Thursday, May 26, 2011

Silverlight 4 - Bind to a property in the level of parent or Ancestor

In Silverlight, most of us will use the MVVM pattern for which we will create a ViewModel and bind it to the respective View.

In such cases, there might arise a scenario in which we need to bind a property for an element or control which is embeded inside another control. Let us take a real case scenario in order to understand the problem clearer.
Consider that our ViewModel contains two properties (CustomCollection, ButtonVisibility) of which one of type ObservableCollection(CustomCollection) and other one of type Visibility(ButtonVisibility).

Now in the View, first we need to bind the ObservableCollection to a ListBox as follows.

Snippet 1

<Grid x:Name="LayoutRoot" Background="White">
    <ListBox ItemsSource="{Binding Path=CustomCollection}">
        <ListBox.ItemTemplate>
            <DataTemplate>
                <StackPanel>
                    <TextBlock Text="{Binding Path=CustomName}" />
                    <Button Content="Sample Button"></Button>
                </StackPanel>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>    
</Grid>

Then if i want to set the ButtonVisibility property to the button control inside the DataTemplate of the ListBox, then there should be some way to specify that the property belongs to the ancestor and not the current. Unfortunately we can't directly specify this in Silverlight 4.

In order to achieve this we can do an alternate by using ElementName property of Binding. In MVVM, we will be assigning the ViewModel's instance to the View's DataContext. Hence any root level elemnt can be made use. In our case I'll take the "LayoutRoot" element(which is created by default).

Snippet 2

<Grid x:Name="LayoutRoot" Background="White">
    <ListBox ItemsSource="{Binding Path=CustomCollection}">
        <ListBox.ItemTemplate>
            <DataTemplate>
                <StackPanel>
                    <TextBlock Text="{Binding Path=CustomName}" />
                    <Button Content="Sample Button" Visibility="{Binding Path=DataContext.ButtonVisibility, ElementName=LayoutRoot}"></Button>
                </StackPanel>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>
</Grid>

You can use any valid element name with relevant DataContext you need for the property to bind.

No comments:

Post a Comment

Creative Commons License
This work by Tito is licensed under a Creative Commons Attribution 3.0 Unported License.