使用 WPF MVVM 过滤数据网格,它可以工作,但我不知道为啥

Posted

技术标签:

【中文标题】使用 WPF MVVM 过滤数据网格,它可以工作,但我不知道为啥【英文标题】:Filtering on datagrid with WPF MVVM, it works but I don't know why使用 WPF MVVM 过滤数据网格,它可以工作,但我不知道为什么 【发布时间】:2017-12-21 13:26:37 【问题描述】:

所以问题是,昨天我想做一个用于过滤数据网格的搜索栏。我成功地做到了这一点,但是当我今天查看它时,我意识到我不知道它为什么会起作用。这让我感到困惑:

基本上我有一个数据网格,它的 ItemsSource 设置为称为 Equipments 的 ObservableCollection。为了过滤设备,我还创建了一个名为 EquipmentView 的 ICollectionView,它只是我可以对其进行过滤的设备的镜像。

设备从我的数据库中的表中填充到视图模型中,如下所示:

 public async Task LoadAsync()
    
        try
        
            var lookup = await _equipmentLookupDataService.GetEquipmentLookupAsync();
            Equipments.Clear();
            foreach (var item in lookup)
            
                Equipments.Add(item);
            
            EquipmentView = CollectionViewSource.GetDefaultView(Equipments);
            EquipmentView.Filter = new Predicate<object>(Filter);
        
        catch (Exception e)
        
            MessageBox.Show(e.Message, "An error occurred", MessageBoxButton.OK, MessageBoxImage.Warning);
            //create new error object from the exception and add to DB
            Error error = new Error
            
                ErrorMessage = e.Message,
                ErrorTimeStamp = DateTime.Now,
                ErrorStackTrace = e.StackTrace,
                LoginId = CurrentUser.LoginId
            ;
            await _errorDataService.AddError(error);
        
    

EquipmentView.Filter 调用 Filter 方法:

 public bool Filter(object obj)
    
        var data = obj as EquipmentLookup;

        if (EquipmentView != null)
        
            if (!string.IsNullOrEmpty(_filterString))
            
                string allcaps = _filterString.ToUpper();
                return data.TypeName.StartsWith(_filterString) || data.TypeName.StartsWith(allcaps);
            
            return true;
        
        return false;
    

仅当 TypeName 属性以 filterstring 开头时返回 true,这是绑定到我的搜索栏的字符串。

现在我想我只需要将数据网格 ItemsSource 设置为 EquipmentView。如果我这样做,一切正常,数据网格只显示与搜索栏匹配的任何内容。

显然,如果我将数据网格上的 itemsSource 设置回 Equipments,它仍然可以工作,包括搜索栏。为什么是这样?据我了解,我在 EquipmentView 上的过滤不应该改变关于 Equipments 的任何内容,但它似乎还是这样做了。

一切都很好,我只是希望我知道为什么。

还有搜索栏的 XAML 代码:

<TextBox Name="SearchBar" Margin="10 10 10 10" Text="Binding FilterString, UpdateSourceTrigger=PropertyChanged"/>

数据网格:

        <DataGrid MaxHeight="800"
            ItemsSource="Binding Equipments"
            SelectedItem="Binding SelectedEquipment, Mode=TwoWay"
            IsReadOnly="True"
            CanUserReorderColumns="False"
            SelectionMode="Single"
            ColumnWidth="*">
            <DataGrid.ItemContainerStyle>
                <Style TargetType="DataGridRow">
                    <EventSetter Event="MouseDoubleClick"
                     Handler="Row_DoubleClick" />
                </Style>
            </DataGrid.ItemContainerStyle>
        </DataGrid>

【问题讨论】:

当您绑定到一个集合时,WPF 实际上是绑定到该集合的默认视图。视图只是一个包装器,使您能够过滤、排序等。 【参考方案1】:

来自 WPF 文档:

所有集合都有一个默认的 CollectionView。 WPF 总是绑定到一个 视图而不是集合。如果你直接绑定到一个集合, WPF 实际上绑定到该集合的默认视图。这 默认视图由​​集合的所有绑定共享,这会导致 所有直接绑定到集合以共享排序、过滤器、 组,以及一个默认视图的当前项目特征。

现在在您的代码中,您正在这样做:

EquipmentView = CollectionViewSource.GetDefaultView(Equipments);
EquipmentView.Filter = new Predicate<object>(Filter);

【讨论】:

以上是关于使用 WPF MVVM 过滤数据网格,它可以工作,但我不知道为啥的主要内容,如果未能解决你的问题,请参考以下文章

是否可以在 mvvm 模式中获取 wpf 数据网格上的动态列?

Wpf数据网格CurrentCell属性只触发一次MVVM

WPF MVVM 将 ComboBox 绑定到 Datagrid 选定项

WPF MVVM 创建动态控件

WPF MVVM 将 Dictionary<String, List<String>> 绑定到数据网格

带有自定义列的 WPF 数据网格绑定