【问题标题】:Listbox selection produces Cannot Animate Immutable Object error列表框选择产生无法动画不可变对象错误
【发布时间】:2011-01-19 12:08:23
【问题描述】:

我有一个 WPF 4 应用程序。它包含 2 个列表框。

第一个有可用匹配的列表。选择匹配时,选择用作显示匹配详情的详细信息网格的DataContext。此外,还会播放故事板,并显示第二个列表框,显示可用市场。

这一切都很好。

问题是当从第二个列表框中选择市场时,应用程序崩溃并且我得到:

InvalidOperationException 是 未处理

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

我不知道为什么会发生这种情况,因为市场列表框不尝试播放任何动画。它会干扰从匹配列表中的选择吗? 在 MarketsList 中进行选择时,我尝试重置详细数据上下文,但没有奏效。

这是两个 ListBox 的 xaml

       <StackPanel x:Name="Connected" Grid.Column="1" Grid.Row="1" Visibility="Collapsed">
            <ListBox x:Name="ListBoxMatches" HorizontalAlignment="Left" VerticalAlignment="Center" ItemContainerStyle="{DynamicResource ListBoxItemContainerStyle1}" ItemTemplate="{DynamicResource MatchesDataTemplate}" SelectionChanged="ListBoxMatches_SelectionChanged" />
        </StackPanel>

        <Border x:Name="border1" BorderBrush="White" BorderThickness="1" Grid.Row="1" CornerRadius="20" Padding="15" Margin="-400,0,400,0">
            <StackPanel x:Name="Markets">
                <ListBox x:Name="ListBoxCurrentMarkets" SelectionChanged="ListBoxCurrentMarkets_SelectionChanged" />
            </StackPanel>
        </Border>

这是 ListBoxMatches 的 SelectionChanged 事件的代码:

 private void ListBoxMatches_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            if (ListBoxMatches.SelectedIndex != -1)
            {
                var selectedMatch = (Match)ListBoxMatches.SelectedItem;
                if (MatchData.DataContext == null)
                {
                    MatchData.DataContext = selectedMatch;
                    Storyboard PlayMatch = (Storyboard)FindResource("MatchSelected");
                    BeginStoryboard(PlayMatch);
                }
                else if (MatchData.DataContext != selectedMatch)
                {
                    MatchData.DataContext = selectedMatch;
                }
            }
        }

如果您需要更多代码(如故事板 xaml),请告诉我。

如果有人知道为什么以及发生了什么,请帮忙。

谢谢

更新

我按照 Daniel 的建议进行了更改,但我一定是做错了什么,因为它不起作用。 这是我设置项目来源的代码:

 List<Market> TestList = new List<Market>();
                Market market = new Market { ID = 0, MarketName = "CorrectScore" };
                TestList.Add(market);
                market = new Market { ID = 1, MarketName = "Match Odds" };
                TestList.Add(market);                
                ListBoxCurrentMarkets.ItemsSource = TestList;    

这是列表框的 xaml

<ListBox x:Name="ListBoxCurrentMarkets" SelectionChanged="ListBoxCurrentMarkets_SelectionChanged" ItemContainerStyle="{DynamicResource ListBoxItemContainerStyle1}">
                    <ListBox.ItemTemplate>
                        <DataTemplate>
                            <Grid>
                                <TextBlock x:Name="Market" Foreground="Black" TextWrapping="Wrap" Text="{Binding MarketName, Converter={x:Static local:MyCloneConverter.Instance}}" />
                            </Grid>
                        </DataTemplate>
                    </ListBox.ItemTemplate>
                </ListBox>

这是 CloneConverter:

public class MyCloneConverter : IValueConverter
    {
        public static MyCloneConverter Instance = new MyCloneConverter();

        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if (value is Freezable)
            {
                value = (value as Freezable).Clone();
            }

            return value;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotSupportedException();
        }

    }

请看一下,告诉我你的想法?我在 valueconverter 中放了一个断点,它没有被击中。此外,列表框中的项目也会显示,只有在进行选择时才会出现错误。 谢谢

更新

这是动画的 xaml。动画将 2 个负边距边框移动到正边距(即从屏幕外进入屏幕)。有一个包含 MatchDetails 的边框(文本块数据绑定到一个匹配),有问题的是一个包含可用市场 ListBox 的边框。

<Storyboard x:Key="MatchSelected">
            <ThicknessAnimationUsingKeyFrames Storyboard.TargetProperty="(FrameworkElement.Margin)" Storyboard.TargetName="borderMatchData">
                <EasingThicknessKeyFrame KeyTime="0" Value="0,-400,0,400"/>
                <EasingThicknessKeyFrame KeyTime="0:0:1" Value="0"/>
            </ThicknessAnimationUsingKeyFrames>
            <ThicknessAnimationUsingKeyFrames Storyboard.TargetProperty="(FrameworkElement.Margin)" Storyboard.TargetName="borderMarkets">
                <EasingThicknessKeyFrame KeyTime="0" Value="-400,0,400,0"/>
                <EasingThicknessKeyFrame KeyTime="0:0:1" Value="0"/>
            </ThicknessAnimationUsingKeyFrames>
        </Storyboard>

这是从 MatchesListBox 的 selectionchanged 事件播放故事板的代码:

MatchData.DataContext = selectedMatch;
                    Storyboard PlayMatch = (Storyboard)FindResource("MatchSelected");
                    BeginStoryboard(PlayMatch);

这是 BorderMArkets 的 xaml:

