Background
In order to implement async commands in an MVVM app I went through the following tutorials by Stephen Cleary.
https://msdn.microsoft.com/magazine/dn605875 Async Programming : Patterns for Asynchronous MVVM Applications: Data Binding
https://msdn.microsoft.com/en-us/magazine/dn630647.aspx Async Programming : Patterns for Asynchronous MVVM Applications: Commands
Problem
When reimplementing what he proposed step by step I stumbled upon the problem that the PropertyChanged event handler in the command is always null. When running Steves sample code it is not null.
In order to understand this better I started from scratch with implementing the most basic command that one could think of:
public class SimpleCommand : ICommand, INotifyPropertyChanged
{
public bool CanExecute(object parameter)
{
return true;
}
public void Execute(object parameter)
{
// having a break point on the following line
throw new NotImplementedException();
}
public event EventHandler CanExecuteChanged;
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
Note that I have a break point set on the line that throws the NotImplementedException because I just want to see whether PropertyChanged is null or not.
The viewmodel basically just creates this command and the view binds to it via a button.
public class MainViewModel : INotifyPropertyChanged
{
public ICommand SimpleAction { get; set; }
public MainViewModel()
{
SimpleAction = new SimpleCommand();
}
...
}
The window just contains one button to call that command
<Window ...>
<Window.DataContext>
<viewModels:MainViewModel></viewModels:MainViewModel>
</Window.DataContext>
<Grid>
<Button
Command="{Binding SimpleAction}"
Content="Click Me!"></Button>
</Grid>
</Window>
My assumption is that when a command implements INotifyPropertyChanged then the framework listens onto the PropertyChanged event which is obviously wrong.
So how does it work in Steves examples then? There he just implements INotifyPropertyChanged on NotifyTaskCompletion or AsyncCommand and PropertyChanged is not null.
Looking at other SO posts the usual answer in general is that DataContext is not set. Still I don't see how to set this for a command.
Actual Question
How to implement INotifyPropertyChanged properly on a command (based on ICommand) in MVVM (C#)?
The command itself has no subscribers unless you bind to a property of the command itself.
That's what #Stephen Cleary does in his article. He binds to the Execution property of the AsyncCommand<TResult> class. You bind to the SimpleAction property of the MainViewModel class.
So in your sample code, the SimpleCommand object has no subscribers and that's why the event handler returns a null reference.
Related
I am relative new to OOP and C# and wanted to ask what would be the "best practice" to make two classes use Methodes from each other.
Example: I have a "Main Class", this instantiates a Class "UI" which manages the communication to a touch-display and a class "Sensor" which communicates with an external Sensor.
When someone is pushing a button on the Display, an event is triggered in the UI Class. As a reaction, the "ReadSensor" Methode form the Sensor Class needs to be called. (And the other way around, the "SensorDataCallback" needs to write stuff to the Display).
Now in C++ I would have made both Class Objects global, but thats no option in C#.
I tried adding Methodes to the Class which accept a ref to the respective other class instance and store them, but this does not seem like the best aproach. My other way was making both classes static since there is only one Display and one Sensor, but that also can't be the best way I guess.
Sketch
Can anybody give me a hint?
I wouldn't recommend tying two classes so closely to each other, indeed you'll end up with circular references.
Try and keep your classes self contained, so that there remains a definite separation of concerns.
Thus the Sensor class only deals with retrieving sensor data and raising notification of new values (if it is to read values automatically at regular intervals or asynchronously).
Your UI class only deals with the display and reacting to user input.
Your Main class acts as a data handler between the two.
The UI display code notifies the Main class of a user request for information; the Main class handles this and triggers the Sensor class to retrieve a new sensor value.
The Sensor class notifies/passes the new sensor value to the main class; the main class then notifies the UI that a new value is available.
Thus the Sensor does not need to know about the display, not does the display need to know about the sensor.
The above fits the current "best practice" of using MVVM (Model-View-ViewModel) structure for C# programmes with a user interface. In this case your View is the display, the ViewModel is your main class and the Model is your sensor class.
In this arrangement the View class uses databinding to retrieve the sensor value from the ViewModel. The View will raise an event (bound to a Command maybe) on the press of a button that the ViewModel reacts to, triggering it to request for updated data from the sensor. The sensor supplies that data to the ViewModel which when it updates its sensor value property raises a property changed notification that triggers the View to update.
Here's a very basic example of MVVM in a WPF app. I've not included the whole project just the basic classes:
View: (MainWindow.xaml)
<Window x:Class="SimpleWPF.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:SimpleWPF"
mc:Ignorable="d"
Title="MainWindow" Height="204.673" Width="219.626">
<Window.DataContext>
<local:MainViewModel/>
</Window.DataContext>
<Grid>
<TextBox x:Name="textBox" Text="{Binding SensorValue, Mode=OneWay }" HorizontalAlignment="Left" Height="23" Margin="38,47,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120"/>
<Button x:Name="button" Command="{Binding ReadSensorCommand}" Content="Read" HorizontalAlignment="Left" Margin="62,94,0,0" VerticalAlignment="Top" Width="75"/>
</Grid>
ViewModel (MainViewMode.cs) with a helper class:
public class MainViewModel :INotifyPropertyChanged
{
public MainViewModel()
{
ReadSensorCommand = new RelayCommand(new Action<object>(ReadFreshSensorData));
}
private ICommand _ReadSensorCommand;
private int _sensorValue;
private readonly SensorModel _sensor = new SensorModel();
private void ReadFreshSensorData(object o)
{
SensorValue =_sensor.ReadSensor();
}
public int SensorValue
{
get=>_sensorValue;
private set
{
_sensorValue = value;
OnPropertyChanged(nameof(SensorValue));
}
}
public ICommand ReadSensorCommand
{
get => _ReadSensorCommand;
set => _ReadSensorCommand = value;
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
class RelayCommand : ICommand
{
private readonly Action<object> _action;
public RelayCommand(Action<object> action)
{
_action = action;
}
public bool CanExecute(object parameter)
{
return true;
}
public event EventHandler CanExecuteChanged;
public void Execute(object parameter)
{
_action(parameter ?? "");
}
}
Finally the Model (SensorModel.cs)
public class SensorModel
{
private Random _rnd = new Random();
public int ReadSensor()
{
return _rnd.Next(1000);
}
}
Admittedly this only demonstrates a user triggering a read from the sensor, but SensorModel could have an event property on its interface and MainViewModel a handler. SensorModel could then invoke the event to pass a value to MainViewModel which would then update SensorValue from the event handler.
I'm not sure how to make navigation using mvvm. I'm a beginner so I haven't used any framework like mvvm light.
I found good example https://rachel53461.wordpress.com/2011/12/18/navigation-with-mvvm-2/. But it is not exactly what I'm looking for because in my app each view will cover all window. So when I will change page i will have no controls access from the mainview.
So I decided to make one MainViewModel for changing ViewModels (as in Rachel Blog) but each ViewModel should know about MainViewModel to execute change view. So when I create PageViewModel, I pass in constructor MainViewModel with public method, for example, changeview().
Is it a good way of doing this? Or, maybe, there's a better way to achieve this?
The child viewmodels should not know about main viewmodel.
Instead they should raise events with names like Forward or Back and so forth. ChangeView is the only example you give, so we’ll go with that.
We'll have the child viewmodel expose commands that cause the events to be raised. Buttons or MenuItems in the child view's XAML can bind to the commands to let the user invoke them. You can also do that via Click event handlers calling viewmodel methods in the child view code behind, but commands are more "correct", because at the cost of a little more work in the viewmodel, they make life a lot simpler for creators of views.
Main viewmodel handles those events and changes the active page viewmodel accordingly. So instead of child calling _mainVM.ChangeView(), child raises its own ChangeView event, and the main VM’s handler for that event on the child calls its own method this.ChangeView(). Main VM is the organizer VM, so it owns navigation.
It’s a good rule to make code as agnostic as possible about how and where it’s used. This goes for controls and viewmodels. Imagine if the ListBox class required the parent to be some particular class; that would be frustrating, and unnecessary as well. Events help us write useful child classes that don’t need to know or care anything about which parent uses them. Even if reuse isn’t a possibility, this approach helps you write clean, well-separated classes that are easy to write and maintain.
If you need help with the details, provide more code, and we can go through applying this design to your project.
Example
public class MainViewModel : ViewModelBase
{
public MainViewModel()
{
FooViewModel = new FooViewModel();
FooViewModel.Back += (object sender, EventArgs e) => Back();
}
public FooViewModel FooViewModel { get; private set; }
public void Back()
{
// Change selected page property
}
}
public class FooViewModel : ViewModelBase
{
public event EventHandler Back;
private ICommand _backCommand;
public ICommand BackCommand {
get {
if (_backCommand == null)
{
// It has to give us a parameter, but we don't have to use it.
_backCommand = new DelegateCommand(parameter => OnBack());
}
return _backCommand;
}
}
// C#7 version
public void OnBack() => Back?.Invoke(this, EventArgs.Empty);
// C# <= 5
//protected void OnBack()
//{
// var handler = Back;
// if (handler != null)
// {
// handler(this, EventArgs.Empty);
// }
//}
}
// I don't know if you already have a DelegateCommand or RelayCommand class.
// Whatever you call it, if you don't have it, here's a quick and dirty one.
public class DelegateCommand : ICommand
{
public DelegateCommand(Action<object> exec, Func<object, bool> canExec = null)
{
_exec = exec;
_canExec = canExec;
}
Action<object> _exec;
Func<object, bool> _canExec;
public event EventHandler CanExecuteChanged;
public bool CanExecute(object parameter)
{
return _canExec == null || _canExec(parameter);
}
public void Execute(object parameter)
{
if (_exec != null)
{
_exec(parameter);
}
}
}
How to invoke BackCommand from child XAML:
<Button Content="Back" Command="{Binding BackCommand}" />
Can someone explain me why need to use implementation of INotifyPropertyChanged when using binding in wpf?
I can bind properties without implementation of this interface?
For example i have code
public class StudentData : INotifyPropertyChanged
{
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
#endregion
void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
string _firstName = null;
public string StudentFirstName
{
get
{
return _firstName;
}
set
{
_firstName = value;
OnPropertyChanged("StudentFirstName");
}
}
}
And binding in .xaml
<TextBox Text="{Binding Path=StudentFirstName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Grid.Row="1"
Grid.Column="2"
VerticalAlignment="Center" />
this code from .xaml.cs
StudentData _studentData = new StudentData { StudentFirstName = "John", StudentGradePointAverage = 3.5};
public MainWindow()
{
InitializeComponent();
this.DataContext = _studentData;
}
why we need to use INotifyPropertyChanged in this case?
It is not my code.
You need INotifyPropertyChanged if you want a wpf form to be automatically updated when a property changes through code. Also some controllers might want to know if edits have been made in order to enable/disable a save-button, for instance. You also might be displaying the same property on different views; in this case INotifyPropertyChanged helps to immediately update the other view when you edit a property.
If you think that your form behaves well without INotifyPropertyChanged, then you can drop it.
Note that binding works even without INotifyPropertyChanged. See: Why does the binding update without implementing INotifyPropertyChanged?
I would implement the properties like this. In some rare cases it can help to avoid endless circular updates. And it is more efficient by the way.
private string _firstName;
public string StudentFirstName
{
get { return _firstName; }
set
{
if (value != _firstName) {
_firstName = value;
OnPropertyChanged("StudentFirstName");
}
}
}
Starting with C#6.0 (VS 2015), you can implement OnPropertyChanged like this:
private void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
When you bind to a property of StudentData such as the StudentFirstName then the binding class tests to see if the StudentData instance provides the INotifyPropertyChanged interface. If so then it will hook into the PropertyChanged event. When the event fires and it fires because of the StudentFirstName property then it knows it needs to recover the source value again because it has changed. This is how the binding is able to monitor changes in the source and reflect them in the user interface.
If you do not provide the INotifyPropertyChanged interface then the binding has no idea when the source value changes. In which case the user interface will not update when the property is changed. You will only see the initial value that was defined when the binding was first used.
It does need to be implemented in order for binding to work but that doesn't mean you always have to do it yourself. There are other options like Castle Dynamic Proxy (which wraps your classes in a proxy and injects INPC into all virtual properties) and Fody (which adds it to the IL in a post-processing step). It's also possible to implement yourself while at the same time reducing code bloat, as demonstrated in my answer to this question.
I am having trouble with grasping the concept of a ObservableCollection inside MVVM. For start I would like to point out that I am doing this in a Windows 8/Metro App, not WPF or Silverlight.
According to microsoft documentation, this collection has the following usefulness:
"Represents a dynamic data collection that provides notifications when items get added, removed, or when the whole list is refreshed." From what I understand this helps you a lot when binding is involved. On the net I found a lot of simple examples, by creating a ObservableCollection on runtime and then working on it, but I didn't find out what is the proper way of using this collection with a repository.
Let' say I have the following repository interface that is an implementation for a ORM database backend, or a raw ADO.NET implementation
public interface IRepository<T>
{
ObservableCollection<T> GetAll();
void Create();
void Update();
void Delete();
T GetByKey(object key);
}
and a simple ViewModel that use the repository as a model
public class ViewModel
{
private ObservableCollection<Dummy> _obsListDummy;
private RelayCommand _addCommand,_deleteCommand,_updateCommand;
private IRepository<Dummy> _repositoryDummy;
public class ViewModel()
{
_repositoryDummy=Factory.GetRepository<Dummy>();
}
public ObservableCollection<Dummy> ObsListDummy
{
get
{
return _repositoryDummy.GetAll();
}
}
public RelayCommand AddCommand
{
get
{
if (_addCommand == null)
{
_addCommand = new RelayCommand(p => DoAdd();
//DoAdd method shows a popup for input dummy and then closes;
);
}
return _myCommand;
}
}
........
}
My view would be a simple XAML with a grid, also Dummy object has INotifyPropertyChanged implemented.
Right now with this implementation after adding or updating or deleting, the ObservableCollection isn't refreshing, I know I could have put IEnumerable instead, but I dont'see an elegant solution of how would make repository to sync with the ObservableCollection that is in the model, other than subscrbing to CollectionChanged and there you treat all the states, but to it seems that I would repeat myself along with the logic that I do in the repository. And to make matters even worse, let's say I would like to get some push notification from my repository, towards the ObservableCollection.
I hope I was understand about my problem.
Thanks in advance.
You should implement INotifyPropertyChanged on your ViewModel and your ObsListDummy property should inform the ViewModel about changes applied to the collection. So it should look like this:
public class ViewModel: INotifyPropertyChanged
{
// Declare the event
public event PropertyChangedEventHandler PropertyChanged;
// Create the OnPropertyChanged method to raise the event
protected void OnPropertyChanged(string name)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(name));
}
}
private ObservableCollection<Dummy> _dummyCollection;
public ObservableCollection<Dummy> DummyCollection
{
get { return _dummyCollection; }
set
{
// Set the value and then inform the ViewModel about change with OnPropertyChanged
_dummyCollection = value;
OnPropertyChanged("DummyCollection");
}
}
}
This whole INotifyPropertyChanged interface and implementation includes some dirty work like declaring event and creating a helper method to raise the event so I would suggest you to use some libraries for that like MVVM Light.
You should use a member of type ObservableCollection to store your Dummy ViewModels. In your Initialize method you read the dummies from the repository, create Dummy ViewModels and put those in the ObservableCollection. Now your view will get updated, when you use Binding to ObsListDummy (and add / remove from that collection, also note that Binding only works with public properties).
Right now, you just have a new ObservableCollection on each read, no events involved, so your View will never know about a change.
Further your ViewModel shall implement INotifyPropertyChanged.
I'm relatively new to MVVM and I'm trying to understand how INotifyPropertyChanged interface works and how to implement it in my models. The approach that I decided to take was to implement it in each of my Business Object classes. The problem with that approach is that when I bind my View to a property in a Base class the PropertyChanged event in that base class never gets initialized (is null) and therefore the View does not refresh the data for that element when my Model changes. I was able to reproduce the problem with the example below.
I have a Person Base class:
public class Person : INotifyPropertyChanged
{
#region INotifyProperty
public event PropertyChangedEventHandler PropertyChanged;
public void RaisePropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
#endregion
public String Name
{
get
{
return _name;
}
set
{
_name = value;
RaisePropertyChanged("Name");
}
}
private String _name;
}
And I have an Employee class inheriting from my Person Base class:
public class Employee : Person,INotifyPropertyChanged
{
#region INotifyProperty
public event PropertyChangedEventHandler PropertyChanged;
public void RaisePropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
#endregion
public String EmployeeID
{
get
{
return _employeeId;
}
set
{
_employeeId = value;
RaisePropertyChanged("EmployeeID");
}
}
private String _employeeId;
}
Here my View Model:
public class ViewModel : ViewModelBase<ViewModel>
{
private Employee _employee;
public ViewModel()
{
ChangeModelCommand = new RelayCommand(param=>this.ChangeModel() , param=>this.CanChangeModel);
Employee = new Employee()
{
Name = "BOB",EmployeeID = "1234"
};
}
public ICommand ChangeModelCommand { get; set; }
public Employee Employee
{
get
{
return _employee;
}
set
{
this._employee = value;
NotifyPropertyChanged(m=>m.Employee);
}
}
public void ChangeModel()
{
MessageBox.Show("CHANGING MODEL");
this.Employee.Name = "MIKE";
this.Employee.EmployeeID = "5678";
}
public bool CanChangeModel
{
get{ return true;}
}
}
And finally my View:
<Window.Resources>
<MVVM_NotificationTest:ViewModel x:Key="Model"></MVVM_NotificationTest:ViewModel>
</Window.Resources>
<Grid DataContext="{StaticResource Model}">
<StackPanel>
<Label Content="Employee Name"/>
<TextBox Text="{Binding Path=Employee.Name,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"/>
<Label Content="Employee ID"/>
<TextBox Text="{Binding Path=Employee.EmployeeID,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"/>
<Button Content="Change Model" Height="30" Width="100" Margin="5" Command="{Binding Path=ChangeModelCommand}"/>
</StackPanel>
</Grid>
In this example I initialize my Employee VM Property in the VM constructor and then I have a command to modify the EmployeeID (from Employee class) and Name (from Person Class). However, the only UI element in the View that gets updated is the EmployeeID and not the Name (I expected Bob to update to Mike). While debugging I found that PropertyChanged event was always null in my base class (Person). I also noticed that when I remove the whole #INotifyProperty region from my Employee class everything works fine since it is using the Base Type event and methods.The problem I have with that is that all my current model classes implement INotifyPropertyChanged explicitly. They all define a PropertyChanged event and implement the RaisePropertyChanged method, which obviously will impact my bindings in my MVVM application. Lastly, I want to clarify that I do not want wrap my Model properties in my ViewModel and rely on the VM INPC mechanism. I would like to use my Model INPC implementation already in place whithout having to conditionally remove the INPC implementations depending on whether I am inheriting or not from a base type.
In summary, I would like to know what's the best way to implement the INPC in my deeply hierarchical model so that inheritance doesn't break the PropertyEvent propagation as we saw in this example and so my independent classes can be self sufficient as well. Any ideas or suggestions will be greatly appreciated :)
Simply make RaisePropertyChanged protected and move it into the base class. Currently you will have a lot of duplication that is not necessary.
Something like this:
protected virtual void RaisePropertyChanged(string propertyName);
Many MVVM frameworks provide this for you. For example PRISM has a NotificationObject ViewModel base class.
You should only implement INPC once, you can use the same raising method in the subclasses.
I would also change the raise property changed method to use reflection instead of passing in hard coded strings. I see you did it in your view model but not in your models (where most of the errors tend to occur).