有没有办法检查 WPF 当前是不是在设计模式下执行?

Posted

技术标签:

【中文标题】有没有办法检查 WPF 当前是不是在设计模式下执行?【英文标题】:Is there a way to check if WPF is currently executing in design mode or not?有没有办法检查 WPF 当前是否在设计模式下执行? 【发布时间】:2010-10-24 11:20:51 【问题描述】:

有谁知道一些可用的全局状态变量,以便我可以检查代码当前是否在设计模式下(例如在 Blend 或 Visual Studio 中)执行?

看起来像这样:

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

    ...

我需要这个的原因是:当我的应用程序在 Expression Blend 中以设计模式显示时,我希望 ViewModel 改用“设计客户类”,其中包含设计人员可以在设计模式下查看的模拟数据.

但是,当应用程序实际执行时,我当然希望 ViewModel 使用返回真实数据的真实 Customer 类。

目前我通过让设计师在他开始工作之前进入 ViewModel 并将“ApplicationDevelopmentMode.Executing”更改为“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);
        
    

【问题讨论】:

【参考方案1】:

我相信您正在寻找 GetIsInDesignMode,它接受一个 DependencyObject。

即。

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

编辑:使用 Silverlight / WP7 时,您应该使用 IsInDesignTool,因为 GetIsInDesignMode 在 Visual Studio 中有时会返回 false:

DesignerProperties.IsInDesignTool

编辑:最后,为了完整起见,WinRT / Metro / Windows Store 应用程序中的等价物是DesignModeEnabled

Windows.ApplicationModel.DesignMode.DesignModeEnabled

【讨论】:

附带说明,IsInDesignMode 实际上是一个附加属性,因此您也可以在 xaml 的绑定中使用它。虽然可能不是最常见的用途:) 感谢您使用最新的 XAML“应用程序”(如 WinRT 和 WP)及时更新答案。 在 VS2019 中开关 Enable project code 必须启用(或菜单->设计->?运行项目代码)。【参考方案2】:

你可以这样做:

DesignerProperties.GetIsInDesignMode(new DependencyObject());

【讨论】:

此方法也适用于使 ViewModel 设计者友好(因为它们本身不是 DependencyObjects)。 DependencyObject 有一个受保护的构造函数 - 定义 internal class MyDependencyObject : DependencyObject 并使用 new MyDependencyObject 而不是 DependencyObject @RicoSuter: DependencyObject's constructor is public. 如果在视图模型中执行此操作,您可能希望将其抽象为静态类并将结果存储为静态布尔值【参考方案3】:
public static bool InDesignMode()

    return !(Application.Current is App);

在任何地方工作。我用它来阻止数据绑定视频在设计器中播放。

【讨论】:

上述Application.Current.MainWindow == null 的变体,虽然我更喜欢类型测试,更直接。看起来好像 Visual Studio 中托管的设计器添加了资源,所以这是另一种方法(如果您无权访问托管代码的库中的特定 App 类型)((bool)Application.Current.Resources["ExpressionUseLayoutRounding"])。需要检查资源是否不存在,但它确实在设计器上下文中工作。 这个答案在任何地方都不起作用。例如,在一个库中,您没有 App 类。 ;) @GregorMohorko 如果您需要在App 的静态构造函数中检查,这是正确的答案。 @MartinBraun 是的,它会起作用的。我正在回复他的Works from anywhere. 声明。 @GregorMohorko 对不起,是的,将您的话误读为“无处不在”。你是对的,你需要访问App,我什至认为从App 本身以外的任何地方访问App 以确保模块化是不好的。【参考方案4】:

还有其他(可能是较新的)方法可以在 WPF 中指定设计时数据,例如 mentioned in this related answer。

基本上,您可以使用design-time instance of your ViewModel 指定设计时数据:

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

或specifying sample data in a XAML file:

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

您必须将SamplePage.xaml 文件属性设置为:

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

我将这些放在我的UserControl 标签中,如下所示:

<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="...">

在运行时,所有“d:”设计时标记都会消失,因此您只会获得运行时数据上下文,但您可以选择设置它。

编辑 您可能还需要这些行(我不确定,但它们似乎相关):

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

【讨论】:

【参考方案5】:

当 Visual Studio 自动为我生成一些代码时,它使用了

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

    ...

【讨论】:

【参考方案6】:

如果您在大型 WPF / Silverlight / WP8 / WinRT 应用程序中广泛使用 Caliburn.Micro,您可以在您的视图模型也是如此(它在 Blend 中的效果与在 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"
        //;
    

【讨论】:

【参考方案7】:

接受的答案对我不起作用(VS2019)。

在检查了发生了什么之后,我想出了这个:

    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");
        
    

【讨论】:

这对我有用,我需要知道我是否在设计时从 viewModel 中运行并且不能使用 Windows 库。我知道这是一个非常少量的反射,但我不喜欢它在生产中运行的想法,所以我将此代码包装在 #if DEBUG else return false 中。有什么理由不这样做吗? 我在 VS2022 和 .NET 6 中尝试过这种技术,但我得到的 appname 是 WpfSurface【参考方案8】:

我只使用 Visual Studio 2013 和 .NET 4.5 对此进行了测试,但它成功了。

public static bool IsDesignerContext()

  var maybeExpressionUseLayoutRounding =
    Application.Current.Resources["ExpressionUseLayoutRounding"] as bool?;
  return maybeExpressionUseLayoutRounding ?? false;

虽然 Visual Studio 中的某些设置可能会将此值更改为 false,但如果发生这种情况,我们可以只检查此资源名称是否存在。当我在设计器之外运​​行我的代码时是null

这种方法的好处是它不需要明确了解特定的App 类,并且可以在整个代码中全局使用。专门用虚拟数据填充视图模型。

【讨论】:

【参考方案9】:

如果你的类不需要空的构造函数,我有一个想法。

想法是创建一个空的构造函数,然后用 ObsoleteAttribute 标记它。设计者忽略了过时的属性,但如果你尝试使用它,编译器会报错,所以没有自己误用的风险。

(pardon my visual basic)

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

还有 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>

如果您真的需要空的构造函数来做其他事情,这将不起作用。

【讨论】:

优秀而简单的解决方案。

以上是关于有没有办法检查 WPF 当前是不是在设计模式下执行?的主要内容,如果未能解决你的问题,请参考以下文章

在 wpf 应用程序中以调试模式检查当前用户凭据

如何确定 WPF DataGrid 是不是处于编辑模式? [复制]

检查是不是有任何文本框为空 wpf

有没有办法设置猫鼬来检查两个值是不是在一个模式中匹配?

如何以编程方式检查应用程序是不是在 TestFlight beta 模式下运行? [复制]

在WPF中,有没有办法在后面的代码中获取故事板动画值的当前值?