为什么我的用户控件崩溃了Visual Studio?

我花了一整天时间试图弄清楚为什么这个用户控件崩溃VS2010(Windows Phone 7.1开发)。 应用程序运行此控件没有问题,但是当我在MainPage.xaml中进入设计模式时 – VS崩溃。

                        Visible     Collapsed     Visible     Visible     Visible                                   

而现在的代码。

 namespace blabla.Controls { public partial class Tile : UserControl { ///  /// Defines if the tile has two sides. ///  public bool IsTwoSided { get { return (bool)GetValue(IsTwoSidedProperty); } set { SetValue(IsTwoSidedProperty, value); this.startAnimations(); } } ///  /// Image that will be displayed on front side. ///  public BitmapImage FrontImage { get { return (BitmapImage)GetValue(FrontImageProperty); } set { SetValue(FrontImageProperty, value); } } ///  /// Image that ill be displayed on back side. ///  public BitmapImage BackImage { get { return (BitmapImage)GetValue(BackImageProperty); } set { SetValue(BackImageProperty, value); } } ///  /// Brush that will be used as background for front side. ///  public Brush FrontBackground { get { return (Brush)GetValue(FrontBackgroundProperty); } set { SetValue(FrontBackgroundProperty, value); } } ///  /// Brush that will be used as background for back side. ///  public Brush BackBackground { get { return (Brush)GetValue(BackBackgroundProperty); } set { SetValue(BackBackgroundProperty, value); } } /////////////////////////////////////////////////////////////////////////////////////////////////////// public static readonly DependencyProperty IsTwoSidedProperty = DependencyProperty.Register("IsTwoSided", typeof(bool), typeof(Tile), new PropertyMetadata(false)); public static readonly DependencyProperty FrontImageProperty = DependencyProperty.Register("FrontImage", typeof(BitmapImage), typeof(Tile), new PropertyMetadata(null)); public static readonly DependencyProperty BackImageProperty = DependencyProperty.Register("BackImage", typeof(BitmapImage), typeof(Tile), new PropertyMetadata(null)); public static readonly DependencyProperty FrontBackgroundProperty = DependencyProperty.Register("FrontBackground", typeof(Brush), typeof(Tile), new PropertyMetadata(new SolidColorBrush((Color)Application.Current.Resources["PhoneAccentColor"]))); public static readonly DependencyProperty BackBackgroundProperty = DependencyProperty.Register("BackBackground", typeof(Brush), typeof(Tile), new PropertyMetadata(new SolidColorBrush((Color)Application.Current.Resources["PhoneAccentColor"]))); /////////////////////////////////////////////////////////////////////////////////////////////////////// public Tile() { InitializeComponent(); this.LayoutRoot.DataContext = this; } /////////////////////////////////////////////////////////////////////////////////////////////////////// ///  /// Modifies animation frames' KeyTime to adjust time for new timing. /// Lenght of the pause. ///  private void setPauses(TimeSpan pauseTime) { // Sets pauses. EasingDoubleKeyFrame frameToModify; for(int i = 0; true; i++) { if(this.FindName("MoveThisForPause" + i) != null) { frameToModify = (EasingDoubleKeyFrame)this.FindName("MoveThisForPause" + i); frameToModify.KeyTime = KeyTime.FromTimeSpan(frameToModify.KeyTime.TimeSpan - TimeSpan.FromSeconds(5) + pauseTime); } else { break; } } } ///  /// Starts animations. ///  /// Usually delay before first-time animation. private void startAnimations() { // We start animations only if the tile is two sided. if(this.IsTwoSided) { // Stopping previous animation. this.SwitchSidesAnimation.Stop(); // Sets correct pauses. this.setPauses(TimeSpan.FromSeconds(new Random().Next(5, 10))); // Starts animation. this.SwitchSidesAnimation.BeginTime = TimeSpan.FromSeconds(new Random().Next(2, 15)); this.SwitchSidesAnimation.RepeatBehavior = RepeatBehavior.Forever; this.SwitchSidesAnimation.Begin(); } else { this.SwitchSidesAnimation.Stop(); } } } } 

我已经能够重现这次崩溃,无可否认地使用Silverlight的非手机版本,以及Visual Web Dev Express而不是完整版本的VS.

问题最终归结为这两个依赖项属性声明中指定的默认值:

  public static readonly DependencyProperty FrontBackgroundProperty = DependencyProperty.Register("FrontBackground", typeof(Brush), typeof(Tile), new PropertyMetadata(new SolidColorBrush((Color)Application.Current.Resources["PhoneAccentColor"]))); public static readonly DependencyProperty BackBackgroundProperty = DependencyProperty.Register("BackBackground", typeof(Brush), typeof(Tile), new PropertyMetadata(new SolidColorBrush((Color)Application.Current.Resources["PhoneAccentColor"]))); 

在我用null替换默认值(使用Notepad ++作为Visual Web Dev Express崩溃)后,崩溃消失了,删除了项目的binobj文件夹并重新启动了Visual Web Dev Express。 当我重新启动VWDX时,它抱怨它无法找到Tile类型,但那是因为我删除了binobj文件夹。 重建将其整理出来。

我只能猜出问题到底是什么。 在静态初始化Tile类时, Application.Current可能为nullApplication.Current.Resources可能为null ,或者Application.Current.Resources["PhoneAccentColor"]可能为null (这会导致Application.Current.Resources["PhoneAccentColor"]Color失败,因为Color是一个struct )。 也许VS设计器不能处理在类型的静态初始化期间抛出的非常好的exception?

顺便说一下,我还想指出另外几个潜在的问题。 首先,这是您的IsTwoSided属性:

  ///  /// Defines if the tile has two sides. ///  public bool IsTwoSided { get { return (bool)GetValue(IsTwoSidedProperty); } set { SetValue(IsTwoSidedProperty, value); this.startAnimations(); } } 

看起来您希望在IsTwoSided依赖项属性更改时调用startAnimations方法。 你上面写的代码不会达到这个目的。

当Silverlight更改依赖项属性的值时,它不会调用属性setter来执行此操作。 如果您希望在依赖项属性的值更改时发生事情,请改为使用属性更改的回调 。

其次,在Tile.xaml ,您在声明Storyboard ,如下所示:

   

我建议使用x:Key而不是x:Name ,原因有两个:

  • 资源字典中的所有项目(隐式样式除外)必须具有x:Keyx:Name才能标识它们。 VS支持使用x:Name代替x:Key ,但仅作为传统支持机制存在。

  • 使用x:Name用户控件XAML中的元素中的x:Name会导致VS在Tile类的自动生成部分的InitializeComponent()中创建具有该名称的字段(在obj \ Debug中的某个地方的Tile.g.cs )。 但是,仅仅因为您可以在元素上粘贴x:Name并不一定意味着您将能够访问生成的字段中的相应对象。 因为SwitchSidesAnimation中没有名为SwitchSidesAnimation UIElement(故事板不是UIElements),所以SwitchSidesAnimation字段将始终为null

    实际上, x:Key属性的MSDN文档 (也与上面链接)提到了这一点

    使用键值的FindName调用将不会检索键控资源

    FindName是用于按名称查找控件的方法。如果你查看Tile.g.cs你会看到它在那里使用。)

我建议在资源字典中始终使用x:Key ,这样您就不会相信您可以直接在代码隐藏中访问此Storyboard。

要在代码隐藏中访问故事板,请使用

  this.Resources["SwitchSidesAnimation"] as Storyboard 

实际上,如果添加以下属性,则不必更改startAnimations方法:

  private Storyboard SwitchSidesAnimation { get { return this.Resources["SwitchSidesAnimation"] as Storyboard; } } 

我有类似的问题(在开发Silverlight 5时),这花了将近3天的时间来挣扎,并且肯定会更多,但幸运的是我在这里找到了解决方案(由Luke Woodward提供)。

就我而言,我正在使用:

  public static readonly DependencyProperty MyStyleProperty = DependencyProperty.Register( "MyStyle", typeof(Style), typeof(MainButton), new PropertyMetadata( // using this construct as a default value // makes VS 2010 SP1 to crush! Application.Current.Resources["SomeStyle"] as Style, OnPropertyChanged ) ); 

因此,这两个问题的共同点是使用一些资源值作为DependencyProperty的默认值。

但更悲惨的是,这个问题发生在我为VS 2010应用SP1之后(因为我想在Silverlight 5中开发,需要SP1 for VS 2010)。

这给我带来了头痛和大量的搜索时间。

幸运的是现在它已经解决了,谢谢!