Working with Binding data and UI elements in Silverlight 4

Exclusive offer: get 50% off this eBook here
Microsoft Silverlight 4 Data and Services Cookbook

Microsoft Silverlight 4 Data and Services Cookbook — Save 50%

Over 80 practical recipes for creating rich, data-driven business applications in Silverlight with this Microsoft book and eBook

$35.99    $18.00
by Gill Cleeren Kevin Dockx | May 2010 | Microsoft

In this article series by Gill Cleeren and Kevin Dockx, authors of Microsoft Silverlight 4 Data and Services Cookbook, we will cover the following recipes:

  • Displaying data in Silverlight applications
  • Creating dynamic bindings
  • Binding data to another UI element
  • Binding collections to UI elements
  • Enabling a Silverlight application to automatically update its UI
  • Obtaining data from any UI element it is bound to
  • Using the different modes of data binding to allow persisting data
  • Data binding from Expression Blend 4
  • Using Expression Blend 4 for sample data generation

Read Introduction to Data Binding here.

Binding data to another UI element

Sometimes, the value of the property of an element is directly dependent on the value of the property of another element. In this case, you can create a binding in XAML called an element binding or element-to-element binding . This binding links both values. If needed, the data can flow bidirectionally.

In the banking application, we can add a loan calculator that allows the user to select an amount and the number of years in which they intend to pay the loan back to the bank, including (of course) a lot of interest.

Getting ready

To follow this recipe, you can either continue with your solution from the previous recipe or use the provided solution that can be found in the Chapter02/SilverlightBanking_ Element_Binding_Starter folder in the code bundle that is available on the Packt website. The finished application for this recipe can be found in the Chapter02/SilverlightBanking_Element_Binding_Completed folder.

How to do it...

To build the loan calculator, we'll use Slider controls. Each Slider is bound to a TextBlock using an element-to-element binding to display the actual value. Let's take a look at the steps we need to follow to create this binding:

  1. We will build the loan calculator as a separate screen in the application. Add a new child window called LoanCalculation.xaml. To do so, right-click on the Silverlight project in the Solution Explorer, select Add | New Item..., and choose Silverlight Child Window under Visual C#.
  2. Within MainPage.xaml, add a Click event on the LoanCalculationButton as shown in the following code:
    <Button x:Name="LoanCalculationButton"
    Click="LoanCalculationButton_Click" />
  3. In the code-behind's event handler for this Click event, we can trigger the display of this new screen with the following code:
    private void LoanCalculationButton_Click(object sender,
    RoutedEventArgs e)
    {
    LoanCalculation loanCalculation = new LoanCalculation();
    loanCalculation.Show();
    }
  4. The UI of the LoanCalculation.xaml is quite simple—it contains two Slider controls. Each Slider control has set values for its Minimum and Maximum values (not all UI code is included here; the complete listing can be found in the finished sample code) as shown in the following code:
    <Slider x:Name="AmountSlider"
    Minimum="10000"
    Maximum="1000000"
    SmallChange="10000"
    LargeChange="10000"
    Width="300" >
    </Slider>
    <Slider x:Name="YearSlider"
    Minimum="5"
    Maximum="30"
    SmallChange="1"
    LargeChange="1"
    Width="300"
    UseLayoutRounding="True">
    </Slider>
  5. As dragging a Slider does not give us proper knowledge of where we are exactly between the two values, we add two TextBlock controls. We want the TextBlock controls to show the current value of the Slider control, even while dragging. This can be done by specifying an element-to-element binding as shown in the following code:
    <TextBlock x:Name="AmountTextBlock"
    Text="{Binding ElementName=AmountSlider, Path=Value}">
    </TextBlock>
    <TextBlock x:Name="MonthTextBlock"
    Text="{Binding ElementName=YearSlider, Path=Value}">
    </TextBlock>
  6. Add a Button that will perform the actual calculation called CalculateButton and a TextBlock called PaybackTextBlock to show the results. This can be done using the following code:
    <Button x:Name="CalculateButton"
    Content="Calculate"
    Click="CalculateButton_Click">
    </Button>
    <TextBlock x:Name="PaybackTextBlock"></TextBlock>
  7. The code for the actual calculation that is executed when the Calculate button is clicked uses the actual value for either the Slider or the TextBlock. This is shown in the following code:
    private double percentage = 0.0345;
    private void CalculateButton_Click(object sender,
    RoutedEventArgs e)
    {
    double requestedAmount = AmountSlider.Value;
    int requestedYears = (int)YearSlider.Value;
    for (int i = 0; i < requestedYears; i++)
    {
    requestedAmount += requestedAmount * percentage;
    }
    double monthlyPayback =
    requestedAmount / (requestedYears * 12);
    PaybackTextBlock.Text =
    "€" + Math.Round(monthlyPayback, 2);
    }

