Có cách nào để kiểm tra xem WPF hiện đang thực thi trong chế độ thiết kế hay không?


147

Có ai biết một số biến trạng thái toàn cầu có sẵn để tôi có thể kiểm tra xem mã hiện đang thực thi trong chế độ thiết kế (ví dụ như trong Blend hoặc Visual Studio) hay không?

Nó sẽ trông giống như thế này:

//pseudo code:
if (Application.Current.ExecutingStatus == ExecutingStatus.DesignMode) 
{
    ...
}

Lý do tôi cần điều này là: khi ứng dụng của tôi được hiển thị ở chế độ thiết kế trong Expression Blend, tôi muốn ViewModel thay vào đó sử dụng "Lớp khách hàng thiết kế" có dữ liệu giả mà nhà thiết kế có thể xem trong chế độ thiết kế.

Tuy nhiên, khi ứng dụng thực sự đang thực thi, tất nhiên tôi muốn ViewModel sử dụng lớp Khách hàng thực trả về dữ liệu thực.

Hiện tại tôi giải quyết vấn đề này bằng cách có nhà thiết kế, trước khi anh ta làm việc với nó, đi vào ViewModel và thay đổi "ApplicationDevelopmentMode.Executing" thành "ApplicationDevelopmentMode.Designing":

public CustomersViewModel()
{
    _currentApplicationDevelopmentMode = ApplicationDevelopmentMode.Designing;
}

public ObservableCollection<Customer> GetAll
{
    get
    {
        try
        {
            if (_currentApplicationDevelopmentMode == ApplicationDevelopmentMode.Developing)
            {
                return Customer.GetAll;
            }
            else
            {
                return CustomerDesign.GetAll;
            }
        }
        catch (Exception ex)
        {
            throw new Exception(ex.Message);
        }
    }
}

Câu trả lời:


226

Tôi tin rằng bạn đang tìm kiếm GetIsInDesignMode , có DependencyObject.

I E.

// 'this' is your UI element
DesignerProperties.GetIsInDesignMode(this);

Chỉnh sửa: Khi sử dụng Silverlight / WP7, bạn nên sử dụng IsInDesignToolGetIsInDesignModeđôi khi có thể trả về false khi ở trong Visual Studio:

DesignerProperties.IsInDesignTool

Chỉnh sửa: Và cuối cùng, vì lợi ích của sự hoàn thiện, tương đương trong các ứng dụng WinRT / Metro / Windows Store là DesignModeEnabled:

Windows.ApplicationModel.DesignMode.DesignModeEnabled

3
Là một lưu ý phụ, IsInDesignMode thực sự là một thuộc tính đính kèm, vì vậy bạn cũng có thể sử dụng nó trong một ràng buộc từ xaml. Có thể không được sử dụng phổ biến nhất mặc dù :)
aL3891

3
Cảm ơn vì đã cập nhật câu trả lời với các "ứng dụng" XAML mới nhất như WinRT và WP.
Bảy

Trong VS2019, công tắc Enable project codephải được bật (hoặc Menu-> Thiết kế-> Chạy Mã dự án).
marbel82

115

Bạn có thể làm một cái gì đó như thế này:

DesignerProperties.GetIsInDesignMode(new DependencyObject());

30
Phương pháp này cũng hoạt động để làm cho nhà thiết kế ViewModels thân thiện (vì bản thân chúng không phải là DependencyObjects).
Pat

1
DependencyObject có một hàm tạo được bảo vệ - xác định internal class MyDependencyObject : DependencyObject {}và sử dụng new MyDependencyObjectthay vìDependencyObject
Rico Suter


nếu thực hiện điều này trong một khung nhìn, bạn có thể muốn trừu tượng hóa nó thành một lớp tĩnh và lưu trữ kết quả dưới dạng boolean tĩnh
Simon_Weaver

24
public static bool InDesignMode()
{
    return !(Application.Current is App);
}

Hoạt động từ bất cứ đâu. Tôi sử dụng nó để ngăn các video dữ liệu phát trong trình thiết kế.


Một biến thể ở trên Application.Current.MainWindow == nullmặc dù tôi thích loại thử nghiệm tốt hơn, trực tiếp hơn. Nó cũng xuất hiện như thể nhà thiết kế được lưu trữ trong Visual Studio thêm tài nguyên, vì vậy đây là một cách khác để làm điều đó (nếu bạn không có quyền truy cập vào Apploại cụ thể trong thư viện lưu trữ mã của bạn) ((bool)Application.Current.Resources["ExpressionUseLayoutRounding"]). Cần kiểm tra nếu tài nguyên không có mặc dù nhưng nó hoạt động trong bối cảnh thiết kế.
John Leidegren

9

Khi Visual Studio tự động tạo một số mã cho tôi, nó đã sử dụng

if (!System.ComponentModel.DesignerProperties.GetIsInDesignMode(this)) 
{
    ...
}

9

Có nhiều cách khác (có thể mới hơn) để chỉ định dữ liệu thời gian thiết kế trong WPF, như được đề cập trong câu trả lời liên quan này .

Về cơ bản, bạn có thể chỉ định dữ liệu thời gian thiết kế bằng cách sử dụng phiên bản thời gian thiết kế của ViewModel :

d:DataContext="{d:DesignInstance Type=v:MySampleData, IsDesignTimeCreatable=True}"

hoặc bằng cách chỉ định dữ liệu mẫu trong tệp XAML :

