2012-08-05 62 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)。

這給我帶來了頭痛和大量的時間來搜索。

幸好現在解決了,謝謝!