Programmatic Binding to Presentation Controls in C#

Posted in software by Christopher R. Wirz on Tue Jun 30 2015



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.

Note: System.Runtime.CompilerServices must be used for parameter attributes such as CallerMemberName.

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.