【问题标题】:Cannot animate '(0).(1)' on an immutable object instance无法在不可变对象实例上为“(0).(1)”设置动画
【发布时间】:2019-04-15 22:10:57
【问题描述】:

我有一个用户控件,我想在特定时间制作动画。我将其中两个用户控件添加到一个窗口中。我使用该窗口中的按钮来启动动画。其中一个用户控件工作得很好。第二个给我一个不可变对象实例错误的Cannot animate '(0).(1)'。我完全不明白这个!为什么一个工作而不是另一个?我正在阅读需要一个转换器 - 但我根本无法让它工作。我把代码留在这里以防万一我确实需要它。感谢您对此提供的任何帮助。我是 WPF 的新手,所以我可能会在这里做一些愚蠢的事情 - 请原谅我。这是我的用户控件代码:

<UserControl x:Class="colorCompButton"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:Local="clr-namespace:UserControlTests"
         xmlns:custom="clr-namespace:UserControlTests"

         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
         mc:Ignorable="d" Height="179" Width="317">
<UserControl.Resources>
    <BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
    <Storyboard x:Key="sb2" RepeatBehavior="Forever" x:Name="thisone">

        <ColorAnimation Storyboard.TargetName="badge1" 
      Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)" From="Red" To="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserControl}}, Path=BadgeColor}" 
      Duration="0:0:1" />

    </Storyboard>
</UserControl.Resources>

<Grid Margin="0,0,10,10">

    <Rectangle x:Name="rect"   HorizontalAlignment="Left" Height="135"  VerticalAlignment="Top" Width="259" x:FieldModifier="public"  Fill ="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserControl}}, Path=RectColor}"/>
    <Image x:Name="image" Height="87" Margin="10,10,63,0" VerticalAlignment="Top" x:FieldModifier="public" Source ="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserControl}}, Path=ImageSource}"/>


    <TextBlock x:Name="textBlock" Margin="0,102,10,38" Text="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserControl}}, Path=TxtBoxValue}" Background="Transparent" Foreground="White" FontSize="20" Padding="3"/>

    <Grid Margin="222,81,0,0" x:Name="NumberIMG" Height="78" VerticalAlignment="Top" HorizontalAlignment="Left" Width="85" Visibility="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserControl}}, Path=BadgeVisibile}" >
        <Border BorderBrush="Maroon" BorderThickness="1" CornerRadius="120" Background="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserControl}}, Path=BadgeColor}" HorizontalAlignment="Left" Height="76"  VerticalAlignment="Top" Width="76" x:Name="badge1" x:FieldModifier="public"></Border>
        <Border BorderBrush="black" Margin="2,2,0,0" BorderThickness="3" Opacity=".5" CornerRadius="120"  HorizontalAlignment="Left" Height="74"  VerticalAlignment="Top" Width="74"></Border>
        <Border BorderBrush="White" BorderThickness="3" CornerRadius="120"  HorizontalAlignment="Left" Height="78" VerticalAlignment="Top" Width="78">
            <Label x:Name="resCount" Content="46" FontSize="25"  Foreground="White"  HorizontalContentAlignment="center" VerticalContentAlignment="center" Margin="0,0,-3,-3"/>
        </Border>
    </Grid>

</Grid>

以及该控件背后的代码:

Imports System.Windows.Media.Animation

Public Class colorCompButton
Public Sub New()

    ' This call is required by the designer.
    InitializeComponent()

    ' Add any initialization after the InitializeComponent() call.

End Sub
'Public Shared Sub SetImage(obj As DependencyObject, value As ImageSource)
'    obj.SetValue(ImageProperty, value)
'End Sub
'Public Shared Function GetImage(obj As DependencyObject) As ImageSource
'    Return DirectCast(obj.GetValue(ImageProperty), ImageSource)
'End Function


Shared Sub New()
    'register attached dependency property

    Dim metadata = New FrameworkPropertyMetadata(DirectCast(Nothing, ImageSource))
    'ImageProperty = DependencyProperty.RegisterAttached("Image", GetType(ImageSource), GetType(colorCompButton), metadata)
End Sub


