Skip to main content
 首页 » 编程设计

c#之带有 Observable 集合类型的 Viewmodel 的 MVVM ListView 不更新 View

2024年05月10日39sky-heaven

我的问题是我在 Viewmodel 中添加了 2 个类型文件对象(出于测试原因),这是一个可观察的集合,但 View 不会随着应用程序的启动而更新。 这是 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 对象时更新 View ,是否真的需要 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> 

请您参考如下方法:

像这样更改您的代码;

你的"file"类;这里没有太大变化。但是请看一下我实现属性和 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。如您所见,此 View 模型与您的完全不同。这里有一些注释的属性/方法。如果您计划实现某些命令,该代码可能会有用。

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); 
        } 
    } 
} 

您的观点;看看绑定(bind)。那是你的问题之一。

<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>