Windows Presentation Foundation (WPF) offers many advances over WinForms. One of the most important features is data binding. This is a concept in the Model View ViewModel (MVVM) design patten that separates the responsibility of User Interface (UI) / View logic with Business / ViewModel logic.
Programmatic binding offers a slight advantage over XAML in that it will check the property names at compile time. With XAML, the binding path property names are evaluated at run time.
First, being with a ViewModel - or a ViewModelBase.
public abstract class ViewModelBase : DependencyObject, INotifyPropertyChanged
{
private string _message;
/// <summary>
/// Gets or sets the message.
/// </summary>
/// <value>
/// The message.
/// </value>
public string Message
{
get { return _message; }
set { SetField(ref _message, value); }
}
public event PropertyChangedEventHandler PropertyChanged;
public virtual void RaisePropertyChanged(string propertyName = null)
{
OnPropertyChanged(propertyName);
}
protected virtual void OnPropertyChanged(string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
protected bool SetField<T>(ref T field, T value, [CallerMemberName] string propertyName = null)
{
if (!EqualityComparer<T>.Default.Equals(field, value))
{
field = value;
OnPropertyChanged(propertyName);
return true;
}
return false;
}
}
Make sure to identify the MainGrid in the .xaml portion of the UserControl. For this example, we will define a MessageTextBox as well.
<UserControl x:Class="DemonstrationApp.UserControlView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:DemonstrationApp"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid x:Name="MainGrid" Margin="5">
<TextBox x:Name="MessageTextBox">
</TextBox>
</Grid>
</UserControl>
Next, in the xaml.cs file, set the view model and hook up the binding.
/// <summary>
/// Interaction logic for UserControlView.xaml
/// </summary>
public partial class UserControlView : UserControl
{
/// <summary>
/// The string for the ViewModel resource key
/// </summary>
private static readonly string ViewModelKey = "ViewModelKey";
/// <summary>
/// Gets or sets the view model.
/// </summary>
/// <value>
/// The view model.
/// </value>
public ViewModelBase ViewModel
{
get { return (ViewModelBase) Resources[ViewModelKey]; }
set
{
if (value != null && Resources != null)
{
Resources[ViewModelKey] = value;
MainGrid.DataContext = ViewModel;
}
}
}
public UserControlView()
{
InitializeComponent();
ViewModel = new ViewModelBase();
// Set the binding
BindingOperations.SetBinding(MessageTextBox,
TextBox.TextProperty,
new Binding(nameof(ViewModel.Message))
{
Source = ViewModel,
Path = new PropertyPath(nameof(ViewModel.Message)),
Mode = BindingMode.TwoWay,
UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged
});
}
}
If you put a break point in the SetField method of the ViewModelBase, you will see binding to the Message property.