Public Shared ReadOnly BadgeVisibileProperty As DependencyProperty = DependencyProperty.Register("BadgeVisibile", GetType(Visibility), GetType(colorCompButton), New PropertyMetadata(Visibility.Visible))

Public Property BadgeVisibile() As Visibility
    Get
        Return DirectCast(GetValue(BadgeVisibileProperty), Visibility)
    End Get
    Set(value As Visibility)
        SetValue(BadgeVisibileProperty, value)
    End Set
End Property

Public Shared ReadOnly BadgeColorProperty As DependencyProperty = DependencyProperty.Register("BadgeColor", GetType(Brush), GetType(colorCompButton), New PropertyMetadata(New SolidColorBrush(Colors.DarkGray)))
Public Property BadgeColor() As SolidColorBrush
    Get
        Return DirectCast(GetValue(BadgeColorProperty), SolidColorBrush)
    End Get
    Set(value As SolidColorBrush)
        SetValue(BadgeColorProperty, value)
    End Set
End Property

Public Shared ReadOnly buttonColorProperty As DependencyProperty = DependencyProperty.Register("buttonColor", GetType(Brush), GetType(colorCompButton), New PropertyMetadata(New SolidColorBrush(Colors.DarkGray)))
Public Property buttonColor() As SolidColorBrush
    Get
        Return DirectCast(GetValue(buttonColorProperty), SolidColorBrush)
    End Get
    Set(value As SolidColorBrush)
        SetValue(buttonColorProperty, value)
    End Set
End Property


Public Shared ReadOnly ImageSourceProperty As DependencyProperty = DependencyProperty.Register("ImageSource", GetType(BitmapSource), GetType(colorCompButton))
Public Property ImageSource() As ImageSource
    Get
        Return DirectCast(GetValue(ImageSourceProperty), ImageSource)
    End Get
    Set(value As ImageSource)
        SetValue(ImageSourceProperty, value)
    End Set
End Property


Public Shared ReadOnly RectColorProperty As DependencyProperty = DependencyProperty.Register("RectColor", GetType(Brush), GetType(colorCompButton), New PropertyMetadata(New SolidColorBrush(Colors.DarkGray)))
Public Property RectColor() As SolidColorBrush
    Get
        Return DirectCast(GetValue(RectColorProperty), SolidColorBrush)
    End Get
    Set(value As SolidColorBrush)
        SetValue(RectColorProperty, value)
    End Set
End Property

Public Shared TxtBoxValueProperty As DependencyProperty = DependencyProperty.Register("txtBoxValue", GetType([String]), GetType(colorCompButton))
Public Property TxtBoxValue() As [String]
    Get
        Return DirectCast(GetValue(TxtBoxValueProperty), [String])
    End Get
    Set(value As [String])
        SetValue(TxtBoxValueProperty, value)
    End Set
End Property
Public Sub StartLeafUp()
    Dim sb As Storyboard = TryCast(Me.Resources("sb2"), Storyboard)
    sb.Begin()
End Sub

Public Sub StartLeafDown()
    Dim sb As Storyboard = TryCast(Me.Resources("sb2"), Storyboard)
    sb.Stop()
End Sub
End Class
Friend Class MyCloneConverter
Implements IValueConverter

Public Function Convert(value As Object, targetType As Type, parameter As Object, culture As Globalization.CultureInfo) As Object Implements IValueConverter.Convert
    If TypeOf value Is Freezable Then
        value = TryCast(value, Freezable).Clone()
    End If

    Return value
End Function

Public Function ConvertBack(value As Object, targetType As Type, parameter As Object, culture As Globalization.CultureInfo) As Object Implements IValueConverter.ConvertBack
    Throw New NotSupportedException()
End Function
End Class

主窗口和后面的代码:

<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:UserControlTests" x:Class="MainWindow"
Title="MainWindow" Height="437" Width="1057">

