代码之家  ›  专栏  ›  技术社区  ›  Rob King

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

  •  3
  • Rob King  · 技术社区  · 13 年前

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

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

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

    如何重置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#

    在加载的窗口中(_L):

    this.DataContext = this.VM;
    

    在Add_Click中

    this.VM.WorkLog.Add(this.VM.NewItem);
    
    this.VM.NewItem = new Model.WorkLogItem();
    
    2 回复  |  直到 13 年前
        1
  •  3
  •   Ed Chapel    13 年前

    你的 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}" />
    
        2
  •  0
  •   Sheridan    13 年前

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

    NewItem = new YourDataType();
    

    这将按预期更新所有数据绑定控件的财产。请注意,我的数据类型类都实现了 INotifyPropertyChanged 接口,并且这种清除UI控件的方法只有在它们确实实现了它的情况下才会起作用。