A common situation I run into is the need to access some element within a DataTemplate. Silverlight isn't able to auto-generate strongly typed references to these elements in code behind. In other words, adding the "x:Name=myElementName" property to the element doesn't matter from a code-behind standpoint. However, we can use the x:Name in a different way to access our element at the right moment. Enter: Element-To-Element databinding. I think many of us know how to bind to property of another element, but it is also possible to bind to the element itself.
The scenario:
In one of my mini-projects, I have a Button which represents the bound Fill color of an element, like so:
- <form:DataForm.EditTemplate>
- <DataTemplate>
- <form:DataField>
- <Grid>
- <Button Click="Button_Click" Tag="{Binding ElementName=popupColorPicker}">
- <Button.Content>
- <StackPanel Orientation="Horizontal">
- <Rectangle Width="20" Height="20" Fill="{Binding Fill}"></Rectangle>
- <TextBlock Margin="5,0,0,0" Text="Background..."></TextBlock>
- </StackPanel>
- </Button.Content>
- </Button>
- <Popup x:Name="popupColorPicker" >
- <Border BorderBrush="Black" BorderThickness="1">
- <StackPanel>
- <Controls:ColorPicker SelectedColorChanging="ColorPicker_SelectedColorChanging" SelectedColor="{Binding Fill, Mode=TwoWay, Converter={StaticResource SolidColorBrushToColorConverterResource}}">
- </Controls:ColorPicker>
- <Button Content="Finished" Click="Button_Click" Tag="{Binding ElementName=popupColorPicker}"></Button>
- </StackPanel>
- </Border>
- </Popup>
- </Grid>
- </form:DataField>
- </DataTemplate>
- </form:DataForm.EditTemplate>
So in the Xaml snip above, we have a DataForm Template, which is bound a CLR view model (using MVVM Pattern). Inside the form, we have our DataField, which in turn has a DataTemplate;.Inside the DataTemplate is where we put our UI Xaml, along with any needed bindings. In this case we have a Button, which contains a Rectangle bound to the same Fill color as the Element we are current editing in Xamla. Pretty standard stuff so far. However, notice that below the button we have a Popup control. When the user clicks on the button, we want this Popup to become visible and display the color picker control within, along with a button so the user can signal us when the color choosing action is complete.
The Problem:
When the user clicks on the button to open the popup, how do we reference the Popup to set it's "IsOpen" property? The more difficult route would be to manually crawl the Xaml tree. This is time consuming and messy.
The Solution:
Using Silverlight 3's new support for Element-To-Element binding (notice the syntax in the Xaml above), we can place a reference to the <Popup> control in each of our Button's "Tag" properties, which will easily allow us to cast "Tag" to Popup in code-behind:
- private void Button_Click(object sender, RoutedEventArgs e)
- {
- //toggle the pop up visibility
- var p = (Popup)((Button)sender).Tag;
- p.IsOpen = p.IsOpen ? false : true;
- }
As you can see, now it is simply a matter of casting correctly and then setting the property of Popup.IsOpen. In my case I'm simply toggling it since I know that each button will toggle to the correct state of the Popup.