首页 > 解决方案 > WPF/MVVM中ObservableCollection的双向绑定和过滤

问题描述

我在将应用程序重构为 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>

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

怎么做?(我可以有某种二传手ICollectionView吗?)

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

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

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

标签: c#wpfmvvmdata-bindingbinding

解决方案


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

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

希望这可以帮助某人。


推荐阅读