Having carried out the previous steps, we now have successfully linked the value of the Slider controls and the text of the TextBlock controls. The following screenshot shows the LoanCalculation.xaml screen as it is included in the finished sample code containing some extra markup:

How it works...

An element binding links two properties of two controls directly from XAML. It allows creating a Binding where the source object is another control. For this to work, we need to create a Binding and specify the source control using the ElementName property. This is shown in the following code:

<TextBlock Text="{Binding ElementName=YearSlider, Path=Value}" >
</TextBlock>

Element bindings were added in Silverlight 3. Silverlight 2 did not support this type of binding.

There's more...

An element binding can also work in both directions, that is, from source to target and vice versa. This can be achieved by specifying the Mode property on the Binding and setting it to TwoWay.

The following is the code for this. In this code, we replaced the TextBlock by a TextBox. When entering a value in the latter, the Slider will adjust its position:

<TextBox x:Name="AmountTextBlock"
Text="{Binding ElementName=AmountSlider, Path=Value,
Mode=TwoWay}" >
</TextBox>

Element bindings without bindings

Achieving the same effect in Silverlight 2—which does not support this feature—is also possible, but only through the use of an event handler as shown in the following code. Element bindings eliminate this need:

private void AmountSlider_ValueChanged(object sender,
RoutedPropertyChangedEventArgs<double> e)
{
AmountSlider.Value = Math.Round(e.NewValue);
AmountTextBlock.Text = AmountSlider.Value.ToString();
}

See also

Element-to-element bindings can be easily extended to use converters. For more information on TwoWay bindings, take a look at the Using the different modes of data binding to allow persisting data recipe in this article.

Binding collections to UI elements

Often, you'll want to display lists of data in your application such as a list of shopping items, a list of users, a list of bank accounts, and so on. Such a list typically contains a bunch of items of a certain type that have the same properties and need to be displayed in the same fashion.

We can use data binding to easily bind a collection to a Silverlight control (such as a ListBox or DataGrid) and use the same data binding possibilities to defi ne how every item in the collection should be bound. This recipe will show you how to achieve this.

Getting ready

For this recipe, you can fi nd the starter solution in the Chapter02/SilverlightBanking_ Binding_Collections_Starter folder and the completed solution in the Chapter02/SilverlightBanking_Binding_Collections_Completed folder in the code bundle that is available on the Packt website.

Microsoft Silverlight 4 Data and Services Cookbook Over 80 practical recipes for creating rich, data-driven business applications in Silverlight with this Microsoft book and eBook
Published: April 2010
eBook Price: $35.99
Book Price: $59.99
See more
Select your format and quantity:

How to do it...

