2

我发现在许多情况下,如果 WPF UserControl 包含一个控件在代码中基于控件的加载事件(例如转换到不同的 Visual State通过类似的电话VisualStateManager.GoToState(this, "AfterLoaded", true);)。

我解决这些设计器崩溃的典型方法是使用控件构造函数中的DesignerProperties.GetIsInDesignMode(this)方法:

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 的设计师可以给我它的预览,从而节省了时间。

4

3 回答 3

1

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

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

Visual Studio 进程名称

然后我发现这篇文章解释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(...).

为了更好地说明这是有效的,我在OnApplyTemplate()针对 VS 2010 设计器的代码中将控件的背景属性设置为蓝色(参见屏幕截图)。

    /// 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 设计器预览

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

Visual Studio 2010 设计器预览

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

在此处输入图像描述

于 2013-02-08T18:13:15.430 回答
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/

于 2013-01-30T18:45:45.367 回答
0

您最好制作一个设计时视图模型。这样就不必在控件的构造函数中检查任何类型的设计器。

于 2013-01-30T17:56:55.317 回答