【问题标题】:Updating a MVVM View when model property is set to new instance当模型属性设置为新实例时更新 MVVM 视图
【发布时间】:2013-09-10 16:04:05
【问题描述】:

我在 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();

【问题讨论】:

  • 我在您的代码中的任何地方都看不到 NotifyPropertyChangeObservableCollection&lt;T&gt;。您需要这些用于 2 向绑定。
  • 谢谢。我已经实现了 INotifyPropertyChanged 并将所有列表更改为 ObservableCollections 但它没有任何区别。

标签: c# wpf mvvm


【解决方案1】:

您的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}" />

【讨论】:

  • 谢谢。这就是我所缺少的,现在它正在工作(几乎)。我会将其标记为答案,您知道为什么我的 ComboBox 不会重置所选项目吗?我用过 IsSynchronizedWithCurrentItem="true"
  • 检查绑定是否有Mode=TwoWay(见答案底部)。
  • 我有,也有 NotifyOnSourceUpdated=True
  • 你能描述一下“重置选中项”的意思吗?数据往哪个方向发展? ComboBox 没有重置为空吗?
  • 组合框仍然显示我选择的任何项目,但如果我再次单击添加,则背景中的选定项目为空
【解决方案2】:

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

NewItem = new YourDataType();

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

【讨论】:

  • 我曾尝试将它实例化为一个新实例,但我没有在构造函数中明确设置值。我现在已经尝试过了,但不幸的是它没有用。我的值全部重置,所以我的对象是正确的,但 UI 没有改变 - 我认为这是因为它是一个新实例而不是值更改,所以 UI 没有得到通知。
  • 当我将属性设置为新实例时,我的 UI 会被清除... UI 不知道也不关心对象是否已更改... 它只是绑定到生成的属性值在新实例中为空。
  • 我不知道我在做什么不同。我在 XAML 绑定中添加了 NotifyOnSourceUpdated=True,我在每个属性上实现了 INotifyPropertyChanged,我的 C# 就是 this.VM.WorkLog.Add(this.VM.WorkLogItem); this.VM.WorkLogItem = new Model.WorkLogItem();
  • 如果您调用this.VM.WorkLog.Add(new Model.WorkLogItem());,UI 属性是否设置为新实例中的值?
  • 不,相同的 UI 效果,但我的收藏添加了一个空项目。我已经用我更新的代码更新了问题
猜你喜欢
  • 1970-01-01
  • 2021-06-09
  • 2018-06-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-01-04
相关资源
最近更新 更多