在模型属性设置为新实例时更新 MVVM 视图

本文关键字:实例 更新 视图 MVVM 属性 模型 设置 新实例 | 更新日期: 2023-09-27 18:30:46

我在WPF应用程序中有一个ViewModel和一个View。屏幕上有一系列输入(日期选择器,文本框和组合框)。

输入绑定到 ViewModel 的 NewItem 属性,DataGrid 绑定到 WorkLog 集合属性。

当用户单击"添加"按钮时,我希望将 NewItem 添加到 WorkLog 集合中,并且 NewItem 属性重置以允许用户添加更多项。问题是,当我添加项目时,如果我重新实例化 NewItem,那么控件仍然会填充,但在后台,VM 值都是默认值(或空值),因此它不起作用。

如何重置 NewItem 属性并更新 UI 以反映这一点?我尝试了 INotifyPropertyChanged 无济于事(因为我正在设置为新实例而不是更改值)。

为了简洁起见,我已经修剪了代码

public class WorkLogItem : INotifyPropertyChanged
{
    public WorkLogItem()
    {
        this.Datestamp = DateTime.Today;
        this.Staff = new Lookup();
        this.WorkItem = new Lookup();
    }
    #region ID
    private Int32 _ID;
    public Int32 ID
    {
        get { return this._ID; }
        set
        {
            this._ID = value;
            FirePropertyChanged("ID");
        }
    }
    #endregion
    #region Datestamp
    private DateTime? _Datestamp;
    public DateTime? Datestamp
    {
        get { return this._Datestamp; }
        set
        {
            this._Datestamp = value;
            FirePropertyChanged("Datestamp");
        }
    }
    #endregion
    #region Staff
    private Model.Lookup _Staff;
    public Model.Lookup Staff
    {
        get { return this._Staff; }
        set
        {
            this._Staff = value;
            FirePropertyChanged("Staff");
        }
    }
    #endregion
    #region WorkItem
    private Model.Lookup _WorkItem;
    public Model.Lookup WorkItem
    {
        get { return this._WorkItem; }
        set
        {
            this._WorkItem = value;
            FirePropertyChanged("WorkItem");
        }
    }
    #endregion
    #region Hours
    private Decimal _Hours;
    public Decimal Hours
    {
        get { return this._Hours; }
        set
        {
            this._Hours = value;
            FirePropertyChanged("Hours");
        }
    }
    #endregion
    public event PropertyChangedEventHandler PropertyChanged;
    // Create the OnPropertyChanged method to raise the event
    protected void FirePropertyChanged(String name)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
            handler(this, new PropertyChangedEventArgs(name));
    }
}

查看模型

public Model.WorkLogItem NewItem { get; set; }
public ObservableCollection<Model.WorkLogItem> WorkLog { get; set; }

视图

<Label Content="Date " />
<DatePicker SelectedDate="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Window}}, Path=DataContext.NewItem.Datestamp, NotifyOnSourceUpdated=True}" />
<Label Content="Work Item " />
<ComboBox Grid.Column="1" Grid.Row="2" DataContext="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Window}}, Path=DataContext.WorkItems}" ItemsSource="{Binding}" DisplayMemberPath="Value" SelectedValuePath="ID" SelectedItem="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Window}}, Path=DataContext.WorkLogItem.Type, NotifyOnSourceUpdated=True}" IsSynchronizedWithCurrentItem="True" />
<Label Grid.Row="3" Content="Hours " />
<TextBox Grid.Column="1" Grid.Row="3" Text="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Window}}, Path=DataContext.NewItem.Hours, NotifyOnSourceUpdated=True}" />

C#

在Window_Loaded:

this.DataContext = this.VM;

在Add_Click

this.VM.WorkLog.Add(this.VM.NewItem);
this.VM.NewItem = new Model.WorkLogItem();

在模型属性设置为新实例时更新 MVVM 视图

您的ViewModel还必须实现INotifyPropertyChanged

public class ViewModel : INotifyPropertyChanged
{
    private Model.WorkLogItem _newItem;
    public ViewModel()
    {
        NewItem = new Model.WorkLogItem();
        WorkLog  = new ObservableCollection<Model.WorkLogItem>();
    }
    public Model.WorkLogItem NewItem
    { 
        get { return _newItem; }
        set
        {
            _newItem = value;
            FirePropertyChanged("NewItem");
        }
    }
    public ObservableCollection<Model.WorkLogItem> WorkLog { get; set; }
    // INotifyPropertyChanged implementation here...
}

绑定到ComboBox时,请务必使用Mode=TwoWay

<ComboBox ... SelectedItem="{Binding ... Mode=TwoWay}" />

我这样做的方法是在我的数据对象中设置一个空的构造函数,将其所有属性设置为默认值。然后,当我想将视图"重置"为所有空字段时,我只需将数据绑定属性设置为一个新项目:

NewItem = new YourDataType();

这将按预期更新所有数据绑定控件属性。请注意,我的数据类型类都实现了 INotifyPropertyChanged 接口,并且这种清除 UI 控件的方法只有在它们实现它时才有效。