2012-08-05 61 views
2

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

<UserControl x:Class="blabla.Controls.Tile" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
    mc:Ignorable="d" 
    FontFamily="{StaticResource PhoneFontFamilyNormal}" 
    FontSize="{StaticResource PhoneFontSizeNormal}" 
    Foreground="{StaticResource PhoneForegroundBrush}"> 

    <UserControl.Resources> 
     <Storyboard x:Name="SwitchSidesAnimation"> 
      <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Projection).(PlaneProjection.RotationX)" Storyboard.TargetName="FrontSide"> 
       <EasingDoubleKeyFrame KeyTime="0" Value="0"/> 
       <EasingDoubleKeyFrame KeyTime="0:0:0.2" Value="90"/> 
       <EasingDoubleKeyFrame KeyTime="0:0:0.4" Value="90"/> 
       <EasingDoubleKeyFrame x:Name="MoveThisForPause1" KeyTime="0:0:6" Value="-90"/> 
       <EasingDoubleKeyFrame x:Name="MoveThisForPause2" KeyTime="0:0:6.2" Value="-90"/> 
       <EasingDoubleKeyFrame x:Name="MoveThisForPause3" KeyTime="0:0:6.4" Value="0"/> 
       <EasingDoubleKeyFrame x:Name="MoveThisForPause4" KeyTime="0:0:12" Value="0"/> 
      </DoubleAnimationUsingKeyFrames> 
      <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Projection).(PlaneProjection.RotationX)" Storyboard.TargetName="BackSide"> 
       <EasingDoubleKeyFrame KeyTime="0" Value="-90"/> 
       <EasingDoubleKeyFrame KeyTime="0:0:0.2" Value="-90"/> 
       <EasingDoubleKeyFrame KeyTime="0:0:0.4" Value="0"/> 
       <EasingDoubleKeyFrame x:Name="MoveThisForPause5" KeyTime="0:0:6" Value="0"/> 
       <EasingDoubleKeyFrame x:Name="MoveThisForPause6" KeyTime="0:0:6.2" Value="90"/> 
       <EasingDoubleKeyFrame x:Name="MoveThisForPause7" KeyTime="0:0:6.4" Value="90"/> 
       <EasingDoubleKeyFrame x:Name="MoveThisForPause8" KeyTime="0:0:12" Value="90"/> 
      </DoubleAnimationUsingKeyFrames> 
      <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="FrontSide"> 
       <DiscreteObjectKeyFrame KeyTime="0:0:0.2"> 
        <DiscreteObjectKeyFrame.Value> 
         <Visibility>Visible</Visibility> 
        </DiscreteObjectKeyFrame.Value> 
       </DiscreteObjectKeyFrame> 
       <DiscreteObjectKeyFrame KeyTime="0:0:0.4"> 
        <DiscreteObjectKeyFrame.Value> 
         <Visibility>Collapsed</Visibility> 
        </DiscreteObjectKeyFrame.Value> 
       </DiscreteObjectKeyFrame> 
       <DiscreteObjectKeyFrame x:Name="MoveThisForPause9" KeyTime="0:0:6"> 
        <DiscreteObjectKeyFrame.Value> 
         <Visibility>Visible</Visibility> 
        </DiscreteObjectKeyFrame.Value> 
       </DiscreteObjectKeyFrame> 
       <DiscreteObjectKeyFrame x:Name="MoveThisForPause10" KeyTime="0:0:6.4"> 
        <DiscreteObjectKeyFrame.Value> 
         <Visibility>Visible</Visibility> 
        </DiscreteObjectKeyFrame.Value> 
       </DiscreteObjectKeyFrame> 
       <DiscreteObjectKeyFrame x:Name="MoveThisForPause11" KeyTime="0:0:12"> 
        <DiscreteObjectKeyFrame.Value> 
         <Visibility>Visible</Visibility> 
        </DiscreteObjectKeyFrame.Value> 
       </DiscreteObjectKeyFrame> 
      </ObjectAnimationUsingKeyFrames> 
      <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.TranslateX)" Storyboard.TargetName="FrontSide"> 
       <EasingDoubleKeyFrame KeyTime="0:0:0.4" Value="0"/> 
       <EasingDoubleKeyFrame x:Name="MoveThisForPause12" KeyTime="0:0:6" Value="0"/> 
       <EasingDoubleKeyFrame x:Name="MoveThisForPause13" KeyTime="0:0:6.2" Value="0"/> 
       <EasingDoubleKeyFrame x:Name="MoveThisForPause14" KeyTime="0:0:6.4" Value="0"/> 
       <EasingDoubleKeyFrame x:Name="MoveThisForPause15" KeyTime="0:0:12" Value="0"/> 
      </DoubleAnimationUsingKeyFrames> 
     </Storyboard> 
    </UserControl.Resources> 

    <Grid x:Name="LayoutRoot"> 
     <Grid.ColumnDefinitions> 
      <ColumnDefinition Width="1*" /> 
     </Grid.ColumnDefinitions> 
     <Grid.RowDefinitions> 
      <RowDefinition Height="1*" /> 
     </Grid.RowDefinitions> 

     <!-- Front side --> 
     <Grid x:Name="FrontSide" Grid.Column="0" Grid.Row="0" 
       Background="{Binding FrontBackground}"> 
      <Image Source="{Binding FrontImage}" /> 
     </Grid> 
     <!-- /Front side --> 

     <!-- Back side --> 
     <Grid x:Name="BackSide" Grid.Column="0" Grid.Row="0" 
       Background="{Binding BackBackground}"> 
      <Grid.Projection> 
       <PlaneProjection RotationX="-90" /> 
      </Grid.Projection> 
      <Image Source="{Binding BackImage}" /> 
     </Grid> 
     <!-- /Back side --> 
    </Grid> 
