StackPanel 上的 FluidMoveBehavior 在动画之前闪烁

FluidMoveBehavior On a StackPanel Flickers Before Animating

我有一个 ItemsControl,上面附有 FluidMoveBehavior,如下所示:

<ScrollViewer VerticalScrollBarVisibility="Auto">
    <ItemsControl ItemsSource="{Binding RequirementsSource}" ItemTemplateSelector="{StaticResource RequirementTemplateSelector}">
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <StackPanel IsItemsHost="True">
                    <i:Interaction.Behaviors>
                        <ic:FluidMoveBehavior AppliesTo="Children" Duration="0:0:00.5" Tag="DataContext">
                            <ic:FluidMoveBehavior.EaseX>
                                <BackEase EasingMode="EaseInOut" Amplitude="0.5"/>
                            </ic:FluidMoveBehavior.EaseX>
                            <ic:FluidMoveBehavior.EaseY>
                                <BackEase EasingMode="EaseInOut" Amplitude="0.5"/>
                            </ic:FluidMoveBehavior.EaseY>
                            </ic:FluidMoveBehavior>
                    </i:Interaction.Behaviors>
                </StackPanel>
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
    </ItemsControl>
</ScrollViewer>

当项目改变它们的排序顺序时,它们会进行动画处理,但首先项目排序就像没有 FluidMoveBehavior 附加的一样,然后再排序回来。整个事情发生得非常快,以至于在动画开始之前看起来像是闪烁。

ItemsControl ItemsSource 如下所示:

RequirementsSource = new ListCollectionView(Requirements);
ICollectionViewLiveShaping live = (ICollectionViewLiveShaping)RequirementsSource;
live.IsLiveSorting = True;
live.IsLiveFiltering = True;
live.LiveSortingProperties.Add("Rank");
live.LiveFilteringProperties.Add("Owner");
RequirementsSource.SortDescriptions.Add(
    new SortDescription("Rank", ListSortDirection.Ascending)
);
RequirementsSource.Filter = _filterPred;

排序由以下方法触发:

private void SwapRanks(SwapArgs args)
{
    IPropertyRequirement first = args.Warning.Requirements
        .First(r => r.Rank == args.RankToSwap);
    IPropertyRequirement second = args.Warning.Requirements
        .First(r => r.Rank == args.SwapWith);

    int temp = first.Rank;
    first.Rank = second.Rank;
    second.Rank = temp;

    RequirementsSource.Refresh();
}

有谁知道造成这种情况的原因 "flicker" 以及我可以做些什么来阻止它?

从您的代码中删除 RequirementsSource.Refresh(); 行。

由于您使用的是生活排序,因此当 Requirement.Rank 发生变化(触发 PropertyChanged 事件)时动画开始。但是当您调用刷新时,它会使用 Reset 参数引发 CollectionChanged 并强制刷新列表框。

编辑:

public class MainWindowViewModel 
{
    ObservableCollection<Requirement> requirements;
    public MainWindowViewModel()
    {
        requirements = new ObservableCollection<Requirement>(Enumerable
            .Range(0, 10)
            .Select(i => new Requirement {Rank = 10 - i, Name = "Item " + i}));

        RequirementsSource = new ListCollectionView(requirements);
        var live = (ICollectionViewLiveShaping)RequirementsSource;
        live.IsLiveSorting = true;
        live.IsLiveFiltering = true;
        live.LiveSortingProperties.Add("Rank");
        RequirementsSource.SortDescriptions.Add(
            new SortDescription("Rank", ListSortDirection.Ascending)
        );
        ReorderCommand = new DelegateCommand(Reorder);
    }

    public ListCollectionView RequirementsSource { get; set; }
    public DelegateCommand ReorderCommand { get; private set; }

    private void Reorder()
    {
        for (int i = 0; i < requirements.Count - 1; i += 2)
        {
            var temp = requirements[i].Rank;
            requirements[i].Rank = requirements[i + 1].Rank;
            requirements[i + 1].Rank = temp;
        }
    }
}
public class Requirement : BindableBase
{
    private double _rank;

    public double Rank
    {
        get { return _rank; }
        set { SetProperty(ref _rank, value); }
    }

    public string Name { get; set; }
}