views:

123

answers:

3

I have a WPF ListView with a collection of RadioButtons. I want to set the GroupName of the child controls to be bound to a property on the parent data context. At the moment I am doing this by duplicating the property in each of the children's data context but that can't be right.

My XAML:

 <ListView ItemsSource="{Binding OptionItems}" >
     <ListView.ItemTemplate>
         <DataTemplate DataType="{x:Type Logging:FilterOptionsRadioListViewModel}">
            <RadioButton GroupName="{Binding GroupName}" Content="{Binding Option.Value}" Tag="{Binding Option.Key}" IsChecked="{Binding IsChecked}" Command="Logging:FilterOptionsRadioListViewModel.CheckedChangedCommand" />
         </DataTemplate>
     </ListView.ItemTemplate>
 </ListView>

GroupName is a property on the parent View Model. I currently pass this onto the child View Model (where it is also a property) in the child constructor:

var item = new FilterOptionsRadioListItemViewModel(option, this.GroupName);

What is the correct way of doing this?

A: 

You certainly can do that, but if you don't want to have to copy the GroupName to every child Option instance, you could instead do something like the following

// I'm imagining your viewmodels look something like this
public class ParentViewModel
{
    private ObservableCollection<Option> m_OptionItems;
    public ObservableCollection<Option> OptionItems
    {
        get { return m_OptionItems; }
        set { m_OptionItems = value; }
    }

    private string m_ParentGroupName;
    public string ParentGroupName
    {
        get { return m_ParentGroupName; }
        set
        {
            m_ParentGroupName = value;
        }
    }


}

public class Option
{
    private string m_Value;
    public string Value
    {
        get { return m_Value; }
        set
        {
            m_Value = value;
        }
    }



}

Then you can use a relative binding so you can look up the control tree to find the right datacontext, so you don't have to copy the ParentGroupName to each child Option instance.

viggity
Thanks, viggity, that is how my view models look but it is the relative binding to access the parent property that has me stumped. I have been looking at examples using RelativeSource and FindAncestor but all the examples I could find were more complicated that this simple requirement. I don't need to browse a hierarchy, it is only the immediate ancestor I need to find. Isn't there a simple way to just bind to one step up in the XAML?
Val M
Unfortunately there is no way to go one level up, it would be really nice though :)
viggity
A: 

If you name your window, you can traverse the root DataContext.

<Window x:Class="MyNamespace.MainWindow"
        Name="Window"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
        Title="MainWindow" Height="500" Width="725">

<ListView ItemsSource="{Binding OptionItems}" >
     <ListView.ItemTemplate>
         <DataTemplate DataType="{x:Type Logging:FilterOptionsRadioListViewModel}">
            <RadioButton GroupName="{Binding ElementName=Window, Path=DataContext.ParentGroupName}" Content="{Binding Option.Value}" Tag="{Binding Option.Key}" IsChecked="{Binding IsChecked}" Command="Logging:FilterOptionsRadioListViewModel.CheckedChangedCommand" />
         </DataTemplate>
     </ListView.ItemTemplate>
 </ListView>
Daniel Auger
Thanks, Daniel. Would this would mean that the property ParentGroupName would need to be unique to the controls within the window? I have now used the RelativeSource binding to find the property on the parent and that is working perfectly.
Val M
A: 
 <ListView ItemsSource="{Binding OptionItems}" >
     <ListView.ItemTemplate>
         <DataTemplate DataType="{x:Type Logging:FilterOptionsRadioListViewModel}">
            <RadioButton GroupName="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListView}}, Path=DataContext.GroupName}" Content="{Binding Option.Value}" Tag="{Binding Option.Key}" IsChecked="{Binding IsChecked}" Command="Logging:FilterOptionsRadioListViewModel.CheckedChangedCommand" />
         </DataTemplate>
     </ListView.ItemTemplate>
 </ListView>
John Bowen
Thanks, John. This is what I am doing now. It had seemed to me an overly complicated way of doing things but of course isn't once you break it down. It works perfectly now.
Val M