In this recipe, we'll create a ListBox bound to a collection of activities. To complete this task, carry out the following steps:

  1. We'll need a collection of some kind. We'll create a new type, that is, AccountActivity. Add the AccountActivity class to your Silverlight project as shown in the following code:
    public class AccountActivity
    {
    public int ActivityId {get; set;}
    public double Amount { get; set; }
    public string Beneficiary { get; set; }
    public DateTime ActivityDate { get; set; }
    public string ActivityDescription { get; set; }
    }

    Add an ObservableCollection of AccountActivity to MainPage.xaml.cs using the following code:

    private ObservableCollection<AccountActivity>
    accountActivitiesCollection;
  2. Now, we'll instantiate accountActivitiesCollection and fill it with data. To do this, add the following code to MainPage.xaml.cs:
    private void InitializeActivitiesCollection()
    {
    accountActivitiesCollection = new
    ObservableCollection<AccountActivity>();
    AccountActivity accountActivity1 = new AccountActivity();
    accountActivity1.ActivityId = 1;
    accountActivity1.Amount = -33;
    accountActivity1.Beneficiary = "Smith Woodworking Shop London";
    accountActivity1.ActivityDescription = "Paid by credit card";
    accountActivity1.ActivityDate = new DateTime(2009, 9, 1);
    accountActivitiesCollection.Add(accountActivity1);
    AccountActivity accountActivity2 = new AccountActivity();
    accountActivity2.ActivityId = 2;
    accountActivity2.Amount = 1000;
    accountActivity2.Beneficiary = "ABC Infrastructure";
    accountActivity2.ActivityDescription = "Paycheck September
    2009";
    accountActivity2.ActivityDate = new DateTime(2009, 9, 1);
    accountActivitiesCollection.Add(accountActivity2);
    }

    This creates a collection with two items. You can add more if you want to.

  3. Add the following code to the MainPage constructor to call the method you created in the previous step:
    InitializeActivitiesCollection();
  4. We're going to need a control to display these AccountActivity items. To do this, add a ListBox called AccountActivityListBox. This ListBox defines a DataTemplate that defi nes how each AccountActivity is displayed.
    <ListBox x:Name="AccountActivityListBox"
    Width="600"
    Grid.Row="1">
    <ListBox.ItemTemplate>
    <DataTemplate>
    <Grid>
    <Grid.RowDefinitions>
    <RowDefinition></RowDefinition>
    <RowDefinition></RowDefinition>
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
    <ColumnDefinition Width="150">
    </ColumnDefinition>
    <ColumnDefinition Width="330">
    </ColumnDefinition>
    <ColumnDefinitionWidth="100">
    </ColumnDefinition>
    </Grid.ColumnDefinitions>
    <TextBlock
    Grid.Row="0"
    Grid.Column="0"
    Grid.RowSpan="2"
    Text="{Binding ActivityDate}">
    </TextBlock>
    <TextBlock
    Grid.Row="0"
    Grid.Column="1"
    Text="{Binding Beneficiary}"
    FontWeight="Bold">
    </TextBlock>
    <TextBlock
    Grid.Row="0"
    Grid.Column="2"
    HorizontalAlignment="Right"
    Text="{Binding Amount}">
    </TextBlock>
    <TextBlock
    Grid.Row="1"
    Grid.Column="1"
    Text="{Binding ActivityDescription}">
    </TextBlock>
    </Grid>
    </DataTemplate>
    </ListBox.ItemTemplate>
    </ListBox>
  5. In the MainPage constructor, set the ObservableCollection of AccountActivity you created in step 2 as the ItemsSource of the ListBox as shown in the following code:
    AccountActivityListBox.ItemsSource = accountActivitiesCollection;
  6. If we build and run the application now, we'll see that a list of AccountActivity items is displayed as shown in the following screenshot:

How it works...