<Border x:Name="borderMarkets" BorderBrush="White" BorderThickness="1" Grid.Row="1" CornerRadius="20" Padding="15" Margin="-400,0,400,0">
            <StackPanel x:Name="Markets">
                <ListBox x:Name="ListBoxCurrentMarkets" SelectionChanged="ListBoxCurrentMarkets_SelectionChanged" ItemContainerStyle="{DynamicResource ListBoxItemContainerStyle1}">
                    <ListBox.ItemTemplate>
                        <DataTemplate>
                            <Grid>
                                <TextBlock x:Name="Market" Foreground="Black" TextWrapping="Wrap" Text="{Binding MarketName, Converter={StaticResource CloneConverter}}" />
                            </Grid>
                        </DataTemplate>
                    </ListBox.ItemTemplate>
                </ListBox>
            </StackPanel>
        </Border>

更新

这是导致所有问题的模板(我认为)

<ControlTemplate x:Key="ListBoxItemControlTemplate1" TargetType="{x:Type ListBoxItem}">
        <Border x:Name="Bd" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Padding="{TemplateBinding Padding}" SnapsToDevicePixels="true" Background="#FF807F7F">
            <VisualStateManager.VisualStateGroups>
                <VisualStateGroup x:Name="CommonStates">
                    <VisualState x:Name="Normal"/>
                    <VisualState x:Name="MouseOver">
                        <Storyboard>
                            <ColorAnimationUsingKeyFrames Storyboard.TargetProperty="(Panel.Background).(SolidColorBrush.Color)" Storyboard.TargetName="Bd">
                                <EasingColorKeyFrame KeyTime="0" Value="#FF3D3B3B"/>
                            </ColorAnimationUsingKeyFrames>
                        </Storyboard>
                    </VisualState>
                    <VisualState x:Name="Disabled"/>
                </VisualStateGroup>
                <VisualStateGroup x:Name="SelectionStates">
                    <VisualState x:Name="Unselected"/>
                    <VisualState x:Name="Selected">
                        <Storyboard>
                            <ColorAnimationUsingKeyFrames Storyboard.TargetProperty="(Panel.Background).(SolidColorBrush.Color)" Storyboard.TargetName="Bd">
                                <EasingColorKeyFrame KeyTime="0" Value="#FFA71616"/>
                            </ColorAnimationUsingKeyFrames>
                        </Storyboard>
                    </VisualState>
                    <VisualState x:Name="SelectedUnfocused">
                        <Storyboard>
                            <ColorAnimationUsingKeyFrames Storyboard.TargetProperty="(Panel.Background).(SolidColorBrush.Color)" Storyboard.TargetName="Bd">
                                <EasingColorKeyFrame KeyTime="0" Value="#FFA71616"/>
                            </ColorAnimationUsingKeyFrames>
                        </Storyboard>
                    </VisualState>
                </VisualStateGroup>
                <VisualStateGroup x:Name="FocusStates">
                    <VisualState x:Name="Unfocused"/>
                    <VisualState x:Name="Focused">
                        <Storyboard>
                            <ColorAnimationUsingKeyFrames Storyboard.TargetProperty="(Panel.Background).(SolidColorBrush.Color)" Storyboard.TargetName="Bd">
                                <EasingColorKeyFrame KeyTime="0" Value="#FF18E526"/>
                            </ColorAnimationUsingKeyFrames>
                        </Storyboard>
                    </VisualState>
                </VisualStateGroup>
            </VisualStateManager.VisualStateGroups>
            <ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
        </Border>
        <ControlTemplate.Triggers>
            <Trigger Property="IsSelected" Value="true">
                <Setter Property="Background" TargetName="Bd" Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}"/>
                <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.HighlightTextBrushKey}}"/>
            </Trigger>
            <MultiTrigger>
                <MultiTrigger.Conditions>
                    <Condition Property="IsSelected" Value="true"/>
                    <Condition Property="Selector.IsSelectionActive" Value="false"/>
                </MultiTrigger.Conditions>
                <Setter Property="Background" TargetName="Bd" Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"/>
                <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
            </MultiTrigger>
            <Trigger Property="IsEnabled" Value="false">
                <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
            </Trigger>
        </ControlTemplate.Triggers>
    </ControlTemplate>

【问题讨论】:

    标签: c# wpf xaml .net-4.0


    【解决方案1】:

    http://blogs.msdn.com/b/mikehillberg/archive/2006/09/26/cannotanimateimmutableobjectinstance.aspx

    基本上,如果您为数据绑定属性设置动画,就会发生这种情况。

    【讨论】:

    • 所以是因为它试图同时进行动画和绑定?如果我在动画之后应用 ListBox 项目源,那会起作用吗?
    • 我认为这不会有帮助。您应该使用文章中介绍的解决方案,即指定一个 IValueConverter,它返回任何可冻结对象的克隆。示例中的 MyCloneConverter 类也应该适合您。
    • Daniel 我试过了,但没用。我不确定我做错了什么。我会发布我更新的代码。请看一看。
    • 断点一定要触发。如果将 MyCloneConverter 作为资源添加到 XAML (&lt;src:MyCloneConverter x:Key="cloneConverter"/&gt;) 并引用它 (Converter={StaticResource cloneConverter}) 会发生什么
    • 当我这样做时,它正在达到断点。当它到达“if (value is Freezable)”时,它会跳过它并返回原始值。是否有必要检查价值是否可冻结?值是来自 INPC 类的字符串。
    猜你喜欢
    • 2015-12-04
    • 1970-01-01
    • 2020-07-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-11-15
    • 1970-01-01
    相关资源
    最近更新 更多