The most common pattern in WPF
is the MVVM
(Model-View-Viewmodel) which is a standard of type MV*
.
This standard fits 3 components. The view (which has a set of controls organized in a certain way), the model (which has the data with logic) and the Viewmodel (which has the information to be presented in the view, as well as the events of the controls, such as button clicks).
In MVVM it is typical that the controls support data-binding
. This only means that certain ownership of the control is linked to a class property. For example the text of a text box can be linked to a property Nome
. Bindings also automatically update the view as long as they notify the view. To notify the view is required, at WPF
, implement the interfaceINotififyPropertyChanged
and invoke the event PropertyChanged
public class Model : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
protected bool SetField<T>(ref T field, T value, [CallerMemberName] string propertyName = null)
{
if (!field.Equals(value))
{
field = value;
OnPropertyChanged(propertyName);
return true;
}
return false;
}
}
The Setfield method is a simple way to invoke the event. It only invokes if the value changes.
Now your Viewsmodels can derive from this class.
public class PessoaViewModel : Model{
private string _nome;
public string Nome{
get{ return _nome; }
set{ SetField(ref _nome, value); }
}
}
As I explained before the commands can also be binded
. Users must implement the interface ICommand
. In order to avoid creating a class for each type of command it is common to create one that runs any Action
, passed in the class builder:
public class DelegatedCommand : ICommand
{
protected readonly Action<object> _action;
protected Predicate<object> _canExecute;
public DelegatedCommand(Action<object> action, Predicate<object> canExecute = null)
{
_action = action;
_canExecute = canExecute;
}
public bool CanExecute(object parameter)
{
return _canExecute?.Invoke(parameter) ?? true;
}
public void Execute(object parameter)
{
_action(parameter);
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
}
Now you can add commands to your Viewmodel. There are several ways to do this, but I’ll show you the one I use:
public class PessoaViewModel : Model{
private ICommand _command;
public ICommand Command{
get{
if(_command != null) return _command;
return _command = new DelegtedCommand((arg) => {
Console.WriteLine("O código do comando vai aqui");
});
}
}
}
Of course commands can change the status of properties if they invoke PropertyChanged
then the interface will be automatically updated.
Finally a very simple view (I omitted some Window attributes):
<Window>
<Window.DataContext>
<local:PessoaViewModel />
</Window.DataContext>
<StackPanel>
<TextBox Text="{Binding Nome}" />
<Button Command="{Binding Command}" />
</Stackpanel>
</Window>
References
What is the MVP and MVVM
Note that in my example I did not implement any Model! Basically my Model is also Viewmodel. This is not desirable if the Template has multiple properties
– Bruno Costa