Data Binding – Margin Notes

 

We have a couple tutorials and videos about Data-binding, and once you grok the basics, it is reasonably straightforward.

There are a couple interesting concepts at the edges that are worth calling out, however.  The topics I’d like to cover in this and a couple more blog posts include

  • Binding and DataContext (today, as a gentle intro)
  • The role of Value Converters & Data Validation (next)
  • Property Paths (fun)

DataContext

  One of the first places that folks become confused when it comes to data-binding is in the relationship between the Binding Xaml syntax, and the DataContext set in code.  The way I think about this is that at design time I know what properties I want to bind to but not which object I’ll have in my hand.  At run time, I’ll have the specific object, and I’d like all the properties there and ready to link to, like neurotransmitter receptors standing by to absorb Serotonin. [1]

For example, I might have a library full of books, and I might know that each book has a Title, and Author, and a collection of chapters.   But I don’t know which book I’ll be displaying when the application is running.

I can lay out my page and bind the control that I’ll use to display these three fields even without knowing which book the user will request; all I need to know is that the Book class defines these three properties. It is the property that I bind to.

   1: <TextBlock x:Name="TitlePrompt" Text="Title:  " 
   2:     VerticalAlignment="Bottom"
   3:     HorizontalAlignment="Right"
   4:     Grid.Row="0"  Grid.Column="0" />
   5:  
   6: <TextBlock x:Name="Title" 
   7:     Text="{Binding Title, Mode=OneWay }" 
   8:     VerticalAlignment="Bottom"
   9:     HorizontalAlignment="Left"
  10:     Grid.Row="0" Grid.Column="1" />
  11:     
  12: <TextBlock x:Name="AuthorPrompt" Text="Author: " 
  13:     VerticalAlignment="Bottom"
  14:     HorizontalAlignment="Right"
  15:     Grid.Row="1"  Grid.Column="0" />
  16:  
  17: <TextBlock x:Name="Author" 
  18:     Text="{Binding Author, Mode=OneWay }" 
  19:     VerticalAlignment="Bottom"
  20:     HorizontalAlignment="Left"
  21:     Grid.Row="1" Grid.Column="1" />
  22:  
  23: <TextBlock x:Name="ChapterPrompt" Text="Chapters:  "  
  24:     VerticalAlignment="Bottom"
  25:     HorizontalAlignment="Right"
  26:     Grid.Row="2" Grid.Column="0"  />
  27:  
  28: <ListBox x:Name="Chapters" 
  29:     ItemsSource="{Binding  Chapters, Mode=OneWay}"
  30:     VerticalAlignment="Bottom"
  31:     HorizontalAlignment="Left"
  32:     Height="60" Width="200"
  33:     Grid.Row="2" Grid.Column="1" />
  34:  

Mode

When I bind I tell the binding engine that I’m binding in one of three modes:

  1. OneTime (bind and then I’ll never change it)
  2. OneWay (bind from the datasource to the UI, and keep the UI up to date)
  3. TwoWay (bind from the datasource to the UI and if either changes, update the other)

There is a trade off in efficiency vs.. freshness of data that I’ll return to in another entry.

Context

Having set the property of the object at design time, (e.g., Binding Title) I need to inform the TextBlock (or whichever control I’m binding to) which object’s property to bind to – that is “okay, bind to the Title, but whose??”  That is decided at run time, typically by retrieving a specific book based on a user’s action.

The context is a bit odd; it is tied to the visual hierarchy and contained objects inherit the context from outer objects, though you are free to supply them with their own context.  If you only need a single object for everything in the grid, you can set the DataContext for the grid, and then all the controls within that grid will inherit it (note that this is different from class inheritance)

Thus, you could set up the DataContext in code by writing,

Title.DataContext = currentBook;
Author.DataContext = currentBook;
Chapters.DataContext = currentBook;

or you could just write

LayoutRoot.DataContext = currentBook;

In the former case, you are setting the DataContext for each control, in the latter, you are setting the DataContext for the container control (LayoutRoot is the grid), and the contained controls (Title, Author, Chapters) inherit that context).

Once the context is set, the Binding can be completed. You’ll remember that the TextBlock  named Title looked like this:

   1: <TextBlock x:Name="Title" 
   2:     Text="{Binding Title, Mode=OneWay }" 
   3:     VerticalAlignment="Bottom"
   4:     HorizontalAlignment="Left"
   5:     Grid.Row="0" Grid.Column="1" />

Having now set the data context, the binding resolves to the Title property of currentBook which is of type Book and thus resolves to a specific property of a specific object with a very specific value to be displayed.

The list of chapters is handled very similarly, except it is the ItemSource that was set to the property Chapters. If we examine the Book class we find that Chapters is a collection (a List<string>) and serves well as an ItemSource.

In the next column, I’ll turn to Value Converters and Data Validation.

-jesse

(note, the code for this entry is taken from the code used for the tutorial linked above)

[1] This analogy has been reported to the Department of Metaphors and will be investigated for appropriateness. You will be notified.

About Jesse Liberty

Jesse Liberty has three decades of experience writing and delivering software projects and is the author of 2 dozen books and a couple dozen online courses. His latest book, Building APIs with .NET will be released early in 2025. Liberty is a Senior SW Engineer for CNH and he was a Senior Technical Evangelist for Microsoft, a Distinguished Software Engineer for AT&T, a VP for Information Services for Citibank and a Software Architect for PBS. He is a Microsoft MVP.
This entry was posted in z Silverlight Archives. Bookmark the permalink.