XAML 101: Two Way Data Binding

FacebookTwitterGoogle+Share

Source code for this sample on GitHub: https://github.com/billreiss/xamlnative/tree/master/Xaml101/017_TwoWayBinding

In the last couple of posts we looked at getting started with data binding and then some more options available. In all of these cases the data binding was from the source to the target, or the model to the view, but we haven’t looked at sending data the other way through the binding. Let’s look at that now.

Where you would need two way data binding is when you aren’t in read only mode for your view and you want to edit the data. It could be a text box, a check box, a combo box, a selected item in a list, or one of many other ways to provide input. Let’s look at a couple of these. In MainPage.xaml we will have the following, a lot of it we have already seen, and a couple of new controls:

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
    <Grid.RowDefinitions>
        <RowDefinition Height="auto"/>
        <RowDefinition Height="auto"/>
        <RowDefinition Height="auto"/>
        <RowDefinition Height="auto"/>
        <RowDefinition Height="auto"/>
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="auto"/>
        <ColumnDefinition Width="200"/>
    </Grid.ColumnDefinitions>
    <TextBlock Text="Checkbox:"/>
    <TextBlock Grid.Row="1" Text="Checkbox Result:"/>
    <TextBlock Grid.Row="2" Text="TextBox:"/>
    <TextBlock Grid.Row="3" Text="TextBox Result:"/>
    <CheckBox Grid.Row="0" Grid.Column="1" IsChecked="{x:Bind Model.CheckBoxValue,Mode=TwoWay}"/>
    <TextBlock Grid.Row="1" Grid.Column="1" Text="{x:Bind Model.CheckBoxValue, Mode=OneWay}"/>
    <TextBox Grid.Row="2" Grid.Column="1" Text="{x:Bind Model.TextBoxValue, Mode=TwoWay}"/>
    <TextBlock Grid.Row="3" Grid.Column="1" Text="{x:Bind Model.TextBoxValue, Mode=OneWay}"/>
    <Button Grid.Row="4" Content="Submit" Click="{x:Bind Model.ClickHandler}"/>
</Grid>

The CheckBox and TextBox are new, but probably pretty well known and self explanatory. The CheckBox has an IsChecked property, which is a nullable boolean value. Null represents the third state of a checkbox, usually used when a mix of child nodes are true and false. We set the initial value to false, or unchecked. The TextBox has a Text property, which is a string value. Notice the Mode=TwoWay in the bindings. Remember that the mode defaults to OneTime, and so in order to make the data flow back to the model we need to set this to TwoWay.

We also have a couple of TextBlock controls which will show what the current values of the model are. Like in the last example, we have a declaration and instantiation of the MainViewModel object in the MainPage.xaml.cs code behind file:

public sealed partial class MainPage : Page
{

    public MainPage()
    {
        this.InitializeComponent();
    }

    MainViewModel Model = new MainViewModel();

}

And then in the MainViewModel.cs file:

class MainViewModel : INotifyPropertyChanged
{
    bool? checkBoxValue = false;
    string textBoxValue;

    public bool? CheckBoxValue
    {
        get
        {
            return checkBoxValue;
        }

        set
        {
            checkBoxValue = value;
            NotifyPropertyChanged();
        }
    }

    public string TextBoxValue
    {
        get
        {
            return textBoxValue;
        }

        set
        {
            textBoxValue = value;
            NotifyPropertyChanged();
        }
    }

    public MainViewModel()
    {
    }


    public async void ClickHandler(object sender, RoutedEventArgs e)
    {
        var dlg = new Windows.UI.Popups.MessageDialog(string.Format("CheckBox:{0}, TextBox:{1}", CheckBoxValue, TextBoxValue));
        await dlg.ShowAsync();
    }

    public event PropertyChangedEventHandler PropertyChanged;

    private void NotifyPropertyChanged([CallerMemberName] string propertyName = "")
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    } 

}

The ClickHandler method has been updated to show a MessageDialog with the current values. Since the MessageDialog.ShowAsync method is anynchronous, we await the result of this method call. Since we await the result, we need to make the calling method async, which is fine, the Click event  still wires up properly.

If you run this sample, you’ll see something like this:

image

If you click the CheckBox, then you will see the TextBlock representing the CheckBox result change:

image

Now if you enter text into the TextBox, you might think that you should see the changes as you type, but for a TextBox the value doesn’t update until the TextBox loses focus, so you can click anywhere else or on the Submit button, and then you will see the TextBox result field show the current value:

image

and then if you click the submit button, you should see the current values in the model:

image

If you needed the current value of the text in the TextBox as you type, you could wire up the TextChanged event and check what the current value of the Text property is. The assumption is that you normally won’t need that value until you are done typing and click away.

Until next time…