具有可观察集合类型的 Viewmodel 的 MVVM ListView 不更新视图
Posted
技术标签:
【中文标题】具有可观察集合类型的 Viewmodel 的 MVVM ListView 不更新视图【英文标题】:MVVM ListView with Viewmodel of type Observable Collection not updating view 【发布时间】:2016-01-11 01:30:33 【问题描述】:我的问题是我在 Viewmodel 中添加了 2 个类型文件对象(出于测试原因),这是一个可观察的集合,但视图不会随着应用程序的启动而更新。 这是 Mainview.cs:
public class MainView:ObservableCollection<Files>
public MainView()
Files x = new Files("picture", "jpg");
Files x1 = new Files("soundfile", "mp3");
Add(x);
Add(x1);
我做错了什么?以及如何避免这个错误?如果我不更改 Files 类中的属性并且只想在创建新的 File 对象时更新视图,是否真的需要 INotifyPropertyChanged?
我上了这门课:
public class Files:INotifyPropertyChanged
private String _fileName;
public String FileName
get return _fileName;
set _fileName = value; OnPropertyChanged("FileName");
private String _dataType;
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propertyName)
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
public String DataType
get return _dataType;
set _dataType = value; OnPropertyChanged("DataType");
public Files(string filename, string dataType)
this._fileName = filename;
this._dataType = dataType;
还有这个 ViewModel:
public class MainView:ObservableCollection<Files>
public MainView()
Files x = new Files("picture", "jpg");
Files x1 = new Files("soundfile", "mp3");
Add(x);
Add(x1);
并在 xaml 中做到这一点:
<Window x:Class="ClientTestDesign.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:ClientTestDesign"
xmlns:vm="clr-namespace:ClientTestDesign.ViewModel"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525"
>
<Window.Resources>
<vm:MainView x:Key="View"></vm:MainView>
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="75"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
</Grid.ColumnDefinitions>
<Button Grid.Column="0" Style="DynamicResource ForwardBackButton" Content="Back"></Button>
<Button Grid.Column="1" Style="DynamicResource StopButton" Content="Pause"></Button>
<Button Grid.Column="2" Style="DynamicResource ForwardBackButton" Content="Forward"></Button>
<ListView Grid.Row="1" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Grid.ColumnSpan="3">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="Binding /FileName, Source=StaticResource View"></TextBlock>
<TextBlock Text="Binding /FileName, Source=StaticResource View"></TextBlock>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
【问题讨论】:
这更多的是一个理解问题。您的Files
类应该是您的 ViewModel。 Files
应该是您的 ViewModel 中的一个属性。
@KosalaW 你的意思是文件应该是可观察的集合?我的 fviewmodel 应该包含文件的属性?
@KosalaW 这不可能是唯一的错误,不是吗?我改了没用
我会尽快写一个答案。这样你就能更好地理解它。
@KosalaW 好的,我很期待
【参考方案1】:
像这样改变你的代码;
你的“文件”类;这里没有太大变化。但是看看我实现属性和 OnPropertyChanged 的方式。
using System.ComponentModel;
namespace WpfApplication1
public class File:INotifyPropertyChanged
private string _fileName;
private string _dataType;
public string FileName
get return _fileName;
set
_fileName = value;
OnPropertyChanged("FileName");
public string DataType
get return _dataType;
set
_dataType = value;
OnPropertyChanged("DataType");
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propertyName)
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
这是您的 ViewModel。如您所见,此视图模型与您的完全不同。这里有一些注释的属性/方法。如果您打算实现一些命令,那么该代码可能会很有用。
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Windows.Input;
namespace WpfApplication1
public class MainWindowViewModel1:INotifyPropertyChanged
private ObservableCollection<File> _files;
private File _selectedFile;
//private ICommand _getFiles;
public ObservableCollection<File> Files
get return _files;
set
_files = value;
OnPropertyChanged("Files");
public File SelectedFile
get return _selectedFile;
set
_selectedFile = value;
OnPropertyChanged("SelectedFile");
//public ICommand GetFiles
//
// get return _getFiles;
// set
//
// _getFiles = value;
//
//
//public void ChangeFileName(object obj)
//
// Files[0].FileName = "File_" + new Random().Next().ToString(CultureInfo.InvariantCulture);
//
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propertyName)
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
public MainWindowViewModel1()
Files = new ObservableCollection<File>();
Files.Add(new File() FileName = "picture", DataType = "jpg");
Files.Add(new File() FileName = "soundfile", DataType = "mp3" );
//GetFiles = new RelayCommand(ChangeFileName, param => true);
您的观点;看看绑定。那是你的问题之一。
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525"
xmlns:vm="clr-namespace:WpfApplication1">
<Window.Resources>
<vm:MainWindowViewModel1 x:Key="View"></vm:MainWindowViewModel1>
</Window.Resources>
<Grid>
<ListView HorizontalAlignment="Stretch" VerticalAlignment="Stretch" ItemsSource="Binding Source=StaticResource View, Path=Files, Mode=TwoWay" SelectedItem="Binding Source=StaticResource View, Path= SelectedFile, Mode=TwoWay" Margin="28,27,31,146">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="Binding Path= FileName, Mode=TwoWay"></TextBlock>
<TextBlock Text="Binding Path= DataType, Mode=TwoWay"></TextBlock>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<!--<Button Content="Refresh" Command="Binding Source=StaticResource View,Path = GetFiles" HorizontalAlignment="Left" Height="33" Margin="347,236,0,0" VerticalAlignment="Top" Width="139"/>-->
</Grid>
【讨论】:
它起作用了,我使用了你的代码并删除了我所有的额外网格和列+行定义,然后它起作用了。谢谢,最好有一个可观察的集合作为列表视图中的一个对象,我很高兴它的工作:D【参考方案2】:你需要设置ListView的ItemsSource。在这种情况下,它与您的 DataContext 相同,因此只需执行以下操作:
<ListView ItemsSource="Binding" ... etc...
【讨论】:
没用,如果没有明确设置,ItemsSource 不是从 DataContext 继承的 不,它与 DataContext 完全分离。使用您发布的代码对我来说效果很好,所以您必须做一些您没有向我们展示的其他事情。 那么您可以看到 2 个列表对象吗?我没有改变任何它不起作用的东西:( 是的,列表中有两个对象。我想说您设置 DeviceContext 的方式可能有问题...我使用了 MVVM 自动设置的 ServiceLocator,并在 MainWindow 中执行了DataContext="Binding Source=StaticResource Locator, Path=MainView"
。你自己怎么设置的?
@MarkFeldman 他使用静态资源并在绑定中指定Source
。没关系。但是对于更复杂的视图,我认为使用 DataContext 要好得多。以上是关于具有可观察集合类型的 Viewmodel 的 MVVM ListView 不更新视图的主要内容,如果未能解决你的问题,请参考以下文章
如果 viewmodel1 属性发生变化,通知 viewmodel2
Knockout JS:从 viewmodel 可观察数组创建 Json