The first three steps aren't important for people who have worked with collections before. A class is created to define the type of items that are held by the collection, which is initialized and then items are added to it. The default collection type to use in Silverlight is ObservableCollection. We're using this collection type here. (For more information about this, have a look at the There's more... section in this recipe.)

The real magic happens in steps 4 and 5. In step 4, we are creating a ListBox, which has an ItemTemplate property. This ItemTemplate property should contain a DataTemplate, and it's this DataTemplate that defi nes how each item of the collection should be visualized. So, the DataTemplate corresponds to one item of your collection: one AccountActivity. This means we can use the data binding syntax that binds to properties of an AccountActivity in this DataTemplate.

When the ItemsSource property of the ListBox gets set to the ObservableCollection of AccountActivity, each AccountActivity in the collection is evaluated and visualized as defined in the DataTemplate.

There's more...

An ObservableCollection is the default collection type you'll want to use in a Silverlight application because it's a collection type that implements the INotifyCollectionChanged interface. This makes sure that the UI can automatically be updated when the collection is changed (by adding or deleting an item). More on this can be found in the Enabling a Silverlight application to automatically update its UI recipe.

The same principle applies for the properties of classes that implement the INotifyPropertyChanged interface. More on this can be found in the same recipe, that is, Enabling a Silverlight application to automatically update its UI.

In this recipe, we're using a ListBox to visualize our ObservableCollection. However, every control that inherits the ItemsControl class (directly or indirectly) can be used in this way, such as a ComboBox, TreeView, DataGrid, WrapPanel, and so on.

See also

To learn how an ObservableCollection enables a UI to be automatically updated, have a look at the Enabling a Silverlight application to automatically update its UI recipe.

Enabling a Silverlight application to automatically update its UI

In the previous recipes, we looked at how we can display data more easily using data binding for both single objects as well as collections. However, there is another feature that data binding offers us for free, that is, automatic synchronization between the target and the source. This synchronization will make sure that when the value of the source property changes, this change will be refl ected in the target object as well (being a control on the user interface). This also works in the opposite direction—when we change the value of a bound control, this change will be pushed to the data object as well. Silverlight's data binding engine allows us to opt-in to this synchronization process. We can specify if we want it to work—and if so, in which direction(s)—using the mode of data binding.

The synchronization works for both single objects bound to the UI as well as entire collections. But for it to work, an interface needs to be implemented in either case.

This synchronization process is what we'll be looking at in this recipe.

Getting ready

If you want to follow along with this recipe, you can either use the code from the previous recipes or use the provided solution in the Chapter02/SilverlightBanking_Update_ UI_Starter folder in the code bundle that is available on the Packt website. The fi nished solution for this recipe can be found in the Chapter02/SilverlightBanking_Update_ UI_Completed folder.

How to do it...

In this recipe, we'll look at how Silverlight does automatic synchronization, both for a single object and for a collection of objects. To demonstrate both types of synchronization, we'll use a timer that adds another activity on the account every 10 seconds. A single instance of the Owner class is bound to the UI. However, the newly added activities will cause the CurrentBalance, LastActivity, and LastActivityAmount properties of the Owner class to get updated. Also, these activities on the account will be reflected in the list of activities. The following are the steps to achieve automatic synchronization:

  1. For the data binding engine to notice changes on the source object, the source needs to send a notification that the value of one of its properties has changed. By default, the Owner class does not do so. The original Owner class is shown by the following code:
    public class Owner
    {
    public int OwnerId { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Address { get; set; }
    public string ZipCode { get; set; }
    public string City { get; set; }
    public string State { get; set; }
    public string Country { get; set; }
    public DateTime BirthDate { get; set; }
    public DateTime CustomerSince { get; set; }
    public string ImageName { get; set; }
    public DateTime LastActivityDate { get; set; }
    public double CurrentBalance { get; set; }
    public double LastActivityAmount { get; set; }
    }
  2. To make this class support notifications, an interface has to be implemented, namely the INotifyPropertyChanged interface. This interface defines one event, that is, the PropertyChanged event. Whenever one of the properties changes, this event should be raised. The changed Owner class is shown in the following code. (Only two properties are shown as they are all similar; the rest can be found in the finished solution in the book sample code.)
    public class Owner : INotifyPropertyChanged
    {
    private double currentBalance;
    private string firstName;
    public event PropertyChangedEventHandler PropertyChanged;
    public string FirstName
    {
    get
    {
    return firstName;
    }
    set
    {
    firstName = value;
    if(PropertyChanged != null)
    PropertyChanged(this, new
    PropertyChangedEventArgs("FirstName"));
    }
    }
    public double CurrentBalance
    {
    get
    {
    return currentBalance;
    }
    set
    {
    currentBalance = value;
    if(PropertyChanged != null)
    PropertyChanged(this, new
    PropertyChangedEventArgs("CurrentBalance"));
    }
    }
    }
  3. To simulate updates, we'll use a DispatcherTimer in the MainPage. With every tick of this timer, a new activity on the account is created. We'll count the new value of the CurrentBalance with every tick and update the value of the LastActivityDate and LastActivityAmount as shown in the following code:
    private DispatcherTimer timer;
    private int currentActivityId = 11;
    public MainPage()
    {
    InitializeComponent();
    //initialize owner data
    InitializeOwner();
    OwnerDetailsGrid.DataContext = owner;
    timer = new DispatcherTimer();
    timer.Interval = new TimeSpan(0, 0, 10);
    timer.Tick += new EventHandler(timer_Tick);
    timer.Start();
    }
    void timer_Tick(object sender, EventArgs e)
    {
    currentActivityId++;
    double amount = 0 - new Random().Next(100);
    AccountActivity newActivity = new AccountActivity();
    newActivity.ActivityId = currentActivityId;
    newActivity.Amount = amount;
    newActivity.Beneficiary = "Money withdrawal";
    newActivity.ActivityDescription = "ATM In Some Dark Alley";
    newActivity.ActivityDate = new DateTime(2009, 9, 18);
    owner.CurrentBalance += amount;
    owner.LastActivityDate = DateTime.Now;
    owner.LastActivityAmount = amount;
    }
  4. In XAML, the TextBlock controls are bound as mentioned before. If no Mode is specifi ed, OneWay is assumed. This causes updates of the source to be reflected in the target as shown in the following code:
    <TextBlock x:Name="CountryValueTextBlock"
    Grid.Row="8"
    Grid.Column="1"
    Margin="2"
    Text="{Binding Country}" >
    </TextBlock>
    <TextBlock x:Name="BirthDateValueTextBlock"
    Grid.Row="9"
    Grid.Column="1"
    Margin="2"
    Text="{Binding BirthDate}" >
    </TextBlock>
    <TextBlock x:Name="CustomerSinceValueTextBlock"
    Grid.Row="10"
    Grid.Column="1"
    Margin="2"
    Text="{Binding CustomerSince}" >
    </TextBlock>
  5. If we run the application now, after 10 seconds, we'll see the values changing. The values can be seen in the following screenshot:

  6. In the Binding collections to UI elements recipe, we saw how to bind a list of AccountActivity items to a ListBox. If we want the UI to update automatically when changes occur in the list (when a new item is added or an existing item is removed), then the list to which we bind should implement the INotifyCollectionChanged interface. Silverlight has a built-in list that implements this interface, namely the ObservableCollection. If we were binding to a List, then these automatic updates wouldn't work. Working with an ObservableCollection is no different than working with a List. In the following code, we're creating the ObservableCollection and adding items to it:
    private ObservableCollection<AccountActivity>
    accountActivitiesCollection;
    private void InitializeActivitiesCollection()
    {
    accountActivitiesCollection = new
    ObservableCollection<AccountActivity>();
    AccountActivity accountActivity1 = new AccountActivity();
    accountActivity1.ActivityId = 1;
    accountActivity1.Amount = -33;
    accountActivity1.Beneficiary = "Smith Woodworking Shop London";
    accountActivity1.ActivityDescription = "Paid by credit card";
    accountActivity1.ActivityDate = new DateTime(2009, 9, 1);
    accountActivitiesCollection.Add(accountActivity1);
    }
  7. Update the Tick event, so that each new Activity is added to the collection:
    void timer_Tick(object sender, EventArgs e)
    {
    ...
    AccountActivity newActivity = new AccountActivity();
    ...
    accountActivitiesCollection.Add(newActivity);
    ...
    }
  8. To bind this collection to the ListBox, we use the ItemsSource property. The following code can be added to the constructor to create the collection and perform the binding:
    InitializeActivitiesCollection();
    AccountActivityListBox.ItemsSource = accountActivitiesCollection;

When we run the application now, we see that all added activities appear in the ListBox control. With every tick of the Timer, a new activity is added and the UI refreshes automatically.

Microsoft Silverlight 4 Data and Services Cookbook Over 80 practical recipes for creating rich, data-driven business applications in Silverlight with this Microsoft book and eBook
Published: April 2010
eBook Price: $35.99
Book Price: $59.99
See more
Select your format and quantity:

How it works...

In some scenarios, we might want to view changes to the source object in the user interface immediately. Silverlight's data binding engine can automatically synchronize the source and target for us, both for single objects and for collections.

Single objects

If we want the target controls on the UI to update automatically if a property value of an instance changes, then the class to which we are binding should implement the INotifyPropertyChanged interface. This interface defines just one event— PropertyChanged. It is defi ned in the System.ComponentModel namespace using the following code:

 

public interface INotifyPropertyChanged
{
event PropertyChangedEventHandler PropertyChanged;
}

 

This event should be raised whenever the value of a property changes. The name of the property that has changed is passed as the parameter for the instance of PropertyChangedEventArgs.

A binding in XAML is set to OneWay by default. OneWay allows updates to be passed on to the target. (For more information on binding modes, refer to the Using the different modes of data binding to allow persisting data recipe.) If we had set the binding to Mode=OneTime, then only the initial values would have been loaded.

Now, what exactly happens when we bind to a class that implements this interface? Whenever we do so, Silverlight's data binding engine will notice this and will automatically start to check if the PropertyChanged event is raised by an instance of the class. It will react to this event, thereby resulting in an update of the target.

Collections

Whenever a collection changes, we might want to get updates of this collection as well. In this example, we want to view the direct information of all the activities on the account. Normally, we would have placed these in a List. However, List does not raise an event when items are being added or deleted. Similar to INotifyPropertyChanged, an interface exists so that a list/collection should implement for data binding to pick up those changes. This interface is known as INotifyCollectionChanged.

We didn't directly create a class that implements this interface. However, we used an ObservableCollection. This collection already implemented this interface for us.

Whenever items are being added, deleted, or the collection gets refreshed, an event will be raised on which the data binding engine will bind itself. As for single objects, changes will be refl ected in the UI immediately.

Cleaning up the code

In the code for the Owner class, we have inputted all the properties as shown in the following code:

public double CurrentBalance
{
get
{
return currentBalance;
}
set
{
currentBalance = value;
if(currentBalance != null)
PropertyChanged(this, new
PropertyChangedEventArgs("CurrentBalance"));
}
}

It's a good idea to move the check whether the event is null (which means that there is no one actually subscribed to the event) and the raising of the event to a separate method as shown in the following code:

 

public void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new
PropertyChangedEventArgs(propertyName));
}
}
public double CurrentBalance
{
get
{
return currentBalance;
}
set
{
if (currentBalance != value)
{
currentBalance = value;
OnPropertyChanged("CurrentBalance");
}
}
}