<Grid>

    <local:colorCompButton x:Name="color" Margin="201,62,0,0"  VerticalAlignment="Top" HorizontalAlignment="Left" BadgeColor="#FF833E1D" buttonColor="Sienna" RectColor="Sienna" ImageSource="pack://siteoforigin:,,,/images/deviation.png" TxtBoxValue="I WORK"/>
    <Button x:Name="button" Content="WORKS FINE" HorizontalAlignment="Left" Margin="336,262,0,0" VerticalAlignment="Top" Width="160" Height="53"/>

    <Button x:Name="button1" Content="DOES NOT WORK!!" HorizontalAlignment="Left" Margin="534,262,0,0" VerticalAlignment="Top" Width="144" Height="53"/>
    <local:colorCompButton HorizontalAlignment="Left" Margin="534,62,0,0" VerticalAlignment="Top" BadgeColor="Indigo" RectColor="IndianRed" ImageSource="pack://siteoforigin:,,,/images/deviation.png" TxtBoxValue="I WON'T WORK" x:Name="res"/>
    <Label x:Name="label" Content="EXACT SAME CONTROLS.  WHY WILL THIS NOT WORK??" HorizontalAlignment="Left" Margin="375,365,0,0" VerticalAlignment="Top"/>

</Grid>

Imports System.Windows.Media.Animation

Class MainWindow

Private Sub button_Click(sender As Object, e As RoutedEventArgs) Handles button.Click
    color.StartLeafUp()


End Sub

Private Sub button1_Click(sender As Object, e As RoutedEventArgs) Handles button1.Click
    res.StartLeafUp()

End Sub
End Class

