In my previous blog post I introduced data binding. It worked, but there was no mechanism for updating. Updating comes in two flavors, and these are often confused by folks new to databinding:
- Someone else updates the underlying data; we’d like the display to be updated
- The user updates the data on the display, we’d like the underlying data to be updated
The first case arises because most of the time you are not the only user of your program – other users may be connected to the same data and while you are looking at your data someone else may change it. You want to see that change immediately. The canonical example is this: you work at a bookstore and someone calls and asks whether you have a particular book in stock. You check and say yes, you have one left. While they are deciding whether to purchase it, another employee has sold that book. The quantity-on-hand just dropped from one (plenty of books for your customer) to zero (oops). You really would like to see that change reflected in the UI.
INotifyPropertyChanged
To accomplish this first kind of update, you will make your data class implement INotifyPropertyChanged. Returning to the previous posting, we had an Employee class. We will have that class implement INotifyPropertyChanged. It does so like this,
class Employee : INotifyPropertyChanged { private string name; public string Name { get { return name; } set { name = value; OnPropertyChanged(); } } private string title; public string Title { get { return title; } set { title = value; OnPropertyChanged(); } } public Employee( string name, string title ) { Name = name; Title = title; } public event PropertyChangedEventHandler PropertyChanged; private void OnPropertyChanged( [CallerMemberName] string caller = "" ) { if ( PropertyChanged != null ) { PropertyChanged( this, new PropertyChangedEventArgs( caller ) ); } } }
First, we mark the class to implement the interface. The interface calls for the existence of a single Event: PropertyChanged. We add a helper method that checks to see if anyone has registered with INotifyPropertyChanged (which all the UIElements do) and if it is not null, then it raises the PropertyChanged event passing in the name of the calling property (using the new attribute [CallerMemberName]).
In the setter of each property we call OnPropertyChanged to inform the UI that the property has been updated.
Let’s add a button to the XAML so that we can simulate the property being changed by another user. Here is what our XAML looks like,
<StackPanel Name="xDisplay" Margin="50"> <StackPanel Orientation="Horizontal"> <TextBlock Text="Name:" /> <TextBlock Margin="5,0,0,0" Text="{Binding Name}" /> </StackPanel> <StackPanel Orientation="Horizontal"> <TextBlock Text="Title:" /> <TextBlock Margin="5,0,0,0" Text="{Binding Title}" /> </StackPanel> <Button Content="Change" Click="Button_Click_1" /> </StackPanel>
When we navigate to the page, we’ll create an instance of Employee.
private Employee emp; protected override void OnNavigatedTo(NavigationEventArgs e) { emp = new Employee( "Joe", "QA" ); xDisplay.DataContext = emp; }
When the button is clicked we’ll modify the employee’s name and title,
private void Button_Click_1( object sender, RoutedEventArgs e ) { emp.Name = "Jesse"; emp.Title = "Evangelist"; }
Run the application. It initially comes up with Joe in QA, but click the button and it is changed to Jesse, Evangelist. The change in the display reflects a change to the underlying data.
Letting The User Update The Data – Two Way Binding
That was scenario #1. In scenario #2 we’d like the user to be able to change the display and have that change persisted in the underlying data. To do this, we’ll add a second stack panel, just like the first, except that the name and title will be in TextBoxes instead of TextBlocks. More important, our binding will no longer be one-way, but rather two-way. This is accomplished with the mode attribute. There are three modes in databinding:
- One Time – Set it and it never updates
- One Way – Set it, update for internal changes, but no feedback from user to data
- Two Way – Set it and then allow user to modify updating the underlying data
Clearly it is Two Way that we want now, and you can see this in our modified XAML,
<StackPanel Name="xDisplay" Margin="50"> <StackPanel Orientation="Horizontal"> <TextBlock Text="Name:" /> <TextBlock Margin="5,0,0,0" Text="{Binding Name}" /> </StackPanel> <StackPanel Orientation="Horizontal"> <TextBlock Text="Title:" /> <TextBlock Margin="5,0,0,0" Text="{Binding Title}" /> </StackPanel> <StackPanel Orientation="Horizontal"> <TextBlock Text="Name:" /> <TextBox Margin="5,0,0,0" Text="{Binding Name, Mode=TwoWay}" /> </StackPanel> <StackPanel Orientation="Horizontal"> <TextBlock Text="Title:" /> <TextBox Margin="5,0,0,0" Text="{Binding Title, Mode=TwoWay}" /> </StackPanel> <Button Content="Change" Click="Button_Click_1" /> </StackPanel>
There are no changes to the code to handle the two way binding; the binding mechanism will take care of that for you. Thus, if you run this again, you can modify the name and title in the TextBoxes, and the changes will be immediately reflected in the TextBlocks above. What is happening is that the user is changing the data, that is being stored back into the underlying data and because of INotifyPropertyChanged the UI is being updated to reflect that data.
Cool, eh?
Here’s something else that is cool; this is exactly how it worked in Silverlight, WPF and Windows Phone.
Here is the complete source code.
Hey Jesse!!
Thanks for all your great and concise windows phone related posts!
Believe me its helped me a ton…
Just a quick question… Im doing n webservice call to get my images and then uppon getting them and converting them from base64 i have them in my codebehind… How do i bind these images (without URI) to then listbox?? Is this possible? I have been searching but cant find anything on the topic :/
Thanks in advance
Dawie
Jesse,
The textblock changes when we tab out of the textbox, any way to update the textblock (label) as we type in the textbox ?
Thanks.
I would love to see this example saving the changes to a file in the local folder.
Thank you for the great tutorials.
Write more, thats all I have to say. Literally, it seems as though you relied on
the video to make your point. You clearly know what youre talking about, why waste your intelligence on just posting videos to your blog when you could be giving us something
enlightening to read?
Which video?
I don’t see how adding an extra button to the XAML would actually simulate another user changing the underlying data. To truly simulate that, you’d need a separate app, preferably on a different machine, or VM.
Yes, if you were interested in seeing the data come in from another source. But the button does not change the ui, it changes only the underlying data, yet the ui updates. This demonstrates that INotifyPropertyChanged is working as expected.
Thank you for this great little post, to get an quick overview 🙂