有没有办法检查 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 DataGrid 是不是处于编辑模式? [复制]