【问题标题】:Two-way binding and filtering of ObservableCollection in WPF/MVVMWPF/MVVM中ObservableCollection的双向绑定和过滤
【发布时间】: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 上设置某种二传手吗?)

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

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

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

【问题讨论】:

  • 在 WPF 中过滤视图的典型方法是使用 CollectionViewSorce。尝试使用它来实现它。

标签: c# wpf mvvm data-binding binding


【解决方案1】:

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

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

希望这可以帮助某人。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-03-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-18
    • 2011-12-31
    • 2015-11-08
    • 2013-03-15
    相关资源
    最近更新 更多