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>
所有这些都有效——直到我尝试将<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的双向绑定和过滤的主要内容,如果未能解决你的问题,请参考以下文章