为什么在 for 循环内设置 WPF ListCollectionView 过滤器谓词会导致奇怪的行为?

Why does setting a WPF ListCollectionView Filter predicate inside a for loop cause strange behavior?

我最近专注于 WPF 应用程序的一个问题,在 for 循环中设置过滤器谓词导致 UI 中没有任何内容出现:

    private void SetListCollectionViewFiltersHasProblem()
    {
        for (int i = 0; i <= 1; ++i)
        {
            _peopleViews[i].Filter = obj => ((Person)obj).Number == i;
        }
    }

而我认为等效的代码工作得很好:

    private void SetListCollectionViewFiltersWorks()
    {
        _peopleViews[0].Filter = obj => ((Person)obj).Number == 0;
        _peopleViews[1].Filter = obj => ((Person)obj).Number == 1;
    }

这与For循环中的lambda表达式有关。 This sort of problem exists in Javascript 但我认为 C# 不一样。

使用 For 循环设置 Filter 函数没有问题的最佳解决方案是什么?

完整代码:

<Window x:Class="WpfListCollectionView.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <StackPanel Orientation="Horizontal">
        <Button Name="AddList0" Click="AddList0_Click">
            Add to list 0
        </Button>
        <Button Name="AddList1" Click="AddList1_Click">
            Add to list 1
        </Button>
        <ItemsControl Name="_list0" ItemsSource="{Binding}">
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <TextBlock Text="{Binding Path=FirstName}" />
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>
        <ItemsControl Name="_list1" ItemsSource="{Binding}">
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <TextBlock Text="{Binding Path=FirstName}" />
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>
    </StackPanel>
</Window>

namespace WpfListCollectionView
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public class Person
        {
            public string FirstName { get; set; }
            public int Number { get; set; }
        }

        private ObservableCollection<Person> _people = new ObservableCollection<Person>();
        private ListCollectionView[] _peopleViews = new ListCollectionView[2];        


        public MainWindow()
        {
            InitializeComponent();

            _peopleViews[0] = new ListCollectionView(this._people);
            _peopleViews[1] = new ListCollectionView(this._people);

            SetListCollectionViewFiltersHasProblem();
            //SetListCollectionViewFiltersWorks();

            // Set up the DataContexts
            _list0.DataContext = _peopleViews[0];
            _list1.DataContext = _peopleViews[1];

            // Put some data in
            _people.Add(new Person { FirstName = "Mike", Number = 0 });
            _people.Add(new Person { FirstName = "Joe", Number = 1 });
        }

        private void SetListCollectionViewFiltersHasProblem()
        {
            for (int i = 0; i <= 1; ++i)
            {
                _peopleViews[i].Filter = obj => ((Person)obj).Number == i;
            }
        }

        private void SetListCollectionViewFiltersWorks()
        {
            _peopleViews[0].Filter = obj => ((Person)obj).Number == 0;
            _peopleViews[1].Filter = obj => ((Person)obj).Number == 1;
        }

        private void AddList0_Click(object sender, RoutedEventArgs e)
        {
            _people.Add(new Person() { FirstName = "AddedAlan", Number = 0 });
        }

        private void AddList1_Click(object sender, RoutedEventArgs e)
        {
            _people.Add(new Person() { FirstName = "AddedAdam", Number = 1 });
        }
    }
}

您设置了稍后将针对您 collection 的每个项目调用的委托。此时没有调用它,问题是它捕获 i 变量而不是它的值。您可以通过在循环中使用局部变量来解决它

for (int i = 0; i <= 1; ++i)
{
    var localValue = i;
    _peopleViews[i].Filter = obj => ((Person)obj).Number == localValue;
}