我发现在很多情况下,Visual Studio 2010或Expression Blend 4中的设计器会崩溃,例如,如果WPF UserControl包含一个控件,则会根据控件的加载在代码中执行某些操作事件(例如通过VisualStateManager.GoToState(this, "AfterLoaded", true);
之类的调用转换到不同的视觉状态。
解决这些设计器崩溃的典型方法是使用控件的构造函数中的DesignerProperties.GetIsInDesignMode(this)
approach:
public MyControl()
{
// prevent designer crashes
if (DesignerProperties.GetIsInDesignMode(this))
return;
Loaded += MyControlLoaded;
Unloaded += MyControlUnloaded;
IsVisibleChanged += MyControlIsVisibleChanged;
}
此方法针对Visual Studio 2010和Expression Blend 4,使我能够再次显示设计图面。但是,它还会删除设计人员可能为我提供的任何设计时预览(例如上面提到的加载事件的VSM状态更改)。特别是,Blend能够在其设计器中为我提供预览(如果我切换到不同的Blend选项卡,然后切换回原始选项卡,我会看到加载的动画运行)。此外,由于我还没有应用上述方法的一些控件,Visual Studio 2010的设计师将崩溃,而Blend 4的设计师则不会。因此,我想做的是检查仅 Visual Studio 2010的设计师,以便我可以让Blend的设计师通过并提供其预览功能。
这种能力的好处是我可以节省时间,因为不需要经常构建和运行应用程序(看加载动画之类的东西),因为Blend的设计师可以给我预览。
答案 0 :(得分:1)
我发现了一些有用的东西。这个想法是使用DesignerProperties.GetIsInDesignMode(...)
方法结合检查运行代码的进程名称。
对于我的VisualStudio 2010,我看到进程名称是“devenv”:
然后我找到了this post,它解释了System.Diagnostics.Process
是我们获取流程信息所需要的。知道了,我创建了这个辅助方法:
private bool IsVisualStudio2010DesignerRunning()
{
using (var process = System.Diagnostics.Process.GetCurrentProcess())
{
const string visualStudio2010ProcessName = "devenv";
if (process.ProcessName.ToLowerInvariant().Contains(visualStudio2010ProcessName)
&& DesignerProperties.GetIsInDesignMode(this))
{
return true;
}
else
return false;
}
}
它在我写的一个名为SunkenBorder的自定义控件中。此控件具有在第一次机会时转换为某个VisualState的行为,因此该状态是用户看到的初始状态。此代码在OnApplyTemplate()
覆盖中执行。 Expression Blend 4能够在运行时处理和显示它。另一方面,Visual Studio 2010的设计器完全崩溃,因为它无法执行通过调用Storyboard
启动的VisualStateManager.GoToState(...)
。
为了更好地说明这是有效的,我在针对VS 2010设计器的OnApplyTemplate()
代码中将控件的background属性设置为蓝色(参见屏幕截图)。
/// Non-static constructor
public SunkenBorder()
{
// Avoid Visual Studio 2010 designer errors
if (IsVisualStudio2010DesignerRunning())
return;
// Expression Blend 4's designer displays previews of animations
// that these event handlers initiate!
Initialized += new EventHandler(SunkenBorder_Initialized);
Loaded += new RoutedEventHandler(SunkenBorder_Loaded);
Unloaded += new RoutedEventHandler(SunkenBorder_Unloaded);
IsVisibleChanged += new DependencyPropertyChangedEventHandler(SunkenBorder_IsVisibleChanged);
}
// ...
/// Used to set the initial VSM state (its the first opportunity).
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
if (IsVisualStudio2010DesignerRunning())
{
// set a property just to illustrate that this targets only Visual Studio 2010:
this.Background = Brushes.Blue;
// return before doing VisualState change so Visual Studio's designer won't crash
return;
}
// Blend 4 executes this at design-time just fine
VisualStateManager.GoToState(this, "InitialState", false);
// ...
}
以下是Expression Blend 4预览的外观(注意SunkenBorder控件的背景不是蓝色)......
......这就是Visual Studio设计师向我展示的内容。现在它的设计师没有崩溃,而且SunkenBorder控件的背景都是蓝色......
...最后,这是运行时的结果(再次,SunkenBorder控件的背景不是蓝色):
答案 1 :(得分:0)
你可能会更好地制作一个design time view model。这样就无需在控件的构造函数中检查任何类型的设计器。
答案 2 :(得分:0)
(注意:现在不能测试/验证这个,稍后会这样做)
看起来Silverlight
人在进行“In Designer”检查时离开了农场,所以现在有两个属性:
IsInDesignMode
,这似乎对VS2010始终有效
IsInDesignTool
,对于Blend来说似乎是半合规的
还发现了这个: