×
Namespaces

Variants
Actions
(Difference between revisions)

Data Binding to controls on Windows Phone

From Nokia Developer Wiki
Jump to: navigation, search
chintandave_er (Talk | contribs)
(Chintandave er -)
hamishwillee (Talk | contribs)
m (Hamishwillee - Minor typo)
 
(13 intermediate revisions by 5 users not shown)
Line 1: Line 1:
[[Category:Windows Phone]][[Category:Code Examples]]
+
[[Category:Files/Data on Windows Phone]][[Category:UI on Windows Phone]][[Category:Windows Phone 7.5]][[Category:XAML]][[Category:Code Examples]][[Category:Windows Phone 8]]
{{Abstract|This article explains how to bind data to your windows phone application. Article shows how to bind data
+
{{Abstract|This article explains how bind data objects in code to objects declared in your Windows Phone app's XAML UI.}}
in XAML files and later on also explains how to update data in UI components using INotifyPropertyChanged interface class.
+
{{SeeAlso|
 +
* [http://msdn.microsoft.com/en-us/library/windows/apps/xaml/hh758320.aspx Data binding overview] (WP Dev Center)
 +
* [http://msdn.microsoft.com/en-us/library/windows/apps/xaml/hh464965.aspx Quickstart: Data binding to controls]  (WP Dev Center)
 +
* [http://msdn.microsoft.com/en-us/magazine/hh852595.aspx Windows Phone Data Binding] (MSDN Magazine)
 
}}
 
}}
 
{{ArticleMetaData <!-- v1.2 -->
 
{{ArticleMetaData <!-- v1.2 -->
 
|sourcecode= [[Media:DataBindingEx.zip]]
 
|sourcecode= [[Media:DataBindingEx.zip]]
 
|installfile= <!-- Link to installation file (e.g. [[Media:The Installation File.sis]]) -->
 
|installfile= <!-- Link to installation file (e.g. [[Media:The Installation File.sis]]) -->
|devices= Lumia 800,710
+
|devices= Lumia 800,710, 920
|sdk= Windows Phone 7.1
+
|sdk= Windows Phone 7.1, Windows Phone 8.0
|platform= Windows Phone 7.5 (mango)
+
|devicecompatability= <!-- Compatible devices e.g.: All* (must have internal GPS) -->
+
 
|dependencies= <!-- Any other/external dependencies e.g.: Google Maps Api v1.0 -->
 
|dependencies= <!-- Any other/external dependencies e.g.: Google Maps Api v1.0 -->
 
|signing= <!-- Signing requirements - empty or one of: Self-Signed, DevCert, Manufacturer -->
 
|signing= <!-- Signing requirements - empty or one of: Self-Signed, DevCert, Manufacturer -->
 
|capabilities= <!-- Capabilities required by the article/code example (e.g. Location, NetworkServices. -->
 
|capabilities= <!-- Capabilities required by the article/code example (e.g. Location, NetworkServices. -->
|keywords= C# Properties, [http://msdn.microsoft.com/en-us/library/system.componentmodel.inotifypropertychanged%28v=vs.95%29.aspx INotifyPropertyChanged]
 
 
|language= <!-- Language category code for non-English topics - e.g. Lang-Chinese -->
 
|language= <!-- Language category code for non-English topics - e.g. Lang-Chinese -->
 
|translated-by= <!-- [[User:XXXX]] -->
 
|translated-by= <!-- [[User:XXXX]] -->
Line 27: Line 27:
  
 
== Introduction ==
 
== Introduction ==
Each and every application of windows phone contains some sort 6f data and its very important to link those data to the UI elements and their attributes. Data binding is one of the most important development techniques that is used to provide user with visual representation of the data. It connects the underlying data source with the user interface and enables data
+
Windows Phone apps typically define their UI declaratively using XAML (in Expression Blend). While some UI component values may be hardcoded in XAML, many will be provided by data sources (objects, databases, XML feeds). Data binding is the technique which provides the connection between the XAML components and their values as defined in code.
manipulation and navigation.
+
  
== Getting Started ==
+
{{Anchor|BindingMode}}There are a number of different binding modes, as defined in the [http://msdn.microsoft.com/en-us/library/system.windows.data.bindingmode.aspx BindingMode] enumeration:
To understand binding lets create an example application for Windows Phone 7.1 O/S and add a new class to it. New class is the model class which will contain the data properties, and
+
* {{Icode|TwoWay}} - changes to the UI or model automatically update the other. This is used for editable forms or other interactive scenarios.
will bind those data properties to UI elements in XAML file without any cs code.
+
* {{Icode|OneWay}} - updates the UI when the model changes. This is appropriate for read-only controls populated from data.
 +
* {{Icode|OneTime}} - updates the UI when the application starts or when the data context changes. This is used when the source data is static/does not change.
 +
* {{Icode|OneWayToSource}} - changes to the UI update the model
 +
* ''Default'' - uses the default mode for the particular binding target (UI control). This differs based on the control.  
  
<code csharp>
 
namespace DataBindingEx
 
{
 
    public class PhoneModel
 
    {
 
        public string manufacturer { get; set; }
 
        public string model { get; set; }
 
        public string software { get; set; }
 
 
    }
 
}
 
</code>
 
  
PhoneModel.cs contains all the properties you want to show in your UI form, for example at present we have three textbox and they will show all the three properties declared in the PhoneModel class.
+
This code example shows how bind {{Icode|TextBox}} controls in XAML to a source object defined in the C# file. It covers {{Icode|OneTime}}, {{Icode|OneWay}} and {{Icode|TwoWay}} modes. For the modes where the source (model) updates the UI (target) it also shows how to use the [http://msdn.microsoft.com/en-us/library/system.componentmodel.inotifypropertychanged%28v&#61;vs.95%29.aspx INotifyPropertyChanged] interface class to ensure that the UI is updated whenever the underlying code changes.
  
== Creating the UI ==
+
The associated example creates three text boxes in XAML, and uses binding to update their values with information from C# objects.
Simple Windows phone page which consist of three textbox
+
{{Anchor|Figure1}}
 +
[[File:DataBinding wp one.png|frame|none|Figure 1: Data Binding in Windows Phone|400x600px]]
 +
 
 +
== Creating the XAML UI ==
 +
First we create a simple Windows Phone page which contains a title panel followed by a content panel ({{Icode|Grid}}) containing three {{Icode|TextBox}} - which will display manufacturer, software and model text. Note that the content {{Icode|Grid}} is named {{Icode|ContentPanel}}, and we will later use this name to bind to the XAML from the C# code (and similarly the {{Icode|Name}}s of each of the {{Icode|TextBox}}es).
  
 
<code xml>
 
<code xml>
    <!--LayoutRoot is the root grid where all page content is placed-->
+
<!--LayoutRoot is the root grid where all page content is placed-->
    <Grid x:Name="LayoutRoot" Background="Transparent">
+
<Grid x:Name="LayoutRoot" Background="Transparent">
        <Grid.RowDefinitions>
+
    <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
+
        <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
+
        <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
+
    </Grid.RowDefinitions>
  
        <!--TitlePanel contains the name of the application and page title-->
+
    <!--TitlePanel contains the name of the application and page title-->
        <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">
+
    <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">
            <TextBlock x:Name="ApplicationTitle" Text="MY APPLICATION" Style="{StaticResource PhoneTextNormalStyle}"/>
+
        <TextBlock x:Name="ApplicationTitle" Text="MY APPLICATION" Style="{StaticResource PhoneTextNormalStyle}"/>
            <TextBlock x:Name="PageTitle" Text="DataBindingExample" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
+
        <TextBlock x:Name="PageTitle" Text="DataBindingExample" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
        </StackPanel>
+
    </StackPanel>
  
        <!--ContentPanel - place additional content here-->
+
    <!--ContentPanel - place additional content here-->
        <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
+
    <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
            <TextBox Height="70" HorizontalAlignment="Left" Margin="0,130,0,0" Name="manufacturerBox" Text="manufacturer" VerticalAlignment="Top" Width="450" />
+
        <TextBox Height="70" HorizontalAlignment="Left" Margin="0,130,0,0" Name="manufacturerBox" Text="manufacturer" VerticalAlignment="Top" Width="450" />
            <TextBox Height="72" HorizontalAlignment="Left" Margin="0,206,0,0" Name="modelBox" Text="model" VerticalAlignment="Top" Width="450" />
+
        <TextBox Height="72" HorizontalAlignment="Left" Margin="0,206,0,0" Name="modelBox" Text="model" VerticalAlignment="Top" Width="450" />
            <TextBox Height="72" HorizontalAlignment="Left" Margin="6,284,0,0" Name="softwareBox" Text="software" VerticalAlignment="Top" Width="450" />
+
        <TextBox Height="72" HorizontalAlignment="Left" Margin="6,284,0,0" Name="softwareBox" Text="software" VerticalAlignment="Top" Width="450" />
        </Grid>
+
 
     </Grid>
 
     </Grid>
 +
</Grid>
 +
</code>
  
</code>
+
The above XAML code contains hard-coded {{Icode|Text}} property values for the manufacturer, model and software. To bind the controls to data we first need to update the required properties with the {{Icode|{Binding} }} keyword. The keyword allows us to specify the name of the property we want to bind to, and the binding [[#BindingMode|mode]] (ie whether changes to the UI will propagate to the underlying object and visa versa). Both of these two properties are optional: if you just specify {{Icode|{Binding} }} then the bound object's {{Icode|ToString()}} method will be called to get the property value and the binding will be the default for the target object..
  
== Lets Bind Now ==
+
In this example we specify the particular properties of the bound object to use for the Text (ie the {{Icode|manufacturer}} property of the bound object will be used for the text value of the {{Icode|manufacturerBox}} property). We also specify the mode as ''OneTime'' so that the UI is updated from the model on page load (only).
The above XAML code contains hard-coded data values. To bind the properties first we need to identify the attribute of the UI element which needs to be binded,
+
{{Tip|It is always best to specify the mode you want to use explicitly as this will often result in better performance. <br />
then we need to use the keyword Binding in curly braces and need to specify the name of the property to which we need to bind, e.g. textbox text attribute
+
If we omitted the mode the code would still "work" - the default mode of the {{Icode|TextBox}} is ''TwoWay''. But without implementing {{Icode|INotifyPropertyChanged}} the result would be a one time update of the TextBox's content from code. Input into the {{Icode|TextBox}} will still be stored in the bound property though. }}
we will bind with the manufacturer property of PhoneModel.cs . Now the updated XAML code looks like:
+
  
 +
The updated XAML code looks like:
 
<code xml>
 
<code xml>
 
  <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
 
  <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
       <TextBox Height="70" HorizontalAlignment="Left" Margin="0,130,0,0" Name="manufacturerBox" Text="{Binding manufacturer}" VerticalAlignment="Top" Width="450" />
+
       <TextBox Height="70" HorizontalAlignment="Left" Margin="0,130,0,0" Name="manufacturerBox" Text="{Binding manufacturer,Mode=OneTime}" VerticalAlignment="Top" Width="450" />
       <TextBox Height="72" HorizontalAlignment="Left" Margin="0,206,0,0" Name="modelBox" Text="{Binding model}" VerticalAlignment="Top" Width="450" />
+
       <TextBox Height="72" HorizontalAlignment="Left" Margin="0,206,0,0" Name="modelBox" Text="{Binding model,Mode=OneTime}" VerticalAlignment="Top" Width="450" />
       <TextBox Height="72" HorizontalAlignment="Left" Margin="6,284,0,0" Name="softwareBox" Text="{Binding software}" VerticalAlignment="Top" Width="450" />
+
       <TextBox Height="72" HorizontalAlignment="Left" Margin="6,284,0,0" Name="softwareBox" Text="{Binding software,Mode=OneTime}" VerticalAlignment="Top" Width="450" />
 
</Grid>
 
</Grid>
 
</code>
 
</code>
  
To identify the changes please observe the text attribute of any of the TextBox in the Grid, the attribute now have binding with the manufacturer property of PhoneModel class.
 
  
Still its not clear how the XAML knows which object and its property it needs to bind, i mean to say which class the XAML should look for properties mention in the  
+
At this point we still haven't defined the data source (though we know from the XAML it has properties {{Icode|manufacturer}}, {{Icode|model}} and {{Icode|software}}) and bound it to the XAML.  This is done in the C# code, which we define in the following sections.
text attribute of the textbox.
+
  
To make that happen we will use something known as DataContext. DataContext is the object which contains the bindable property. So we need to initialize our phoneModel class
+
== Create and bind the data source ==
object and set it as our DataContext and then rest all will be taken care by the framework.
+
  
One can set the DataContext when page loads. So in MainPage.xaml.cs add an handler to page load event when page Initialization completes, inside that handler initialize PhoneModel
+
Next we create '''PhoneModel.cs''', and define our {{Icode|PhoneModel}} class. Note how the class has [http://msdn.microsoft.com/en-us/library/x9fsa0sw%28v=vs.80%29.aspx C# properties] that match the bound properties in our XAML.
class with some propeties and set PhoneModel object on DataContext. cs code below will help us to understand this :
+
<code csharp>
 +
namespace DataBindingEx
 +
{
 +
    public class PhoneModel
 +
    {
 +
        public string manufacturer { get; set; }
 +
        public string model { get; set; }
 +
        public string software { get; set; }
 +
 +
    }
 +
}
 +
</code>
 +
 
 +
The next step is to create an instance of the {{Icode|PhoneModel}} and bind it to the XAML, which we do using the [http://msdn.microsoft.com/en-us/library/system.windows.frameworkelement.datacontext(v=vs.95).aspx DataContext] property. The best place to perform the binding is when page initialisation completes, in the {{Icode|MainPage_Loaded()}} event handler as shown below.
  
 
<code csharp>
 
<code csharp>
Line 139: Line 144:
 
</code>
 
</code>
  
To check what has happened we can now deploy the application on emulator and we can see the properties being binded on the TextBox attributes.
+
The interesting part of the code is the {{Icode|setDataContext()}} method:
 +
<code csharp>
 +
private void setDataContext()
 +
    {
 +
    ContentPanel.DataContext = _phnModel;
 +
    }
 +
</code>
 +
The {{Icode|ContentPanel}} is a reference to the Grid object defined in XAML ({{Icode|Grid x:Name&#61;"ContentPanel"}}). We bind to this by assigning our {{Icode|PhoneModel}} instance to the referenced object's {{Icode|DataContext}}. Now when the page is loaded the the properties will be taken from our {{Icode|PhoneModel}} instance when the page is loaded. This results in the screen shown in [[#Figure1]].
  
[[File:DataBinding wp one.png|frame|none|Data Binding in Windows Phone|400x600px]]
+
At this point the binding is ''OneTime'' (the properties are updated in the UI only on page load and changes to the UI do not affect the C# object values). The following sections explain how you can make the UI responsive to changes to the model, and how to make the model responsive to changes in the UI after loading (''TwoWay'' binding).
  
== Changing Properties and Updating UI ==
 
  
Now one can simply say if we change the properties of PhoneModel class via some events then that should also update the UI, but sadly that's not the case.
+
== Updating the UI when the properties change in code ==
When we are binding properties to attributes simply changing the value of the properties will not update the UI, to update the UI we need to use the simple
+
[http://msdn.microsoft.com/en-us/library/system.componentmodel.inotifypropertychanged%28v=vs.95%29.aspx INotifyPropertyChanged] interface. We need to implement [http://msdn.microsoft.com/en-us/library/system.componentmodel.inotifypropertychanged%28v=vs.95%29.aspx INotifyPropertyChanged] and raise an event to update the property.
+
  
So first we need to change the PhoneModel class to implement [http://msdn.microsoft.com/en-us/library/system.componentmodel.inotifypropertychanged%28v=vs.95%29.aspx INotifyPropertyChanged] Interface, now PhoneModel.cs will look like:
+
To update the UI in response to changes in the source (model) we first need to update the XAML to state that this the Mode is ''OneWay'' or ''TwoWay'' binding. For a one-way binding all the TextBox definitions would be changed as below:
 +
<code xml>
 +
<TextBox Height="70" HorizontalAlignment="Left" Margin="0,130,0,0" Name="manufacturerBox" Text="{Binding manufacturer,Mode=OneWay}" VerticalAlignment="Top" Width="450" />
 +
</code>
  
 +
In addition, in order to update the UI when a property changes in code, we also need to update the {{Icode|PhoneModel}} class to implement [http://msdn.microsoft.com/en-us/library/system.componentmodel.inotifypropertychanged%28v=vs.95%29.aspx INotifyPropertyChanged]. The new '''PhoneModel.cs''' with this change is shown below:
 
<code csharp>
 
<code csharp>
 
using System.ComponentModel;
 
using System.ComponentModel;
Line 206: Line 219:
 
     }
 
     }
 
}
 
}
 
 
</code>
 
</code>
  
The above code snippet make PhoneModel class to implement [http://msdn.microsoft.com/en-us/library/system.componentmodel.inotifypropertychanged%28v=vs.95%29.aspx INotifyPropertyChanged], and makes a utility method name NotifyPropertyChanged, that method raises the
+
The above code snippet creates a utility method named {{Icode|NotifyPropertyChanged}}, that raises the {{Icode|PropertyChanged}} event with the name of the property which needs to be updated in the UI. All properties need to call this {{Icode|NotifyPropertyChanged}} utility method.
PropertyChanged event with the name of the property which needs to be updated at the UI. All properties needs to call this NotifyPropertyChanged utility method.
+
  
To update the properties of the model and to see whether the UI get's updated or not we will add a button and on click event of the button we will change our properties and will see
+
To update the properties of the model and to see whether the UI get's updated or not we will add a button and on click event of the button we will change our properties and will see if the UI get updates or not, so the code for '''MainPage.xaml.cs''' goes like:
if the UI get updates or not, so the code for MainPage.xaml.cs goes like:
+
  
 
<code csharp>
 
<code csharp>
Line 266: Line 276:
 
</code>
 
</code>
  
and when you click the button the screen should look like:
+
When you click the button the screen should look like Figure 2:
 +
[[File:DataBinding wp two.png|frame|none|400x600px|Figure2: Propagating data from the model to the UI]]
  
[[File:DataBinding wp two.png|frame|none|Data Binding in Windows Phone|400x600px]]
+
== Two-way binding - updating the model from the UI Changes ==
  
 +
''OneWay'' binding (as covered in the previous section) is suitable for read-only controls. For editable controls we need ''TwoWay'' binding so that changes in the UI can update the model.
 +
 +
We don't need to change any other C# code for binding to be bi-directional. All we need to do is change the [[#BindingMode|Mode]] parameter in XAML to ''TwoWay'', as shown:
 +
{Binding software,Mode=TwoWay}
 +
Actually this is optional - the default mode for a {{Icode|TextBox}} is ''TwoWay''. However you are less likely to make a mistake if the binding is explicitly specified.
 +
 +
The final XAML code is therefore:
 +
<code xml>
 +
  <TextBox Height="70" HorizontalAlignment="Left" Margin="12,80,0,0" Name="manufacturerBox" Text="{Binding manufacturer,Mode=TwoWay}" VerticalAlignment="Top"  Width="438" />
 +
  <TextBox Height="72" HorizontalAlignment="Left" Margin="12,156,0,0" Name="modelBox" Text="{Binding model, Mode=TwoWay}" VerticalAlignment="Top" Width="438" />
 +
  <TextBox Height="72" HorizontalAlignment="Left" Margin="12,234,0,0" Name="softwareBox" Text="{Binding software,Mode=TwoWay}" VerticalAlignment="Top" Width="438" />
 +
</code>
 +
 +
 +
To integrate ''TwoWay'' mode binding in our example application, lets add one {{Icode|Button}} and three {{Icode|TextBlock}}'s to the Grid. We then change the data in the {{Icode|TextBox}}, and will see if updated data is pushed back to the {{Icode|DataContext}} by clicking the '''Read Model''' Button - this reads the data from the model object and should update the {{Icode|TextBlock}}'s Text property.
 +
 +
The update XAML for the example is:
 +
 +
<code xml>
 +
  <!--ContentPanel - place additional content here-->
 +
  <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
 +
      <TextBox Height="70" HorizontalAlignment="Left" Margin="12,80,0,0" Name="manufacturerBox" Text="{Binding manufacturer,Mode=TwoWay}" VerticalAlignment="Top" Width="438" />
 +
      <TextBox Height="72" HorizontalAlignment="Left" Margin="12,156,0,0" Name="modelBox" Text="{Binding model, Mode=TwoWay}" VerticalAlignment="Top" Width="438" />
 +
      <TextBox Height="72" HorizontalAlignment="Left" Margin="12,234,0,0" Name="softwareBox" Text="{Binding software,Mode=TwoWay}" VerticalAlignment="Top" Width="438" />
 +
      <Button Content="Update" Height="72" HorizontalAlignment="Left" Margin="9,18,0,0" Name="changeButton" VerticalAlignment="Top" Width="441" Click="updateBtn_Click" />
 +
      <Button Content="Read Model" Height="72" HorizontalAlignment="Left" Margin="12,322,0,0" Name="readBtn" VerticalAlignment="Top" Width="438" Click="readBtn_Click" />
 +
      <TextBlock Height="30" HorizontalAlignment="Left" Margin="32,400,0,0" Name="manufacBlock" Text="TextBlock" VerticalAlignment="Top" Width="401" />
 +
      <TextBlock Height="30" HorizontalAlignment="Left" Margin="32,452,0,0" Name="modelBlock" Text="TextBlock" VerticalAlignment="Top" Width="401" />
 +
      <TextBlock Height="30" HorizontalAlignment="Left" Margin="32,506,0,0" Name="softwareBlock" Text="TextBlock" VerticalAlignment="Top" Width="401" />
 +
    </Grid>
 +
</code>
 +
 +
and click event of ''Read Button'' will look like:
 +
 +
<code csharp>
 +
 +
        private void readBtn_Click(object sender, RoutedEventArgs e)
 +
        {
 +
          // reading data from model and changing Text of the TextBlocks
 +
            manufacBlock.Text = _phnModel.manufacturer;
 +
            modelBlock.Text = _phnModel.model;
 +
            softwareBlock.Text = _phnModel.software;
 +
        }
 +
 +
</code>
 +
 +
If everything implemented is correct than it should look like:
 +
 +
[[File:DataBindingWpThree.png|frame|none|Figure 3: TwoWay data binding in Windows Phone|400x600px]]
  
 
== Summary ==
 
== Summary ==
Line 276: Line 336:
 
== References==
 
== References==
 
* [http://msdn.microsoft.com/en-us/library/system.componentmodel.inotifypropertychanged%28v=vs.95%29.aspx INotifyPropertyChanged]
 
* [http://msdn.microsoft.com/en-us/library/system.componentmodel.inotifypropertychanged%28v=vs.95%29.aspx INotifyPropertyChanged]
 
* [http://msdn.microsoft.com/en-us/library/x9fsa0sw%28v=vs.80%29.aspx c# properties]
 
 
 
* [http://msdn.microsoft.com/en-us/library/ms617928 Binding Class]
 
* [http://msdn.microsoft.com/en-us/library/ms617928 Binding Class]

Latest revision as of 03:50, 17 September 2013

This article explains how bind data objects in code to objects declared in your Windows Phone app's XAML UI.

See Also
WP Metro Icon File.png
WP Metro Icon UI.png
SignpostIcon XAML 40.png
WP Metro Icon WP8.png
SignpostIcon WP7 70px.png
Article Metadata
Code ExampleTested with
SDK: Windows Phone 7.1, Windows Phone 8.0
Devices(s): Lumia 800,710, 920
CompatibilityArticle
Created: gaba88 (09 Sep 2012)
Last edited: hamishwillee (17 Sep 2013)

Contents

[edit] Introduction

Windows Phone apps typically define their UI declaratively using XAML (in Expression Blend). While some UI component values may be hardcoded in XAML, many will be provided by data sources (objects, databases, XML feeds). Data binding is the technique which provides the connection between the XAML components and their values as defined in code.

There are a number of different binding modes, as defined in the BindingMode enumeration:

  • TwoWay - changes to the UI or model automatically update the other. This is used for editable forms or other interactive scenarios.
  • OneWay - updates the UI when the model changes. This is appropriate for read-only controls populated from data.
  • OneTime - updates the UI when the application starts or when the data context changes. This is used when the source data is static/does not change.
  • OneWayToSource - changes to the UI update the model
  • Default - uses the default mode for the particular binding target (UI control). This differs based on the control.


This code example shows how bind TextBox controls in XAML to a source object defined in the C# file. It covers OneTime, OneWay and TwoWay modes. For the modes where the source (model) updates the UI (target) it also shows how to use the INotifyPropertyChanged interface class to ensure that the UI is updated whenever the underlying code changes.

The associated example creates three text boxes in XAML, and uses binding to update their values with information from C# objects.

Figure 1: Data Binding in Windows Phone

[edit] Creating the XAML UI

First we create a simple Windows Phone page which contains a title panel followed by a content panel (Grid) containing three TextBox - which will display manufacturer, software and model text. Note that the content Grid is named ContentPanel, and we will later use this name to bind to the XAML from the C# code (and similarly the Names of each of the TextBoxes).

<!--LayoutRoot is the root grid where all page content is placed-->
<Grid x:Name="LayoutRoot" Background="Transparent">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
 
<!--TitlePanel contains the name of the application and page title-->
<StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">
<TextBlock x:Name="ApplicationTitle" Text="MY APPLICATION" Style="{StaticResource PhoneTextNormalStyle}"/>
<TextBlock x:Name="PageTitle" Text="DataBindingExample" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
</StackPanel>
 
<!--ContentPanel - place additional content here-->
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<TextBox Height="70" HorizontalAlignment="Left" Margin="0,130,0,0" Name="manufacturerBox" Text="manufacturer" VerticalAlignment="Top" Width="450" />
<TextBox Height="72" HorizontalAlignment="Left" Margin="0,206,0,0" Name="modelBox" Text="model" VerticalAlignment="Top" Width="450" />
<TextBox Height="72" HorizontalAlignment="Left" Margin="6,284,0,0" Name="softwareBox" Text="software" VerticalAlignment="Top" Width="450" />
</Grid>
</Grid>

The above XAML code contains hard-coded Text property values for the manufacturer, model and software. To bind the controls to data we first need to update the required properties with the {Binding} keyword. The keyword allows us to specify the name of the property we want to bind to, and the binding mode (ie whether changes to the UI will propagate to the underlying object and visa versa). Both of these two properties are optional: if you just specify {Binding} then the bound object's ToString() method will be called to get the property value and the binding will be the default for the target object..

In this example we specify the particular properties of the bound object to use for the Text (ie the manufacturer property of the bound object will be used for the text value of the manufacturerBox property). We also specify the mode as OneTime so that the UI is updated from the model on page load (only).

Tip.pngTip: It is always best to specify the mode you want to use explicitly as this will often result in better performance.
If we omitted the mode the code would still "work" - the default mode of the TextBox is TwoWay. But without implementing INotifyPropertyChanged the result would be a one time update of the TextBox's content from code. Input into the TextBox will still be stored in the bound property though.

The updated XAML code looks like:

 <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<TextBox Height="70" HorizontalAlignment="Left" Margin="0,130,0,0" Name="manufacturerBox" Text="{Binding manufacturer,Mode=OneTime}" VerticalAlignment="Top" Width="450" />
<TextBox Height="72" HorizontalAlignment="Left" Margin="0,206,0,0" Name="modelBox" Text="{Binding model,Mode=OneTime}" VerticalAlignment="Top" Width="450" />
<TextBox Height="72" HorizontalAlignment="Left" Margin="6,284,0,0" Name="softwareBox" Text="{Binding software,Mode=OneTime}" VerticalAlignment="Top" Width="450" />
</Grid>


At this point we still haven't defined the data source (though we know from the XAML it has properties manufacturer, model and software) and bound it to the XAML. This is done in the C# code, which we define in the following sections.

[edit] Create and bind the data source

Next we create PhoneModel.cs, and define our PhoneModel class. Note how the class has C# properties that match the bound properties in our XAML.

namespace DataBindingEx
{
public class PhoneModel
{
public string manufacturer { get; set; }
public string model { get; set; }
public string software { get; set; }
 
}
}

The next step is to create an instance of the PhoneModel and bind it to the XAML, which we do using the DataContext property. The best place to perform the binding is when page initialisation completes, in the MainPage_Loaded() event handler as shown below.

namespace DataBindingEx
{
public partial class MainPage : PhoneApplicationPage
{
// declare PhoneModel object
PhoneModel _phnModel;
 
// Constructor
public MainPage()
{
InitializeComponent();
 
// add page load event handler
Loaded += MainPage_Loaded;
}
 
void MainPage_Loaded(object sender,RoutedEventArgs e)
{
// initialize _phnModel object
_phnModel = new PhoneModel
{
manufacturer = "Nokia",
model = "Lumia 920",
software = "windows phone 8"
};
 
// call utility method to set DataContext
setDataContext();
}
 
private void setDataContext()
{
ContentPanel.DataContext = _phnModel;
}
}
}

The interesting part of the code is the setDataContext() method:

private void setDataContext()
{
ContentPanel.DataContext = _phnModel;
}

The ContentPanel is a reference to the Grid object defined in XAML (Grid x:Name="ContentPanel"). We bind to this by assigning our PhoneModel instance to the referenced object's DataContext. Now when the page is loaded the the properties will be taken from our PhoneModel instance when the page is loaded. This results in the screen shown in #Figure1.

At this point the binding is OneTime (the properties are updated in the UI only on page load and changes to the UI do not affect the C# object values). The following sections explain how you can make the UI responsive to changes to the model, and how to make the model responsive to changes in the UI after loading (TwoWay binding).


[edit] Updating the UI when the properties change in code

To update the UI in response to changes in the source (model) we first need to update the XAML to state that this the Mode is OneWay or TwoWay binding. For a one-way binding all the TextBox definitions would be changed as below:

<TextBox Height="70" HorizontalAlignment="Left" Margin="0,130,0,0" Name="manufacturerBox" Text="{Binding manufacturer,Mode=OneWay}" VerticalAlignment="Top" Width="450" />

In addition, in order to update the UI when a property changes in code, we also need to update the PhoneModel class to implement INotifyPropertyChanged. The new PhoneModel.cs with this change is shown below:

using System.ComponentModel;
using System.Windows.Data;
 
namespace DataBindingEx
{
public class PhoneModel:INotifyPropertyChanged
{
private string _manufacturer;
private string _model;
private string _software;
 
 
public string manufacturer
{
get { return _manufacturer; }
 
set
{
_manufacturer = value;
NotifyPropertyChanged("manufacturer");
}
}
public string model
{
get { return _model; }
 
set
{
_model = value;
NotifyPropertyChanged("model");
}
}
public string software
{
get { return _software;}
set
{
_software = value;
NotifyPropertyChanged("software");
}
}
 
public event PropertyChangedEventHandler PropertyChanged;
 
private void NotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
 
}
}

The above code snippet creates a utility method named NotifyPropertyChanged, that raises the PropertyChanged event with the name of the property which needs to be updated in the UI. All properties need to call this NotifyPropertyChanged utility method.

To update the properties of the model and to see whether the UI get's updated or not we will add a button and on click event of the button we will change our properties and will see if the UI get updates or not, so the code for MainPage.xaml.cs goes like:

namespace DataBindingEx
{
public partial class MainPage : PhoneApplicationPage
{
PhoneModel _phnModel;
 
// Constructor
public MainPage()
{
InitializeComponent();
Loaded += MainPage_Loaded;
}
 
void MainPage_Loaded(object sender,RoutedEventArgs e)
{
 
_phnModel = new PhoneModel
{
manufacturer = "Nokia",
model = "Lumia 920",
software = "windows phone 8"
};
 
 
setDataContext();
}
 
private void setDataContext()
{
ContentPanel.DataContext = _phnModel;
}
 
// utility method which changes the PhoneModel properties
private void setPhoneProperties(String manufacturer, String model, String software)
{
_phnModel.manufacturer = manufacturer;
_phnModel.model = model;
_phnModel.software = software;
 
}
 
// called when update button is clicked
private void updateBtn_Click(object sender, RoutedEventArgs e)
{
setPhoneProperties("Nokia", "Lumia 900", "windows Phone 7.8");
}
}
}

When you click the button the screen should look like Figure 2:

Figure2: Propagating data from the model to the UI

[edit] Two-way binding - updating the model from the UI Changes

OneWay binding (as covered in the previous section) is suitable for read-only controls. For editable controls we need TwoWay binding so that changes in the UI can update the model.

We don't need to change any other C# code for binding to be bi-directional. All we need to do is change the Mode parameter in XAML to TwoWay, as shown:

{Binding software,Mode=TwoWay}

Actually this is optional - the default mode for a TextBox is TwoWay. However you are less likely to make a mistake if the binding is explicitly specified.

The final XAML code is therefore:

  <TextBox Height="70" HorizontalAlignment="Left" Margin="12,80,0,0" Name="manufacturerBox" Text="{Binding manufacturer,Mode=TwoWay}" VerticalAlignment="Top"   Width="438" />
<TextBox Height="72" HorizontalAlignment="Left" Margin="12,156,0,0" Name="modelBox" Text="{Binding model, Mode=TwoWay}" VerticalAlignment="Top" Width="438" />
<TextBox Height="72" HorizontalAlignment="Left" Margin="12,234,0,0" Name="softwareBox" Text="{Binding software,Mode=TwoWay}" VerticalAlignment="Top" Width="438" />


To integrate TwoWay mode binding in our example application, lets add one Button and three TextBlock's to the Grid. We then change the data in the TextBox, and will see if updated data is pushed back to the DataContext by clicking the Read Model Button - this reads the data from the model object and should update the TextBlock's Text property.

The update XAML for the example is:

  <!--ContentPanel - place additional content here-->
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<TextBox Height="70" HorizontalAlignment="Left" Margin="12,80,0,0" Name="manufacturerBox" Text="{Binding manufacturer,Mode=TwoWay}" VerticalAlignment="Top" Width="438" />
<TextBox Height="72" HorizontalAlignment="Left" Margin="12,156,0,0" Name="modelBox" Text="{Binding model, Mode=TwoWay}" VerticalAlignment="Top" Width="438" />
<TextBox Height="72" HorizontalAlignment="Left" Margin="12,234,0,0" Name="softwareBox" Text="{Binding software,Mode=TwoWay}" VerticalAlignment="Top" Width="438" />
<Button Content="Update" Height="72" HorizontalAlignment="Left" Margin="9,18,0,0" Name="changeButton" VerticalAlignment="Top" Width="441" Click="updateBtn_Click" />
<Button Content="Read Model" Height="72" HorizontalAlignment="Left" Margin="12,322,0,0" Name="readBtn" VerticalAlignment="Top" Width="438" Click="readBtn_Click" />
<TextBlock Height="30" HorizontalAlignment="Left" Margin="32,400,0,0" Name="manufacBlock" Text="TextBlock" VerticalAlignment="Top" Width="401" />
<TextBlock Height="30" HorizontalAlignment="Left" Margin="32,452,0,0" Name="modelBlock" Text="TextBlock" VerticalAlignment="Top" Width="401" />
<TextBlock Height="30" HorizontalAlignment="Left" Margin="32,506,0,0" Name="softwareBlock" Text="TextBlock" VerticalAlignment="Top" Width="401" />
</Grid>

and click event of Read Button will look like:

        private void readBtn_Click(object sender, RoutedEventArgs e)
{
// reading data from model and changing Text of the TextBlocks
manufacBlock.Text = _phnModel.manufacturer;
modelBlock.Text = _phnModel.model;
softwareBlock.Text = _phnModel.software;
}

If everything implemented is correct than it should look like:

Figure 3: TwoWay data binding in Windows Phone

[edit] Summary

Property Binding is one of the best and simplest ways to glue your data with UI attributes.

[edit] References

This page was last modified on 17 September 2013, at 03:50.
987 page views in the last 30 days.