如何在WPF中仅检查Visual Studio 2010设计器(以便Blend的设计器不是目标)?

时间:2013-01-30 17:47:27

标签: c# wpf visual-studio-2010 visual-studio expression-blend

我发现在很多情况下,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的设计师可以给我预览。

3 个答案:

答案 0 :(得分:1)

我发现了一些有用的东西。这个想法是使用DesignerProperties.GetIsInDesignMode(...)方法结合检查运行代码的进程名称

对于我的VisualStudio 2010,我看到进程名称是“devenv”:

Visual Studio Process name

然后我找到了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控件的背景不是蓝色)......

Blend 4 designer preview

......这就是Visual Studio设计师向我展示的内容。现在它的设计师没有崩溃,而且SunkenBorder控件的背景都是蓝色......

Visual Studio 2010 designer preview

...最后,这是运行时的结果(再次,SunkenBorder控件的背景不是蓝色):

enter image description here

答案 1 :(得分:0)

你可能会更好地制作一个design time view model。这样就无需在控件的构造函数中检查任何类型的设计器。

答案 2 :(得分:0)

(注意:现在不能测试/验证这个,稍后会这样做)

看起来Silverlight人在进行“In Designer”检查时离开了农场,所以现在有两个属性:

  • IsInDesignMode,这似乎对VS2010始终有效

  • IsInDesignTool,对于Blend来说似乎是半合规的

还发现了这个:

http://www.arrangeactassert.com/how-to-use-the-designerproperties-isindesigntool-property-to-populate-controls-with-design-time-data-in-silverlight-using-expression-blend/