programming4us
programming4us
DATABASE

Silverlight : Binding Across Elements

- How To Install Windows Server 2012 On VirtualBox
- How To Bypass Torrent Connection Blocking By Your ISP
- How To Install Actual Facebook App On Kindle Fire
11/30/2012 1:55:48 AM

1. Problem

You would like to data bind some property of a XAML element to a property on another element on the page or to a different property on the source element itself.

2. Solution

To bind to a property on another element, name the source element, and then use the ElementName property on the binding. To bind to a property on the same element, use the RelativeSource property on the binding.

3. How It Works

You have walked through binding a property (target) of a XAML element to a property (source) on a CLR object. This is one possible scenario. You may encounter situations where the binding scenarios are slightly different in terms of the binding source.

3.1. Binding to Another Element

In this scenario, a property on an element on a page is data bound to a property on another element on the same page. You can achieve this by setting the Binding.ElementName property on the binding declaration to the name of the source element and the Binding.Path property to the name of the property on the element. Note that this feature was introduced in Silverlight 3.

For an example, consider a Slider control on a page, with a TextBox on the same page displaying the current value of the Slider. This snippet illustrates such a binding arrangement:

<TextBox Text="{Binding Path=Value,ElementName=sliderSource, Mode=OneWay}" />
<Slider x:Name="sliderSource"
        Minimum="0"
        Maximum="100" />

					  

Note that the Binding.ElementName on the TextBox.Text property points to the Slider on the page. The rest of the binding declaration follows the usual binding rules; for instance, if you were to set the Binding.Mode value to TwoWay, editing the TextBox.Text to a permissible value within the Slider's range would actually reset the Slider thumb to that value.

3.2. Binding to Self

In this scenario, a property on an element is data bound to another property on the same element. This is made possible by using the Binding.RelativeSource property. The Binding.RelativeSource property can be set to one of the two values specified in the System.Windows.Data.RelativeSourceMode enumeration: Self and TemplatedParent. Using the RelativeSourceMode.Self value allows the binding to use the element itself as a source for the binding.

In the following code snippet, you bind the ForeGround property of a TextBox to the Text property of the same TextBox. The intent is that if the user types in a valid color name in the TextBox, the edited text is displayed in that color. Since there is no conversion from string to a brush, you rely on a value converter to do the conversion for you:

<TextBox
  Foreground="{Binding Path=Text,RelativeSource={RelativeSource Self},
  Converter={StaticResource REF_ColorStringToBrushConverter}" />

Note the syntax of the RelativeSource attribute setting in the preceding binding expression. The format RelativeSource={RelativeSource <RelativeSourceMode>} is the required syntax.

3.3. Binding to the TemplatedParent

An instance of a control to which a control template is applied is the TemplatedParent to any element within the control template definition. The following snippet shows a possible binding where a TextBox within a control template is binding its Foreground property to the TemplatedParent's Foreground property:

<ControlTemplate TargetType="MyControl">
  ...
  <TextBox
      Foreground=
    "{Binding Path=Foreground,RelativeSource={RelativeSource TemplatedParent}}" />
  ...

</ControlTemplate>

					  

This will cause the TextBox to inherit the same Foreground brush that the developer decides to set on any particular instance of the control named MyControl.

4. The Code

The code sample for this recipe illustrates the element binding and self binding techniques discussed above. The sample uses the new 3-D capabilities in Silverlight to rotate a simple visual along the X, Y, and Z axes of a 3-D plane. The visual contains a Grid with the current angle values for each rotation axis displayed within a Border, and three separate Sliders are used to control the rotation angles. 

Figure 1 shows the sample in action.

Figure 1. Element and Self Binding sample

The majority of the code is encapsulated in a user control named RotatorDemoControl. Listing 1 shows the complete XAML for RotatorDemoControl.