It may also be a good idea to move this method to a base class and have the entities inherit from this class as shown in the following code:

 

public class BaseEntity : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new
PropertyChangedEventArgs(propertyName));
}
}
}
public class Owner : BaseEntity
{
...
}

While automatic synchronization is a nice feature that comes along with data binding for free, it's not always needed. Sometimes it's not even wanted. Therefore, implement the interfaces that are described here only when the application needs them. It's an opt-in model.

Obtaining data from any UI element it is bound to

When a user who is working with your application performs a certain action, it's often essential to know on what object this action will be executed. For example, if a user clicks on a Delete button on an item, it's essential that you know which item is clicked so that you can write the correct code to delete that item. Also, when a user wants to edit an item in a list, it's necessary that you—the programmer—know which item in the list the user wants to edit.

In Silverlight, there is a very easy mechanism called DataContext that helps us in this task. In this recipe, we're going to use the DataContext to get the data when we need it.

Getting ready

If you want to follow along with this recipe, you can either use the code from the previous recipes or use the provided solution in the Chapter02/SilverlightBanking_ Obtaining_Data_Starter folder in the code bundle that is available on the Packt website. The completed solution for this recipe can be found in the Chapter02/SilverlightBanking_Obtaining_Data_Completed folder.

How to do it...

We're going to create a Details... button for each item in the ListBox containing AccountActivities. This Details... button will open a new ChildWindow that will display details about the selected AccountActivity. To achieve this, carry out the following steps:

  1. We'll start by opening the solution we've created by following all the steps of the Binding data to collections recipe. We add a new item to the Silverlight project—a ChildWindow named ActivityDetailView—and add the following code to the XAML defining this new control:
    <Grid x:Name="LayoutRoot" Margin="2">
    <Grid.RowDefinitions>
    <RowDefinition />
    <RowDefinition Height="Auto" />
    </Grid.RowDefinitions>
    <Grid x:Name="OwnerDetailsGrid">
    <Grid.RowDefinitions>
    <RowDefinition Height="30"></RowDefinition>
    <RowDefinition Height="30"></RowDefinition>
    <RowDefinition Height="30"></RowDefinition>
    <RowDefinition Height="30"></RowDefinition>
    <RowDefinition Height="30"></RowDefinition>
    <RowDefinition Height="30"></RowDefinition>
    <RowDefinition Height="30"></RowDefinition>
    <RowDefinition Height="30"></RowDefinition>
    <RowDefinition Height="30"></RowDefinition>
    <RowDefinition Height="30"></RowDefinition>
    <RowDefinition Height="30"></RowDefinition>
    <RowDefinition Height="*"></RowDefinition>
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
    <ColumnDefinition></ColumnDefinition>
    <ColumnDefinition></ColumnDefinition>
    </Grid.ColumnDefinitions>
    <TextBlock x:Name="ActivityIdTextBlock"
    Grid.Row="0"
    FontWeight="Bold"
    Margin="2"
    Text="Activity ID:">
    </TextBlock>
    <TextBlock x:Name="BeneficiaryTextBlock"
    Grid.Row="1"
    FontWeight="Bold"
    Margin="2"
    Text="Beneficiary:">
    </TextBlock>
    <TextBlock x:Name="AmountTextBlock"
    Grid.Row="2"
    FontWeight="Bold"
    Margin="2"
    Text="Amount:">
    </TextBlock>
    <TextBlock x:Name="ActivityDateTextBlock"
    Grid.Row="3"
    FontWeight="Bold"
    Margin="2"
    Text="Date:">
    </TextBlock>
    <TextBlock x:Name="DescriptionTextBlock"
    Grid.Row="4"
    FontWeight="Bold"
    Margin="2"
    Text="Description:">
    </TextBlock>
    <TextBlock x:Name="ActivityIdTextBlockValue"
    Grid.Row="0"
    Grid.Column="1"
    Margin="2"
    Text="{Binding ActivityId}" >
    </TextBlock>
    <TextBlock x:Name="BeneficiaryTextBlockValue"
    Grid.Row="1"
    Grid.Column="1"
    Margin="2"
    Text="{Binding Beneficiary}" >
    </TextBlock>
    <TextBlock x:Name="AmountTextBlockValue"
    Grid.Row="2"
    Grid.Column="1"
    Margin="2"
    Text="{Binding Amount}" >
    </TextBlock>
    <TextBlock x:Name="ActivityDateTextBlockValue"
    Grid.Row="3"
    Grid.Column="1"
    Margin="2"
    Text="{Binding ActivityDate}" >
    </TextBlock>
    <TextBlock x:Name="DescriptionTextBlockValue"
    Grid.Row="4"
    Grid.Column="1"
    Margin="2"
    Text="{Binding ActivityDescription}"
    TextWrapping="Wrap">
    </TextBlock>
    </Grid>
    <Button x:Name="btnOK"
    Content="OK"
    Click="btnOK_Click"
    Width="75"
    Height="23"
    HorizontalAlignment="Right"
    Margin="0,12,0,0"
    Grid.Row="1" />
    </Grid>
  2. Next, we open ActivityDetailView.xaml.cs and add the following code:
    public ActivityDetailView(AccountActivity activity)
    {
    InitializeComponent();
    this.DataContext = activity;
    }
    private void btnOK_Click(object sender, RoutedEventArgs e)
    {
    this.DialogResult = true;
    }
  3. Now, we open MainPage.xaml, locate the ListBox named AccountActivityListBox, and add a button named btnDetails to the DataTemplate of that ListBox. This is shown in the following code:
    <Button x:Name="btnDetails"
    Grid.Row="1"
    Grid.Column="2"
    HorizontalAlignment="Right"
    Content="Details..."
    Click="btnDetails_Click">
    </Button>
  4. Add the following C# code to MainPage.xaml.cs to handle the Click event of the button we've added in the previous step:
    private void btnDetails_Click(object sender, RoutedEventArgs e)
    {
    ActivityDetailView activityDetailView = new ActivityDetailView
    ((AccountActivity)((Button)sender).DataContext);
    activityDetailView.Show();
    }
  5. We can now build and run the solution. When you click on the Details... button, you'll see the details of the selected AccountActivity in a ChildWindow. You can see the result in the following screenshot:

