How To: DataBinding Of Property From Another Class In WPF

In this article I will show you how to do data binding in Xaml, and demonstrate how you can set the textBlock text property to another class property in WPF. We will do this by firing events when we mouse over a control. Whichever control we hover on, will be the value of our textblock will reflect. Lets dig in. And this is how we plan on doing it. Lets start with the Main_ViewModel :

 public class Main_ViewModel
 {
 public ObservableValue New_Value { get; }
 public Main_ViewModel()
 {
 New_Value = new ObservableValue();
 }
 }

The main view model constructor returns a new class of ObservableValue of the value stored therein : private string TextBlock_Value; of this class. This is done through its GetSetter property :

 public string TextBlock_Text
 {
 get
 {
 if (string.IsNullOrEmpty(TextBlock_Value))
 return "Nothing Detected";
 return TextBlock_Value;
 }
 set
 {
 TextBlock_Value = value;
 OnPropertyChanged();
 }
 }

In the ObservableValue class :

 public class ObservableValue : INotifyPropertyChanged
 {
 private string TextBlock_Value;
 public string TextBlock_Text
 {
 get
 {
 if (string.IsNullOrEmpty(TextBlock_Value))
 return "Nothing Detected";
 return TextBlock_Value;
 }
 set
 {
 TextBlock_Value = value;
 OnPropertyChanged();
 }
 }
 public event PropertyChangedEventHandler PropertyChanged;
 protected void OnPropertyChanged([CallerMemberName] string new_Value = null)
 {
 PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(new_Value));
 }
 }

Notice that we also have a public event PropertyChanged — (Pretty much its a delegate to raise an event which helps with passing the method of the calling code when a component value of the INotifyPropertyChanged has been changed, thus raises the event therein) fires of the below method :

 protected void OnPropertyChanged([CallerMemberName] string new_Value = null)
 {
 PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(new_Value));
 }

Quickly moving to the Main Xaml.cs file. I have declared a field : private Main_ViewModel main_ViewModel = new Main_ViewModel();
And in the constructor I have :

 public Window1()
 {
 InitializeComponent();
 DataContext = main_ViewModel;
 Task Begin = new Task(() => Set_Default_Values());
 Begin.Start();
 }

Notice that I’ve added my DataContext to equal that of my main_ViewModel which is essentially our main_ViewModel => MainViewModel. Next, (I don’t know why), but I update the default value of the textBlock Control by-way of a new task. I just wasn’t following the guidelines of the MVVM here, but it doesn’t really matter as this is another way of updating your UI appropriately, but externally to using a Model. So let me explain what is happening here.

Our Set_Default_Values() method is what first sets the textBlock Text property :

 private void Set_Default_Values()
 {
 myTextBlock.Dispatcher.Invoke(new Delegate_Callback_To(UpdateUI_With_NewItem), new string[] { "Nothing Detected" });
 }

Because the Task is running on a non UI thread, you will need to call Dispatcher.Invoke() to first invoke the control by passing our : UpdateUI_With_NewItemmethod to our Delegate. : public delegate void Delegate_Callback_To(string str_Value);.

Note that this Delegate takes a string value; for type safety, I’ve used a string and not a base class object, but you can use whatever object you want for whatever object you are passing in.

As you can see, I am passing in the value of “Nothing Detected” to our delegate which will pass along this string from the Delegate Delegate_Callback_To to the UpdateUI_With_NewItemmethod in the following code : myTextBlock.Dispatcher.Invoke(new Delegate_Callback_To(UpdateUI_With_NewItem), new string[] { "Nothing Detected" });

The UpdateUI_With_NewItem is the method that is used in this instance to update the value of our textBlock :

 public void UpdateUI_With_NewItem(string item_Value)
 {
 myTextBlock.Text = item_Value;
 }

You should note, that at this point, this has nothing to do with binding, and I am just showing you an alternative safe-way to update your UI without the MVVM pattern, which I would prefer you to follow.

For the sake of pulling it out, and breaking something, I just left it in there, as its also worth knowing how else you can update your UI. No matter what you are doing with your UI. You should never change values of your UI, or allow worker methods to run on your UI thread, and always follow either of these principles in this example when updating your UI.

Getting back on track with the MVVM and bindings here… Sorry for the detour but I’d prefer you know; and prefer to give this example to you as I’ve wrote it instead of pulling something out and risk posting a broken example, and besides it’s also educational for you to understand how to do this.

And before I continue, I would also like you to look up everything I’ve highlighted with inline code and italic with the exception of custom code on the MSDN website. Thus, this will help you to understand how it all works when you have tested this example.

Next I added these MouseMove events to our main yournamed.xaml.cs file :

 private void T0_MouseMove(object sender, MouseEventArgs e)
 {
 main_ViewModel.New_Value.TextBlock_Text = textBox0.Text;
 }

 private void T1_MouseMove(object sender, MouseEventArgs e)
 {
 main_ViewModel.New_Value.TextBlock_Text = textBox1.Text;
 }

 private void T2_MouseMove(object sender, MouseEventArgs e)
 {
 main_ViewModel.New_Value.TextBlock_Text = textBox2.Text;
 }

These events use the Main_ViewModel which depends on the ObservableValue to update the text property of the textBlock. Right, so far; I’ve covered all the classes and explained how it works. You should also note that you will need the following using directives :

using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;

Here is my Xaml :

