在WPF中,如何在ListView中过滤集合?

4
我正在创建一个WPF应用程序,使用Entity Framework、CRUD操作和MVVM,允许用户输入有关其员工的一些详细信息。目前为止,我有两个ListViews。其中一个包含员工姓名列表(listview1),而另一个(listview2)列出了他们的详细信息,例如出生日期、地址等。下面的图像将更好地说明我正在创建的内容: ListView 我正在使用CollectionViewSoruce来使我能够在从listbox1选择特定名称时筛选listview2上的结果。到目前为止,我能够做到这一点,但是当我添加或删除员工时,它会抛出异常;
 An unhandled exception of type 'System.StackOverflowException' occurred in *.UI.exe

这里有一些可能有用的代码片段。
ViewModel:
    private EmployeeListViewModel()
        : base("")
    {
        EmployeeList = new ObservableCollection<EmployeeViewModel>(GetEmployees());
        this._employeeCol = new ListCollectionView(this.employeeList); 
    }

    private ListCollectionView _employeeCol;
    public ICollectionView EmployeeCollection
    {
        get { return this._employeeCol; }
    }

    private ObservableCollection<EmployeeViewModel> employeeList;
    public ObservableCollection<EmployeeViewModel> EmployeeList
    {
        get { return employeeList; }
        set
        {
            employeeList = value;
            OnPropertyChanged("EmployeeList");
        }
    }

    private EmployeeViewModel selectedEmployee = null;
    public EmployeeViewModel SelectedEmployee
    {
        get
        {
            return selectedEmployee;
        }
        set
        {
            selectedEmployee = value;
            OnPropertyChanged("SelectedEmployee");
            EmployeeCollection.Filter = new Predicate<object>(o => SelectedEmployee != null && o != null && ((EmployeeViewModel)o).EmployeeID == SelectedEmployee.EmployeeID);
        }
    }

    internal ObservableCollection<EmployeeViewModel> GetEmployees()
    {
        if (employeeList == null)
            employeeList = new ObservableCollection<EmployeeViewModel>();
        employeeList.Clear();

        foreach (DataObjects.Employee i in new EmployeeRepository().GetAllEmployees())
        {
            EmployeeViewModel c = new EmployeeViewModel(i);
            employeeList.Add(c);
        }
        return employeeList;
    }

ListView2 - 员工列表视图;

            <ListView Name="lsvEmpoyeeList" Height="170" Width="700"
                  ScrollViewer.VerticalScrollBarVisibility="Visible" 
                  ScrollViewer.HorizontalScrollBarVisibility="Visible" 
                  HorizontalAlignment="Center"
                  IsSynchronizedWithCurrentItem="True"
                  ItemsSource="{Binding EmployeeCollection}"
                  SelectedItem="{Binding SelectedEmployee}">
                    <ListView.View>
                      <GridView>
                        <GridViewColumn Header="Position" DisplayMemberBinding="{Binding Position}" Width="100" />
                        <GridViewColumn Header="DateOfBirth" DisplayMemberBinding="{Binding DateOfBirth, StringFormat={}\{0:dd/MM/yyyy\}}" Width="100" />
                     </GridView>
                    </ListView.View>
                </ListView>

ListView1 - 员工设置视图;

            <ListView Height="380" HorizontalAlignment="Left" Name="lsNames" VerticalAlignment="Top" Width="170" 
             ScrollViewer.VerticalScrollBarVisibility="Visible" 
             ScrollViewer.HorizontalScrollBarVisibility="Visible" 
             SelectedItem="{Binding SelectedEmployee}" 
             ItemsSource="{Binding EmployeeList}" Grid.RowSpan="2" Grid.Row="1">

        <ListView.View>
            <GridView>
                <GridViewColumn Header="FirstName" DisplayMemberBinding="{Binding FirstName}" Width="80" />
                <GridViewColumn Header="Surname" DisplayMemberBinding="{Binding Surname}" Width="80" />
            </GridView>
        </ListView.View>
    </ListView>
   <ContentControl Grid.Column="1" Grid.Row="1" HorizontalAlignment="Center"
                    Content="{Binding}" ContentTemplate="{StaticResource EmployeeListView}" />

如您所见,我已将筛选器放置在setaccessor中。我曾尝试将其放置于构造函数中,但似乎没有任何细节出现在ListView2上。
此外,如果我从ListView2而不是从ListView1选择一行,则还会产生StackOverFlowException,我不确定为什么会这样。
非常感谢您的帮助和建议。同时,抱歉问题比较复杂!

现在你真正的问题是什么,是你遇到了StackOverflowException还是ListView2中没有列出详细信息? - Jehof
似乎这是两者的结合,特别是与过滤器有关(很可能与绑定有关)。就像我在问题中所述,如果我将过滤器放在构造函数中,它不会查询结果,也不会显示任何数据。而如果我在“setaccessor”中添加过滤器,则会产生异常。这就是为什么我要问这个问题,以了解如何改进我的应用程序。 - greg
SelectedEmployee 的 getter 方法是怎么实现的?你那里有打字错误吗? - Jehof
就像我的代码片段中一样。 - greg
1个回答

3

我认为UI不知道EmployeeCollection已经改变了

尝试在筛选器应用后的SelectedEmployee setter中为EmployeeCollection添加一个PropertyChanged事件。

public EmployeeViewModel SelectedEmployee
{
    get { return selectedEmployee;}
    set
    {
        selectedEmployee = value;
        OnPropertyChanged("SelectedEmployee");
        EmployeeCollection.Filter = new Predicate<object>(o => SelectedEmployee != null && o != null && ((EmployeeViewModel)o).EmployeeID == SelectedEmployee.EmployeeID);

        // EmployeeCollection view has changed, Notify UI
        OnPropertyChanged("EmployeeCollection");
    }
}

关于 StackOverflowException,我认为这是由于两个 ListView 都对 SelectedEmployee 进行了 TwoWay 绑定所导致的。因此,当一个 ListView1 改变 SelectedItem 时,它会导致 ListView2 更新其选定项,从而更新 ListView1,如此循环反复。

尝试将 ListView2 上的 SelectedEmployee 绑定设置为 OneWay

SelectedItem="{Binding SelectedEmployee, Mode=OneWay}">


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接