d:DataContext="{d:DesignData Source=../DesignData/SamplePage.xaml}">

Bạn phải đặt SamplePage.xamlthuộc tính tệp thành:

BuildAction:               DesignData
Copy to Output Directory:  Do not copy
Custom Tool:               [DELETE ANYTHING HERE SO THE FIELD IS EMPTY]

Tôi đặt chúng trong UserControlthẻ của tôi , như thế này:

<UserControl
    ...
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 

    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    ...
    d:DesignWidth="640" d:DesignHeight="480"
    d:DataContext="...">

Vào thời gian chạy, tất cả các thẻ thời gian thiết kế "d:" sẽ biến mất, do đó bạn sẽ chỉ nhận được bối cảnh dữ liệu thời gian chạy của mình, tuy nhiên bạn chọn đặt nó.

Chỉnh sửa Bạn cũng có thể cần những dòng này (Tôi không chắc chắn, nhưng chúng có vẻ phù hợp):

xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
mc:Ignorable="d" 

7

Và nếu bạn sử dụng rộng rãi Caliburn.Micro cho ứng dụng WPF / Silverlight / WP8 / WinRT lớn của mình, bạn có thể sử dụng thuộc tínhExecute.InDesignMode tĩnh của caliburn tiện dụng và phổ biến trong các mô hình chế độ xem của mình (và nó cũng hoạt động tốt trong Visual Studio):

using Caliburn.Micro;

// ...

/// <summary>
/// Default view-model's ctor without parameters.
/// </summary>
public SomeViewModel()
{
    if(Execute.InDesignMode)
    {
        //Add fake data for design-time only here:

        //SomeStringItems = new List<string>
        //{
        //  "Item 1",
        //  "Item 2",
        //  "Item 3"
        //};
    }
}

2

Tôi chỉ thử nghiệm điều này với Visual Studio 2013 và .NET 4.5 nhưng nó thực hiện được mẹo.

public static bool IsDesignerContext()
{
  var maybeExpressionUseLayoutRounding =
    Application.Current.Resources["ExpressionUseLayoutRounding"] as bool?;
  return maybeExpressionUseLayoutRounding ?? false;
}

Mặc dù có thể một số cài đặt trong Visual Studio sẽ thay đổi giá trị này thành false, nếu điều đó xảy ra, chúng ta có thể chỉ kiểm tra xem tên tài nguyên này có tồn tại hay không. Đó là nullkhi tôi chạy mã của mình bên ngoài nhà thiết kế.

Mặt trái của phương pháp này là nó không đòi hỏi kiến ​​thức rõ ràng về Applớp cụ thể và nó có thể được sử dụng trên toàn cầu trong toàn bộ mã của bạn. Cụ thể để điền mô hình xem với dữ liệu giả.


2

Câu trả lời được chấp nhận đã không làm việc cho tôi (VS2019).

Sau khi kiểm tra những gì đang xảy ra, tôi đã nghĩ ra điều này:

    public static bool IsRunningInVisualStudioDesigner
    {
        get
        {
            // Are we looking at this dialog in the Visual Studio Designer or Blend?
            string appname = System.Reflection.Assembly.GetEntryAssembly().FullName;
            return appname.Contains("XDesProc");
        }
    }

Điều này làm việc cho tôi khi tôi cần biết liệu tôi có đang chạy trong thời gian thiết kế từ bên trong viewModel và không thể sử dụng các thư viện Windows. Tôi biết đó là một lượng phản xạ rất nhỏ nhưng tôi không thích ý nghĩ về việc nó đang được sản xuất nên tôi đã bọc mã này trong một mã #if DEBUGkhác trả về sai. Có bất kỳ lý do để không làm điều đó?
Toby Smith

1

Tôi có một ý tưởng cho bạn nếu lớp của bạn không cần một nhà xây dựng trống.

Ý tưởng là tạo ra một hàm tạo rỗng, sau đó đánh dấu nó bằng ObsoleteAttribution. Nhà thiết kế bỏ qua thuộc tính lỗi thời, nhưng trình biên dịch sẽ phát sinh lỗi nếu bạn cố gắng sử dụng nó, do đó không có nguy cơ bị tai nạn khi sử dụng nó.

( tha thứ cho hình ảnh cơ bản của tôi )

Public Class SomeClass

    <Obsolete("Constructor intended for design mode only", True)>
    Public Sub New()
        DesignMode = True
        If DesignMode Then
            Name = "Paula is Brillant"
        End If
    End Sub

    Public Property DesignMode As Boolean
    Public Property Name As String = "FileNotFound"
End Class

Và xaml:

<UserControl x:Class="TestDesignMode"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:vm="clr-namespace:AssemblyWithViewModels;assembly=AssemblyWithViewModels"
             mc:Ignorable="d" 
             >
  <UserControl.Resources>
    <vm:SomeClass x:Key="myDataContext" />
  </UserControl.Resources>
  <StackPanel>
    <TextBlock d:DataContext="{StaticResource myDataContext}" Text="{Binding DesignMode}" Margin="20"/>
    <TextBlock d:DataContext="{StaticResource myDataContext}" Text="{Binding Name}" Margin="20"/>
  </StackPanel>
</UserControl>

kết quả của đoạn mã trên

Điều này sẽ không hoạt động nếu bạn thực sự cần nhà xây dựng trống cho một cái gì đó khác.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.