<Window xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit"
 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:WPFTestApp" mc:Ignorable="d"
 x:Class="WPFTestApp.Window1" Title="Window1" x:Name="MyWindow1">
 <Window.DataContext>
 <local:Main_ViewModel/>
 </Window.DataContext>


 <ScrollViewer x:Name="ScrollView_Main" VerticalScrollBarVisibility="Visible" HorizontalScrollBarVisibility="Visible">
 <Grid x:Name="MyGrid" Width="Auto" ShowGridLines="false">
 <Button x:Name="button" Content="Button" HorizontalAlignment="Left" Margin="365,455,0,0" VerticalAlignment="Top" Width="75"/>
 <TextBlock x:Name="myTextBlock" HorizontalAlignment="Left" Margin="215,409,0,0" TextWrapping="Wrap"
 Text="{Binding New_Value.TextBlock_Text, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" VerticalAlignment="Top"/>
 <TextBox x:Name="textBox0" HorizontalAlignment="Left" Height="23" Margin="35,310,0,0" TextWrapping="Wrap" Text="Hello" VerticalAlignment="Top" Width="120" MouseMove="T0_MouseMove"/>
 <TextBox x:Name="textBox1" HorizontalAlignment="Left" Height="23" Margin="180,310,0,0" TextWrapping="Wrap" Text="My" VerticalAlignment="Top" Width="120" MouseMove="T1_MouseMove"/>
 <TextBox x:Name="textBox2" HorizontalAlignment="Left" Height="23" Margin="320,310,-21,0" TextWrapping="Wrap" Text="Wizzard" VerticalAlignment="Top" Width="120" MouseMove="T2_MouseMove"/>
 </Grid>
 </ScrollViewer>
</Window>

Sorry I didn’t do anything fancy here with custom templating the Xaml etc. However, the important parts to note here is what I have added in the way of bindings to actually make this work. And they are :

  • DataContext which we also set in our Codebehind file. (Not required in the Xaml code.)
  • Binding : Which point to the sub properties/methods of whatever your Model consists of. Ie in our case : Text="{Binding New_Value.TextBlock_Text, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"

Note on the last bullet that the binding starts with the property, New_Value : public ObservableValue New_Value { get; } of our Main Main_ViewModel.

I’ve also set the mode as TwoWay binding, and importantly added : UpdateSourceTrigger=PropertyChanged to this binding to make it work. Lastly take note of the MouseMove events added in each of the textbox controls in the Xaml file. Ie :

<TextBox x:Name="textBox0" HorizontalAlignment="Left" Height="23" Margin="35,310,0,0" TextWrapping="Wrap" Text="Hello" VerticalAlignment="Top" Width="120" MouseMove="T0_MouseMove"/>

Please remember, I will be away for some time as I am not a hobbyist programmer. I am one of which who is contracted out for hire, so it may be a while before I come back to answer any questions or comments on this post.

Any questions you have will have to be answered by one of the other contributors in the comment section, that includes any corrections you may need help altering. Once I return, I will try to help answer any questions you may have.

By the time you finish following the instructions, you should have something that looks like the full .cs file as follows :

using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;

namespace WPFTestApp
{
 public partial class Window1 : Window
 {
 private Main_ViewModel main_ViewModel = new Main_ViewModel();
 public Window1()
 {
 InitializeComponent();
 DataContext = main_ViewModel;
 Task Begin = new Task(() => Set_Default_Values());
 Begin.Start();
 }

 public delegate void Delegate_Callback_To(string str_Value);

 public void UpdateUI_With_NewItem(string item_Value)
 {
 myTextBlock.Text = item_Value;
 }

 private void Set_Default_Values()
 {
 myTextBlock.Dispatcher.Invoke(new Delegate_Callback_To(UpdateUI_With_NewItem), new string[] { "Nothing Detected" });
 }
 private void T0_MouseMove(object sender, MouseEventArgs e)
 {
 main_ViewModel.New_Value.TextBlock_Text = textBox0.Text;
 }

 private void T1_MouseMove(object sender, MouseEventArgs e)
 {
 main_ViewModel.New_Value.TextBlock_Text = textBox1.Text;
 }

 private void T2_MouseMove(object sender, MouseEventArgs e)
 {
 main_ViewModel.New_Value.TextBlock_Text = textBox2.Text;
 }
 }
 public class ObservableValue : INotifyPropertyChanged
 {
 private string TextBlock_Value;
 public string TextBlock_Text
 {
 get
 {
 if (string.IsNullOrEmpty(TextBlock_Value))
 return "Nothing Detected";
 return TextBlock_Value;
 }
 set
 {
 TextBlock_Value = value;
 OnPropertyChanged();
 }
 }
 public event PropertyChangedEventHandler PropertyChanged;
 protected void OnPropertyChanged([CallerMemberName] string new_Value = null)
 {
 PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(new_Value));
 }
 }
 public class Main_ViewModel
 {
 public ObservableValue New_Value { get; }
 public Main_ViewModel()
 {
 New_Value = new ObservableValue();
 }
 }
}

As an aside note; I’d advise breaking out of nesting classes in one cs file as I have done in this example, and create a hierarchy folder structure for your models, business logic, etc and separate your file structure that way. – Learn to read the code by debugging it by following this debugging tutorial, and also take note of the quote below :

Beware of bugs in the above code; I have only proved it correct, not tried it.” ~ Donald E. Knuth

Hope you liked the tutorial and happy programming.