</UserControl> 

而现在的代码。

namespace blabla.Controls 
{ 
    public partial class Tile : UserControl 
    { 
     /// <summary> 
     /// Defines if the tile has two sides. 
     /// </summary> 
     public bool IsTwoSided 
     { 
      get { return (bool)GetValue(IsTwoSidedProperty); } 
      set 
      { 
       SetValue(IsTwoSidedProperty, value); 

       this.startAnimations(); 
      } 
     } 

     /// <summary> 
     /// Image that will be displayed on front side. 
     /// </summary> 
     public BitmapImage FrontImage 
     { 
      get { return (BitmapImage)GetValue(FrontImageProperty); } 
      set { SetValue(FrontImageProperty, value); } 
     } 

     /// <summary> 
     /// Image that ill be displayed on back side. 
     /// </summary> 
     public BitmapImage BackImage 
     { 
      get { return (BitmapImage)GetValue(BackImageProperty); } 
      set { SetValue(BackImageProperty, value); } 
     } 

     /// <summary> 
     /// Brush that will be used as background for front side. 
     /// </summary> 
     public Brush FrontBackground 
     { 
      get { return (Brush)GetValue(FrontBackgroundProperty); } 
      set { SetValue(FrontBackgroundProperty, value); } 
     } 

     /// <summary> 
     /// Brush that will be used as background for back side. 
     /// </summary> 
     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; 
     } 

     /////////////////////////////////////////////////////////////////////////////////////////////////////// 

     /// <summary> 
     /// Modifies animation frames' KeyTime to adjust time for new timing. 
     /// <param name="pauseTime">Lenght of the pause.</param> 
     /// </summary> 
     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; 
       } 
      } 
     } 

     /// <summary> 
     /// Starts animations. 
     /// </summary> 
     /// <param name="beginTime">Usually delay before first-time animation.</param> 
     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(); 
      } 
     } 
    } 
} 
+0

任何错误消息或其他症状都要经过吗? – 2012-08-05 06:53:17

+0

你可以删除这行,看看会发生什么:'this.LayoutRoot.DataContext = this;'? – 2012-08-05 07:02:39

+0

@HenkHolterman不,Luke Woodward发现了这个问题。 – Andrzej 2012-08-05 18:55:50

回答

4

我已经能够重现此崩溃,承认使用Silverlight的非手机版本,并在Visual Web开发快车,而不是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(使用记事本++作为可视化Web开发Express时崩溃),删除项目的binobj文件夹并重新启动Visual Web Dev Express。当我重新启动VWDX时,它抱怨说找不到Tile类型,但那是因为我删除了binobj文件夹。重建将其整理出来。

我只能猜测问题是什么。在Tile类被静态初始化点,Application.Current可能是nullApplication.Current.Resources可能是null,或Application.Current.Resources["PhoneAccentColor"]可能是null(这将导致投地Color失败,因为Colorstruct)。也许VS设计器不能很好地处理类型静态初始化期间抛出的异常?

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

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

      this.startAnimations(); 
     } 
    } 

它看起来像要被称为startAnimations方法,只要您IsTwoSided依赖属性的变化。你上面编写的代码不会实现。

当Silverlight更改依赖项属性的值时,它不会调用属性设置器来执行此操作。如果您希望在依赖项属性值发生更改时发生,请改用property-changed callback

其次,在Tile.xaml,声明在<UserControl.Resources>Storyboard如下:

<Storyboard x:Name="SwitchSidesAnimation"> 

我会建议使用x:Key代替x:Name,原因有二:

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

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

    事实上,MSDN documentation for the x:Key attribute(也与上文)提到,

    使用键值一个FindName调用不会检索键控资源

    FindName是用来查找的方法如果你看看Tile.g.cs你会看到它在那里使用。)

我推荐总是s在资源字典中使用x:Key,所以您不会相信您可以直接在代码隐藏中访问此Storyboard。

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

this.Resources["SwitchSidesAnimation"] as Storyboard 

事实上,如果你添加以下属性,你不会有改变你的startAnimations方法:

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

好吧,似乎你正确地想出了问题出在哪里。但在使用属性更改回调之后,出现了新问题。回调方法必须是静态的,对吗? (在这种情况下,它是startAnimations())。所以我必须使startAnimations()静态。 – Andrzej 2012-08-05 15:27:50

+0

在startAnimations()中,我使用SwitchSidesAnimation(我已经按照您的建议创建了属性)并访问它,我必须使SwitchSidesAnimation也是静态的。当此属性为静态时,我无法通过“this.Resources [xxx]”访问usercontrol的资源。如果我将它设置为静态,我将无法通过“this.Findname(”MoveThisForPause9“)访问动画帧” – Andrzej 2012-08-05 18:59:59

+0

“Nevermind,我必须投影DependencyObject参数平铺和我有我的控制的实例。 – Andrzej 2012-08-06 11:54:36

0

我(在开发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中开发,这需要VS 2010的SP1)。

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

幸好现在解决了,谢谢!