How it works...

Once the DataContext of a general control has been set (any CLR object can be used as DataContext), each child item of that control refers to the same DataContext.

For example, if we have a UserControl containing a Grid that has three columns, with a TextBox in the fi rst two and a Button in the last column, and if the DataContext of the UserControl gets set to an object of the Person type, then the Grid, TextBox, and Button would have that same Person object as their DataContext. To be more precise, if the DataContext of an item hasn't been set, then Silverlight will find out if the parent of that item in the visual tree has its DataContext set to an object and use that DataContext as the DataContext of the child item. Silverlight keeps on trickling right up to the uppermost level of the application.

If you use an ItemsControl such as a ListBox and give it a collection as an ItemsSource, then the DataContext of that ListBox is the collection you bound it to.

Following the same logic, the DataContext of one ListBoxItem is one item from the collection. In our example, one item is defined by a DataTemplate containing a Grid, various TextBlocks, and a Button. Due to the fact that Silverlight keeps on trickling up to look for a valid DataContext, the DataContext of the Grid, all the TextBlocks, and the Button are the same; they're one item from the ItemsSource collection of the ListBox.

With this in mind, we can now access the data that is bound to any UI element of our ListBoxItem. The data we need is the DataContext of the button we're clicking.

The click event of this button has a sender parameter—the Button itself. To access the DataContext, we cast the sender parameter to a Button object. As we know that the ListBox is bound to an ObservableCollection of AccountActivity, we can cast the DataContext to type AccountActivity. To show the details window, all we need to do now is pass this object to the constructor of the details ChildWindow.

