Reputation: 1201
I have a ViewModel and a View in a WPF application. On the screen there are a selection of inputs (date picker, text box and combobox).
The inputs are bound to the NewItem property of the ViewModel, the DataGrid is bound to the WorkLog collection property.
When the user clicks on the Add button I want the NewItem to be added to the WorkLog collection, and the NewItem property reset in order to allow the user to add more items. The problem is that when I add the item, if I reinstantiate NewItem then the controls are still populated but in the background the VM values are all defaults (or nulls) so it doesn't work.
How can I reset the NewItem property and update the UI to reflect this? I tried INotifyPropertyChanged to no avail (as I am setting to new instance rather than changing values).
I have trimmed the code for brevity
Model
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));
}
}
View Model
public Model.WorkLogItem NewItem { get; set; }
public ObservableCollection<Model.WorkLogItem> WorkLog { get; set; }
View
<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#
In Window_Loaded:
this.DataContext = this.VM;
In Add_Click
this.VM.WorkLog.Add(this.VM.NewItem);
this.VM.NewItem = new Model.WorkLogItem();
Upvotes: 3
Views: 5028
Reputation: 6932
Your ViewModel
must also implement 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...
}
When binding to your ComboBox
, be sure to use Mode=TwoWay
:
<ComboBox ... SelectedItem="{Binding ... Mode=TwoWay}" />
Upvotes: 3
Reputation: 69989
The way that I do this is to set up an empty constructor in my data object that sets all of its properties to their default values. Then when I want to 'reset' a view to all empty fields, I just set my data bound property to a new item:
NewItem = new YourDataType();
This updates all of the data bound control properties as you would expect. Please note that my data type classes all implement the INotifyPropertyChanged
interface and that this method of clearing the UI controls will only work if they do implement it.
Upvotes: 0