C# StackPanel上的FluidMoveBehavior在设置动画之前会闪烁

C# StackPanel上的FluidMoveBehavior在设置动画之前会闪烁,c#,wpf,xaml,blend,C#,Wpf,Xaml,Blend,我有一个ItemsControl,它附加了FluidMoveBehavior,如下所示: <ScrollViewer VerticalScrollBarVisibility="Auto"> <ItemsControl ItemsSource="{Binding RequirementsSource}" ItemTemplateSelector="{StaticResource RequirementTemplateSelector}"> <I

我有一个
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>
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();
}

有人知道是什么导致了这种“闪烁”吗?我能做些什么来阻止它?

删除
RequirementsSource.Refresh()代码中的行

由于您使用的是livesorting,所以当Requirement.Rank发生更改时(触发PropertyChanged事件),动画就会启动。但是,当您调用refresh时,它会使用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;
        }
    }
}

你能给出一些代码来显示你是如何排序的吗,因为你发布的内容看起来很好——除了没有模板可以工作之外with@Cadogi我添加了显示
itemsource
的代码。另外,实际代码使用的是模板,我只是把所有的东西都放在这个例子中,我想声明:RequirementsSource=New ListCollectionView(Requirements)会先刷新视图(通过有效地设置一个新的itemsource),然后当你排序时,这就是你使用FluidMoveBehavior看到的,因为它会从它认为是初始位置移动。(我可能有点不对劲)@Cadogi该代码只在viewmodel的构造函数中。不是每次对代码排序时都调用它。我在问题中添加了导致排序触发的方法。这现在更有意义了。可能值得推迟数据源的刷新,例如RequirementsSource.DeferRefresh();在开始排序之前,然后进行刷新,这样只有一次更新才会命中ItemsPanel。这最终是正确的答案(关键部分是刷新触发了Reset参数)。为了做到这一点,我需要拉取我创建的
PropertyRequirementViewModel
s,它为
SwapRanks
方法中的
Rank
属性而不是实际对象本身实现了
INotifyPropertyChanged
。我还按照Cadogi的建议将它们包装在
DeferRefresh
中。我不知道为什么要使用DeferRefresh,然后从SwapRank调用PropertyChanged。我添加了一些示例代码,这些代码对我很有用。现在,当这些对象的Rank属性发生更改时,propertychanged事件将触发两次:一次是在我设置第一个时,一次是在我设置第二个时。我添加了延迟刷新,因此这只会导致一次刷新。我从该方法中删除了显式刷新调用。我相信使用LiveShaping绑定到ListCollectionView的ItemsControl数据已经过优化,无需进行DefferRefresh。简单地说,每次在循环中调用PropertyChanged时,不会刷新ItemsControl
public class Requirement : BindableBase
{
    private double _rank;

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

    public string Name { get; set; }
}