• Binding to View Model properties in Data Templates. The RootBinding Markup Extension

    Published by on June 26th, 2011 2:39 pm under Data Binding, Emerging Technology, Markup Extensions, MVVM, Silverlight, Silverlight 5

    4 Comments

    If you work with Silverlight and MVVM, you must have probably been forced to do some weird thing to bind to a property in your view model (say a Command) from a DataTemplate. Some of the common approaches I have seen and used myself are:

    • Using some kind of binding helper as a View’s resource.
    • Having a View Model wrap the entity of each collection item, and add the command to the View Model.

    Although these are perfectly valid approaches, they require extra work compared to the good old {Binding} syntax we are all used to.

    Now that Silverlight 5 Beta is out, we can take advantage of the XAML Markup Extensions to help is in this kind of tasks, using a simpler and more intuitive approach.

    I have created a RootBindingExtension, which can be used as follows:

    <Grid x:Name="LayoutRoot" Background="White">
        <ListBox ItemsSource="{Binding Names}">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <StackPanel Orientation="Horizontal">
                        <TextBlock Text="{Binding}"/>
                        <Button Content="{current:RootBinding Path=ButtonContent}" Command="{current:RootBinding Path=MessageBoxCommand}"/>
                    </StackPanel>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
    </Grid>

    The RootBindingExtension uses the Path property to create a Binding that binds to a property of that name in the View’s DataContext.

    public class RootBindingExtension : IMarkupExtension<Binding>
    {
        public string Path { get; set; }
        
        public Binding ProvideValue(IServiceProvider serviceProvider)
        {
            IRootObjectProvider rootProvider = (IRootObjectProvider) serviceProvider.GetService(typeof(IRootObjectProvider));
    
            var view = rootProvider.RootObject;
            var fe = view as FrameworkElement;
    
            if (fe == null)
            {
                throw new InvalidOperationException("Root element must have data context");
            }
    
            var binding = new Binding();
            binding.Path = new PropertyPath(this.Path);
            binding.Source = fe.DataContext;
    
            return binding;
        }
    }

    You can download the RootBindingExtension and a sample that uses it from here.

    Let me know if you have used it.

    Shout it

    Tags: , , , , ,

Archives

Categories