首页 > 解决方案 > .Add 触发 RoutedEvent="Loaded" 但 .Insert 没有

问题描述

当通过绑定到 ViewModel 的 ObservableCollection 将新项目添加到 ListBox 时,我试图在我的视图中触发动画。装订效果很好。

动画与 ListBox.ItemContainer 样式上的 RoutedEvent "Loaded" 相关联。当我使用 .Add 添加新项目时,动画仅在新项目上正确触发,但 .Add 只能在 ObservableCollection 末尾添加项目。我的 ObservableCollection 已排序,所以这不起作用。我想我有三个选择:

1)添加项目,然后重新排序列表 2)在正确的位置插入项目 3)在 XAML 中对列表进行排序

我无法让选项 1) 工作,因为 ObservableCollection 没有 .Sort() (对列表进行排序)并且 .OrderBy(x => x.TimeStamp) 需要重新创建集合,这使得所有项目触发 Loaded RoutedEvent (即它们都动画,我只希望新项目动画)。我也尝试过使用 .ToList().Sort() 就地排序,但这似乎是一个新的排序和丢弃的列表......

我无法让 2) 正常工作。.Add 工作正常并仅触发新项目的加载动画,但将项目放置在它不属于的列表末尾。我可以使用 .Insert 将项目插入到正确的位置;但是, .Insert 不会触发新插入项目的动画。

我根本无法让 3) 工作,并且在线提供的示例对于应该是单行的东西来说似乎不必要地复杂。

这是我正在使用的动画代码:

<ListBox.ItemContainerStyle>
                            <Style TargetType="{x:Type ListBoxItem}">
                                <Setter Property="LayoutTransform">
                                    <Setter.Value>
                                        <ScaleTransform x:Name="transform" />
                                    </Setter.Value>
                                </Setter>
                                <Style.Triggers>
                                    <EventTrigger RoutedEvent="Loaded">
                                        <EventTrigger.Actions>
                                            <BeginStoryboard>
                                                <Storyboard>
                                                    <DoubleAnimation Storyboard.TargetProperty="LayoutTransform.ScaleY" From="0" Duration="0:0:0.4"/>
                                                </Storyboard>
                                            </BeginStoryboard>
                                        </EventTrigger.Actions>
                                    </EventTrigger>
                                </Style.Triggers>
                            </Style>
                    </ListBox.ItemContainerStyle>

我正在插入这样的项目进行测试(插入):

                var timelineItem = new TimelineItem("Test", DateTime.UtcNow);
                Timeline.Insert(0, timelineItem);
                OnPropertyChanged("Timeline");

我正在添加这样的项目进行测试(添加):

                var timelineItem = new TimelineItem("Test", DateTime.UtcNow);
                Timeline.Add(timelineItem);
                OnPropertyChanged("Timeline");

标签: c#wpf

解决方案


您看到这种差异的原因是在 ListBox 中重复使用模板化控件的方式。正在加载的 ui 控件驱动您当前的动画,并且如果您插入它们已经加载。

不幸的是,datacontextchanged 不是路由事件,因此您需要一个行为或其他东西来使用它来启动动画。

我建议您改用数据触发器。

将布尔“IsLoading”公共属性添加到您的行视图模型中。

当您想要加载动画时,将其设置为 true。

使用基于 IsLoading=true 的数据触发器而不是事件触发器。

在插入(或添加)视图模型后的一两秒内,使用带有 await Task.Delay(2000) 的行视图模型中的异步方法将其设置为 false。

数据触发器方法的好处是,当您最初显示 20 个条目时,您可以选择哪些(如果有的话)动画。


推荐阅读