Listing 1. XAML for RotatorDemoControl
<UserControl x:Class="Recipe4_5.RotatorDemoControl"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             mc:Ignorable="d"
             xmlns:local="clr-namespace:Recipe4_5"
             >

  <Grid x:Name="LayoutRoot">

					  

<Grid.RowDefinitions>
      <RowDefinition Height="0.75*" />
      <RowDefinition Height="0.25*" />
    </Grid.RowDefinitions>
    <Grid x:Name="target"
          Width="275"
          Height="100">
      <Grid.ColumnDefinitions>
        <ColumnDefinition />
        <ColumnDefinition />
        <ColumnDefinition />
      </Grid.ColumnDefinitions>
      <Grid.RowDefinitions>
        <RowDefinition />
        <RowDefinition />
        <RowDefinition />
      </Grid.RowDefinitions>
      <Border BorderThickness="2"
              Grid.RowSpan="3"
              Grid.ColumnSpan="3"
              BorderBrush="Red"
              Background="AliceBlue"></Border>
      <TextBlock Text="Rotation X"
                 Margin="3,0,0,0" />
      <TextBlock Text=":"
                 Grid.Column="1" />
      <TextBlock Text="{Binding Xangle}"
                 Grid.Column="2"
                 Margin="0,0,0,3" />
      <TextBlock Text="Rotation Y"
                 Grid.Row="1"
                 Margin="3,0,0,0" />
      <TextBlock Text=":"
                 Grid.Column="1"
                 Grid.Row="1" />
      <TextBlock Text="{Binding Yangle}"
                 Grid.Column="2"
                 Grid.Row="1"
                 Margin="0,0,0,3" />
      <TextBlock Text="Rotation Z"
                 Grid.Row="2"
                 Margin="3,0,0,0" />
      <TextBlock Text=":"
                 Grid.Column="1"
                 Grid.Row="2" />

					  

<TextBlock Text="{Binding Zangle}"
                 Grid.Column="2"
                 Grid.Row="2"
                 Margin="0,0,0,3" />
      <Grid.Projection>
        <PlaneProjection x:Name="gridProjection" />
      </Grid.Projection>
    </Grid>
    <StackPanel Orientation="Vertical" HorizontalAlignment="Center"
                Grid.Row="1">
      <StackPanel Orientation="Horizontal"
                  Margin="0,10,0,10">
        <TextBlock Text="Rotate on X Axis: " />
        <Slider Minimum="0"
                Maximum="360"
                x:Name="sliderX"
                Value=
              "{Binding ElementName=gridProjection, Mode=TwoWay, Path=RotationX}"
                Width="125" />
      </StackPanel>
      <StackPanel Orientation="Horizontal"
                  Margin="0,10,0,10">
        <TextBlock Text="Rotate on Y Axis: " />
        <Slider Minimum="0"
                Maximum="360"
                x:Name="sliderY"
                Value=
              "{Binding ElementName=gridProjection, Mode=TwoWay, Path=RotationY}"
                Width="125" />
      </StackPanel>
      <StackPanel Orientation="Horizontal"
                  Margin="0,10,0,10">
        <TextBlock Text="Rotate on Z Axis: " />
        <Slider Minimum="0"
                Maximum="360"
                x:Name="sliderZ"
                Value=
              "{Binding ElementName=gridProjection, Mode=TwoWay, Path=RotationZ}"
                Width="125" />
      </StackPanel>
    </StackPanel>
  </Grid>
</UserControl>

					  

As shown in Listing 1, the PlaneProjection named gridProjection projects the Grid to a 3-D plane. The PlaneProjection type exposes three properties, namely RotationX, RotationY and RotationZ, each of which can be independently set to an angle value between 0 and 360 degrees to rotate the Grid along that axis.

If you note the binding expression for the Value property of the Slider named sliderX, you will see that it is bound directly in a TwoWay mode to the RotationX property of gridProjection, utilizing the ElementName binding attribute. The range for sliderX is set to vary between 0 and 360, and changing this value will cause gridProjection to rotate along the X axis by that amount. The other two Sliders, sliderY and sliderZ, follow a similar arrangement to affect the RotationY and RotationZ properties of the gridProjection element.