【问题讨论】:

    标签: wpf vb.net xaml


    【解决方案1】:

    这可能不是最好的答案,但我自己解决了这个问题,方法是添加另一个边框,将其背景设置为透明并为其设置动画而不是第一个边框。这似乎更像是一种 hack 而不是解决方案,但它确实有效。我仍然愿意听到真正的解决方案 - 如果有人有的话。

    【讨论】:

      【解决方案2】:

      我在尝试为 TextBlock Foreground 属性设置动画时遇到了同样的错误/问题。

      一种解决方法是创建一个颜色类型 DependencyProperty 并将其设置为颜色动画的目标。然后,例如,将 TextBlock Foreground 属性绑定到宿主 UserControl(或 Window)的 DependencyProperty,并使用转换器从 Color 创建 Brush。

      这是我命名为 SpectrumTextBlock 的闪烁 TextBlock 的示例,它在控件加载时启动动画:

      XAML:

      <UserControl x:Class="Common.SpectrumTextBlock"
               xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
               xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
               xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
               xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
               xmlns:local="clr-namespace:Common"
               mc:Ignorable="d"
               x:Name="spectrumTextBlock">
      
      <UserControl.Resources>
      
          <local:ColorToBrushConverter x:Key="colorToBrushConverter"/>
      
          <Storyboard x:Key="spectrumStoryboard" RepeatBehavior="Forever">
              <ColorAnimationUsingKeyFrames Storyboard.TargetProperty="(EffectColor)" Storyboard.TargetName="spectrumTextBlock">
                  <EasingColorKeyFrame KeyTime="0" Value="Black"/>
                  <EasingColorKeyFrame KeyTime="0:0:0.1" Value="Red"/>
                  <EasingColorKeyFrame KeyTime="0:0:0.2" Value="Orange"/>
                  <EasingColorKeyFrame KeyTime="0:0:0.3" Value="Yellow"/>
                  <EasingColorKeyFrame KeyTime="0:0:0.4" Value="Green"/>
                  <EasingColorKeyFrame KeyTime="0:0:0.5" Value="Cyan"/>
                  <EasingColorKeyFrame KeyTime="0:0:0.6" Value="Blue"/>
                  <EasingColorKeyFrame KeyTime="0:0:0.7" Value="Violet"/>
              </ColorAnimationUsingKeyFrames>
          </Storyboard>
      
      </UserControl.Resources>
      
      <TextBlock Text="TEST TEXT" Foreground="{Binding ElementName=spectrumTextBlock, Path=EffectColor, Converter={StaticResource colorToBrushConverter}}"/>
      

      以及包含转换器的该控件的 CS 文件:

      using System;
      using System.Globalization;
      using System.Windows;
      using System.Windows.Controls;
      using System.Windows.Data;
      using System.Windows.Media;
      using System.Windows.Media.Animation;
      
      namespace Common
      {
      public partial class SpectrumTextBlock : UserControl
      {
          private Storyboard _effestStoryboard;
      
          public Color EffectColor
          {
              get { return (Color)GetValue(EffectColorProperty); }
              set { SetValue(EffectColorProperty, value); }
          }
      
          public static readonly DependencyProperty EffectColorProperty =
              DependencyProperty.Register("EffectColor", typeof(Color), typeof(SpectrumTextBlock), new PropertyMetadata(SystemColors.ControlTextColor));
      
          public SpectrumTextBlock()
          {
              InitializeComponent();
              this.Loaded += SpectrumTextBlock_Loaded;
          }
      
          private void SpectrumTextBlock_Loaded(object sender, RoutedEventArgs e)
          {
              _effestStoryboard = (Storyboard)FindResource("spectrumStoryboard");
              _effestStoryboard.Begin();
          }
      }
      
      internal class ColorToBrushConverter : IValueConverter
      {
          public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
          {
              return new SolidColorBrush((Color)value);
          }
      
          public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
          {
              throw new NotImplementedException();
          }
      }
      

      }

      另一种解决方法是使用 0px 大小(不可见)的 Rectangle 并对 Fill 属性进行动画处理,然后将 TextBlock Foreground 属性绑定到 Rectangle 的 Fill 属性。但是第一个 DependencyProperty 解决方法看起来不那么“hacky”。​​

      【讨论】:

        【解决方案3】:

        我这样做的原因是:

        Background="{Binding ElementName=ToggleButton, Path=Background}"
        

        而不是这样:

        Background="{TemplateBinding Background}"
        

        在我在控件模板中制作动画的控件上。

        看来你也犯了同样的错误:-)

        【讨论】:

          【解决方案4】:

          任何遇到问题的人:

          无法在不可变对象实例上为“(0).(1)”设置动画

          添加[VisualState x:Name="Normal"] 解决了这个问题。

          下面的代码是一个例子:

          XAML:

          <Style TargetType="RadioButton">
              <Setter Property="Template">
                  <Setter.Value>
                      <ControlTemplate TargetType="RadioButton">
                          <Border x:Name="borderIn" 
                                  CornerRadius="0">
                              <Label>
                                  <ContentPresenter/>
                              </Label>
                              <VisualStateManager.VisualStateGroups>
                                  <VisualStateGroup x:Name="CommonStates">
                                      <VisualState x:Name="Normal">
                                          <Storyboard>
                                              <ColorAnimation Storyboard.TargetName="borderIn" 
                                                              Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)"
                                                              FillBehavior="HoldEnd" Duration="0"/>
                                          </Storyboard>
                                      </VisualState>
                                      <VisualState x:Name="MouseOver">
                                          <Storyboard>
                                              <ColorAnimation To="LightBlue" Storyboard.TargetName="borderIn" 
                                                              Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)"
                                                              FillBehavior="HoldEnd" Duration="0"/>
                                          </Storyboard>
                                      </VisualState>
                                  </VisualStateGroup>
                                  <VisualStateGroup x:Name="CheckStates">
                                      <VisualState x:Name="Unchecked">
                                          <Storyboard>
                                              <ColorAnimation Storyboard.TargetName="borderIn" 
                                                              Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)"
                                                              FillBehavior="HoldEnd" Duration="0"/>
                                          </Storyboard>
                                      </VisualState>
                                      <VisualState x:Name="Checked">
                                          <Storyboard>
                                              <ColorAnimation Storyboard.TargetName="borderIn" 
                                                              Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)"
                                                              FillBehavior="HoldEnd" Duration="0"/>
                                          </Storyboard>
                                      </VisualState>
                                  </VisualStateGroup>
                              </VisualStateManager.VisualStateGroups>
                          </Border>
                          <ControlTemplate.Triggers>
                              <Trigger Property="IsChecked" Value="true">
                                  <Setter Property="Background" TargetName="borderIn" Value="LightCyan" />
                              </Trigger>
                              <Trigger Property="IsChecked" Value="false">
                                  <Setter TargetName="borderIn" Property="Background" Value="Transparent"/>
                              </Trigger>
                          </ControlTemplate.Triggers>
                      </ControlTemplate>
                  </Setter.Value>
              </Setter>
          </Style>
          

          希望这个解决方案能帮助那些面临同样问题的人

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2021-10-27
            • 2010-12-04
            相关资源
            最近更新 更多