WPF/MVVM中ObservableCollection的双向绑定和过滤

Posted

技术标签:

【中文标题】WPF/MVVM中ObservableCollection的双向绑定和过滤【英文标题】:Two-way binding and filtering of ObservableCollection in WPF/MVVM 【发布时间】:2020-12-04 14:18:56 【问题描述】:

我在将应用程序重构为 MVVM 时正在学习 MVVM 模式。

我有一个模型类Machine,它以ObservableCollection<Installation> Installations 的形式提供安装列表。

在其中一个窗口(视图)中,我只需要显示那些有更新的安装(因此满足以下条件):

    private void InstallationsToUpdateFilter(object sender, FilterEventArgs e)
    
        var x = (Installation)e.Item;
        bool hasNewVersion = ShowAllEnabledInstallations ?  true : x.NewVersion != null;
        bool isSetAndOn = !String.IsNullOrEmpty(x.Path) && x.CheckForUpdatesFlag;
        e.Accepted = isSetAndOn && hasNewVersion;
    

    private void OnFilterChanged()
    
        installationsToUpdateSource?.View?.Refresh();
    

我通过在我的 ViewModel 中过滤来做到这一点:

class NewVersionViewModel : ViewModelBase

    private Machine machine = App.Machine;
    ...

    public NewVersionViewModel(...)
    
        ...

        InstallationsToUpdate.CollectionChanged += (s, e) => 
         
            OnPropertyChanged("NewVersionsAvailableMessage");
            OnFilterChanged();
        ;

        installationsToUpdateSource = new CollectionViewSource();
        installationsToUpdateSource.Source = InstallationsToUpdate;
        installationsToUpdateSource.Filter += InstallationsToUpdateFilter;

    

    public ObservableCollection<Installation> InstallationsToUpdate
    
        get  return machine.Installations; 
        set  machine.Installations = value; 
    

    internal CollectionViewSource installationsToUpdateSource  get; set; 
    public ICollectionView InstallationsToUpdateSourceCollection
    
        get  return installationsToUpdateSource.View; 
    
    ...

这是由自定义 ListView 完成的:

<ListView ItemsSource="Binding InstallationsToUpdateSourceCollection" ... >
            ...
            <ListView.ItemTemplate>
                <DataTemplate>
                    <Grid ...>
                        <Grid ...>
                            <CheckBox Style="StaticResource LargeCheckBox"
                                      IsChecked="Binding Path=MarkedForUpdate, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged"
                                      IsEnabled="Binding Path=HasNewVersion"
                                      />
                        </Grid>
                        <Label Content="Binding Path=InstalledVersion.Major" Grid.Column="1" Grid.Row="0" FontSize="50" FontFamily="Segoe UI Black" HorizontalAlignment="Center" VerticalAlignment="Top" Margin="0,-10,0,0"/>
                        ...
                        <Grid.ContextMenu>
                            <ContextMenu>
                                ...
                            </ContextMenu>
                        </Grid.ContextMenu>
                    </Grid>                        
                </DataTemplate>
            </ListView.ItemTemplate>                
        </ListView>

所有这些都有效——直到我尝试将&lt;CheckBox IsChecked="Binding Path=MarkedForUpdate...“发送”回我的模型——所以它将被存储在那里。

如何做到这一点? (我可以在ICollectionView 上设置某种二传手吗?)

可以更改当前架构。我最终需要什么:

    ListView(当前:works)中显示模型中的项目(installations) 仅过滤/显示满足某些条件的安装(当前:works) 将MarkedForUpdate 复选框中的更改反映回模型(当前:not working

我搜索了很多,但找不到相关的解决方案或建议。 任何帮助将不胜感激。谢谢!

【问题讨论】:

在 WPF 中过滤视图的典型方法是使用 CollectionViewSorce。尝试使用它来实现它。 Click me 【参考方案1】:

我发现了问题所在。虽然这是一个愚蠢的错误,但我仍然想分享它以节省某人的时间。

模型本身会在上述配置中更新。问题是什么模型属性(在我的例子中是Machine.Installations)没有实现 INotifyPropertyChanged 接口,所以其他视图(通过它们相应的视图模型)不知道变化。因此,一个人不仅应该在 ViewModel 中使用OnPropertyChanged/RaisePropertyChanged,还应该在 Model 中使用。

希望这可以帮助某人。

【讨论】:

以上是关于WPF/MVVM中ObservableCollection的双向绑定和过滤的主要内容,如果未能解决你的问题,请参考以下文章

wpf mvvm获取列表行数据

WPF自学入门WPF MVVM模式Command命令

WPF MVVM实例三

WPF/MVVM中ObservableCollection的双向绑定和过滤

wpf mvvm 还都有哪些框架

有没有wpf mvvm框架的详细讲解?