Reputation: 4381
Following MVVM architecture, we have a view with 2 DataGrids
whose data are related and view-model having ObservableCollection<Model>
.
Model have boolean property, based on which is one of the grid enabled/disabled. Everything works well and when I change the selected Model
, the grid becames unusable. However, when I change the property, the Notify
of the customer property IsSelectedModelChecked
is not invoked (When I check/uncheck the checkbox in 1st grid, I need to invoke Notify
over the property IsSelectedModelChecked
).
Q: How am I able to invoke property change on Model's property change?
I've checked several questions, but none of them answered mine. I'd like to provide some ideas from top of my head, but I don't have a clue. Thanks
<unnecessary code ommited>
XAML:
<DataGrid
ItemsSource="{Binding Models}"
SelectedItem="{Binding SelectedModel}">
<DataGrid.Columns>
<DataGridTextColumn Header="Name"
Binding="{Binding Name}"/>
<DataGridCheckBoxColumn Header="Check"
Binding="{Binding IsChecked, UpdateSourceTrigger=PropertyChanged}">
</DataGrid.Columns>
</DataGrid>
<DataGrid
IsEnabled="{Binding IsSelectedModelChecked}"/>
Model:
public class Model : Microsoft.VisualStudio.PlatformUI.ObservableObject
{
private string mName = @"<Name>";
public string Name
{
get { return mName; }
set { SetProperty(ref mName, value); }
}
private bool mIsChecked = false;
public bool IsChecked
{
get { return mIsChecked; }
set { SetProperty(ref mIsChecked, value); }
}
}
View-Model:
public class ViewModel : Microsoft.VisualStudio.PlatformUI.ObservableObject
{
private Model mSelectedModel;
public Model SelectedModel
{
get { return mSelectedModel; }
set
{
SetProperty(ref mSelectedModel, value);
NotifyPropertyChanged(nameof(IsSelectedModelChecked));
}
}
private ObservableCollection<Model> mModels = new ObservableCollection<Model>();
public ObservableCollection<Model> Models
{
get { return mModels; }
set { SetProperty(ref mModels, value); }
}
public bool IsSelectedModelChecked => SelectedModel?.IsChecked ?? false;
}
Upvotes: 0
Views: 565
Reputation: 4381
This is an extension to Haukinger's answer. He mentions issue with memory leak, that can occur when the ViewModel instance will be destroyed, but the model will exist and the handler will be still attached to the events.
In such case, WPF has implemented something called Weak Event Pattern, which allows to handle such situation. For the property change, there is existing PropertyChangedEventManager that implements such Weak Event Pattern. The code should be written as:
public Model SelectedModel
{
get { return mSelectedModel; }
set
{
if (mSelectedModel != null)
PropertyChangedEventManager.RemoveHandler(mSelectedModel, OnSelectedModelPropertyChanged, "");
SetProperty(ref mSelectedModel, value);
if (mSelectedModel != null)
PropertyChangedEventManager.AddHandler(mSelectedModel, OnSelectedModelPropertyChanged, "");
NotifyPropertyChanged(nameof(IsSelectedModelChecked));
}
}
private void OnSelectedModelPropertyChanged( object sender, PropertyChangedEventArgs args)
{
if (args.PropertyName == nameof(Model.IsChecked))
NotifyPropertyChanged(nameof(IsSelectedModelChecked));
}
Upvotes: 0
Reputation: 10883
You have to listen for your SelectedModel
's PropertyChanged
event.
I.e.
public Model SelectedModel
{
get { return mSelectedModel; }
set
{
if (mSelectedModel != null)
mSelectedModel.PropertyChanged -= OnSelectedModelPropertyChanged;
SetProperty(ref mSelectedModel, value);
if (mSelectedModel != null)
mSelectedModel.PropertyChanged += OnSelectedModelPropertyChanged;
NotifyPropertyChanged(nameof(IsSelectedModelChecked));
}
}
private void OnSelectedModelPropertyChanged( object sender, PropertyChangedEventArgs args )
{
if (args.PropertyName == nameof(Model.IsChecked))
NotifyPropertyChanged(nameof(IsSelectedModelChecked));
}
Also, you will want to take care about leaking the view model instance if your model instance lives longer than the view model.
Upvotes: 1