如果集合发生更改,Listview中的窗体动画将停止工作



我很难弄清楚我的动画是怎么回事。

Viewmodel由一个ObservableCollection组成,每个项都包含一个子ObservableCollection

Parents集合绑定到BindableLayout。该布局的ItemTemplate包含用于显示子元素的Listview

<StackLayout BindableLayout.ItemsSource ="{Binding Parents}">
<BindableLayout.ItemTemplate>
<DataTemplate x:DataType="models:ParentRows">
<StackLayout>      
<Grid BackgroundColor="White" >
<!-- Some bindable content there -->
</Grid>

<ListView ItemsSource="{Binding Childs}" CachingStrategy="RecycleElementAndDataTemplate" RowHeight="50">
<ListView.ItemTemplate>
<DataTemplate x:DataType="models:ChildRows">
<ViewCell>
<StackLayout BackgroundColor="White">
<controls:AnimatedGrid Refresh="{Binding Animation}"
<!-- Some bindable content there -->
</controls:AnimatedGrid>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</DataTemplate>
</BindableLayout.ItemTemplate>
</StackLayout>

我在子列表视图上使用了一个动画网格,这个控件是从网格中嵌入的。它有一个额外的BindableProperty nammed Refresh和一个动画代码,每当Refresh属性更改时都会调用该代码

private async void AnimateItem()
{
await Device.InvokeOnMainThreadAsync(() =>
{
this.RotateTo(360,500);
});
}

在我开始过滤列表之前,一切都很好过滤列表后,后续调用AnimateItem将无效。更确切地说,若父项从列表中删除,然后再次添加,则该父项的子项将永远不会再设置动画。筛选列表包括移除/插入可观察集合的父项(myCollection.Remove(item(、myCollection.Interpt(index,item(,使用框架中的collection方法(

这似乎不是一个可观察到的集合绑定问题,因为父集合和子集合中的值仍然可以完美地更新。改变CachingStrategy对这个问题也没有影响。

我发现,如果我用CollectionView替换ListView控件,问题就会消失。然而,我真的想找到一个解决方案,让我保留listview控件,因为切换到CollectionView会带来许多其他不希望的效果。

编辑2022年2月22日:我制作了一个样本项目,在github上重现这个问题。

  • Basicaly,你可以点击"随机旋转";多次制作随机的儿童旋转
  • 一旦你点击";移除并添加2个亲本";,你可以看到移除/重新插入的项目不再旋转

编辑15/03/2022:我仍然不知道出了什么问题。然而,出于测试目的,我在控件构造函数中添加了一个task.delay,后面跟着一个动画调用,这个调用用于过滤项。这超出了我的理解。

解决方案

AnimatedGrid类中,添加isAttached标志,并将以下行添加到OnPropertyChanged覆盖中:

bool isAttached = false;
protected override void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
base.OnPropertyChanged(propertyName);
if (propertyName == "Renderer")
{
isAttached = !isAttached;
if (!isAttached) this.RemoveBinding(RefreshProperty);
}
if (propertyName == nameof(Refresh))
{
...

原因

免责声明:我花了很长时间才弄清楚这里发生了什么,尽管我能够解决这个问题,但我不会声称我完全完全理解它。我相信这是Xamarin中的一个错误,在你的情况下,我会在Github中提交一个问题(尽管MAUI可能会纠正这个问题…(

删除ChildItem(do Filter(后,旧的ChildItem AnimatedGridRefresh属性仍绑定到ChildItemAnimationInt属性。

当再次添加ChildItem(删除过滤器(时,将创建一个新视图。

现在问题很明显了:当ChildItemAnimationInt属性发生更改时(点击ROTATE RANDOM按钮(,旧的ChildItem AnimatedGridRefresh会得到通知,然后旋转旧的视图,但新的视图保持不变(不旋转(。


一旦理解了这个问题,我们就需要弄清楚当视图被移除时如何删除旧视图的绑定:好吧,为了做到这一点,我使用了这样一个事实,即VisualElementRenderer属性在元素被附加时被设置/修改,在元素被分离时再次被设置/更改:第一次调用它时,我将isAttached标志设置为true。第二次调用它时,我将标志设置为false,并删除绑定。通过删除旧视图的绑定,可以正确绑定新视图。

最新更新