See also

The DataContext is important when you're working with data binding as it's the DataContext of an element that's looked at as the source of the binding properties.

>> Continue Reading: Data binding from Expression Blend 4 in Silverlight 4

If you have read this article you may be interested to view :

About the Author :


Gill Cleeren

Gill Cleeren is Microsoft Regional Director (http://www.theregion.com), Silverlight MVP (former ASP.NET MVP) and Telerik MVP. He lives in Belgium where he works as .NET architect at Ordina (http://www.ordina.be/). Passionate about .NET, he’s always playing with the newest bits. In his role as Regional Director, Gill has given many sessions, webcasts and training on new as well as existing technologies, such as Silverlight, ASP.NET and WPF at conferences including TechEd Berlin 2010, TechDays Belgium – Switzerland - Sweden, DevDays NL, NDC Oslo Norway, DevReach Bulgaria, NRW Conference Germany, Spring Conference UK, Telerik Silverlight Roadshow in Sweden, Telerik RoadShow UK. He is the author of Packt’s Microsoft Silverlight 4 Data and Services Cookbook and is also the author of many articles in various developer magazines and for SilverlightShow.net and he organizes the yearly Community Day event in Belgium. He also leads Visug (http://www.visug.be), the largest .NET user group in Belgium. You can find his blog at http://www.snowball.be and on Twitter by following @gillcleeren.

Kevin Dockx

Kevin Dockx lives in Belgium and works at RealDolmen, one of Belgium's biggest ICT companies, where he is a 30-year old technical specialist/project leader on .NET web applications, mainly Silverlight, and a solution manager for Rich Applications (Silverlight, Windows Phone 7, WPF, Surface, HTML5). His main focus is on all things Silverlight, but he still keeps an eye on the new developments concerning other products from the Microsoft .NET (Web) Stack. As a Silverlight enthusiast, he's a regular speaker on various national and international events, like Microsoft DevDays in the Netherlands, Microsoft Techdays in Portugal, NDC Oslo Norway, and Community Day Belgium. He is the author of Packt’s Microsoft Silverlight 4 Data and Services Cookbook and also writes articles for various Silverlight-related sites & magazines. His blog, which contains various tidbits on Silverlight, .NET, and the occasional rambling, can be found at http://blog.kevindockx.com/, and you can find him on Twitter as well: @KevinDockx.

Books From Packt

Microsoft Silverlight 4 Business Application Development: Beginner’s Guide
Microsoft Silverlight 4 Business Application Development: Beginner’s Guide

SOA Patterns with BizTalk Server 2009
SOA Patterns with BizTalk Server 2009

ASP.NET MVC 1.0 Quickly
ASP.NET MVC 1.0 Quickly

Programming Microsoft Dynamics NAV 2009
Programming Microsoft Dynamics NAV 2009

VSTO 3.0 for Office 2007 Programming
VSTO 3.0 for Office 2007 Programming

Microsoft Dynamics AX 2009 Programming: Getting Started
Microsoft Dynamics AX 2009 Programming: Getting Started

Least Privilege Security for   Windows 7, Vista, and XP
Least Privilege Security for Windows 7, Vista, and XP

Learning SQL Server 2008 Reporting Services
Learning SQL Server 2008 Reporting Services

No votes yet

Post new comment

CAPTCHA
This question is for testing whether you are a human visitor and to prevent automated spam submissions.
p
8
4
P
f
S
Enter the code without spaces and pay attention to upper/lower case.
Code Download and Errata
Packt Anytime, Anywhere
Register Books
Print Upgrades
eBook Downloads
Video Support
Contact Us
Awards Voting Nominations Previous Winners
Judges Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software
Resources
Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software