Listing 2 shows the codebehind for the RotatorDemoControl.

Listing 2. Codebehind for RotatorDemoControl
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;

namespace Recipe4_5
{
  public partial class RotatorDemoControl : UserControl, INotifyPropertyChanged
  {
    public event PropertyChangedEventHandler PropertyChanged;

    public RotatorDemoControl()
    {
      InitializeComponent();

      sliderX.ValueChanged +=
        new RoutedPropertyChangedEventHandler<double>((s, e) =>
      {
        Xangle = sliderX.Value;
      });
      sliderY.ValueChanged +=
        new RoutedPropertyChangedEventHandler<double>((s, e) =>
      {
        Yangle = sliderY.Value;
      });
      sliderZ.ValueChanged +=
        new RoutedPropertyChangedEventHandler<double>((s, e) =>
      {
        Zangle = sliderZ.Value;
      });
    }

    private double _Xangle = default(double);

					  

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

      }
    }

    private double _Yangle = default(double);

    public double Yangle
    {
      get
      {
        return _Yangle;
      }

      set
      {
        if (value != _Yangle)
        {
          _Yangle = value;
          if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs("Yangle"));
        }

      }
    }

    private double _Zangle = default(double);
    public double Zangle
    {
      get
      {
        return _Zangle;

					  

}
      set
      {
        if (value != _Zangle)
        {
          _Zangle = value;
          if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs("Zangle"));
        }

      }
    }
  }

}

As Listing 2 shows, the RotatorDemoControl control class exposes three properties named Xangle, Yangle, and Zangle with property change notification enabled. These values are updated when the corresponding slider values are changed, as shown in the event handlers of the ValueChanged events of the Sliders, in the constructor of the RotatorDemoControl class.

If you refer to the RotatorDemoControl XAML in Listing 1, you will note that there are three TextBlocks inside the rotated Grid that are respectively bound to these properties. The intention is to display the angle values as the Grid is rotated. Looking at the binding statements for these TextBlocks, you will note that they simply provide the Binding.Path values pointing to the properties on RotatorDemoControl. But how do the bindings know to use the control class as its data source? Take a look at Listing 3 that shows the XAML for the MainPage, which actually declares the RotatorDemoControl user control.

Listing 3. XAML for MainPage
<UserControl x:Class="Recipe4_5.MainPage"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local="clr-namespace:Recipe4_5"
             Width="640"
             Height="480">
  <Grid x:Name="LayoutRoot"
        Background="White">
    <local:RotatorDemoControl
        DataContext="{Binding RelativeSource={RelativeSource Self}}" />
  </Grid>
</UserControl>

					  

Listing 3 shows that the DataContext for the RotatorDemoControl is bound to itself because the RelativeSource attribute is set to Self. This then sets the RotatorDemoControl instance as the data source for the TextBlock bindings referred to earlier and helps display the angle values as notified through the corresponding properties on the RotatorDemoControl class.

Other  
 
Top 10
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Finding containers and lists in Visio (part 2) - Wireframes,Legends
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Finding containers and lists in Visio (part 1) - Swimlanes
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Formatting and sizing lists
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Adding shapes to lists
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Sizing containers
- Microsoft Access 2010 : Control Properties and Why to Use Them (part 3) - The Other Properties of a Control
- Microsoft Access 2010 : Control Properties and Why to Use Them (part 2) - The Data Properties of a Control
- Microsoft Access 2010 : Control Properties and Why to Use Them (part 1) - The Format Properties of a Control
- Microsoft Access 2010 : Form Properties and Why Should You Use Them - Working with the Properties Window
- Microsoft Visio 2013 : Using the Organization Chart Wizard with new data
Video Sports
programming4us programming4us
programming4us
 
 
programming4us