Search code examples
c#wpfdata-binding

Binding Tag property of checkbox to ancestor datacontext


I know this is a frequently question but after viewing lots of question in this context i still did not find working solution.

I have this MainWindow

public partial class MainWindow : Window
{
    public ObservableCollection<Camera> Cameras { get; set; } = new ObservableCollection<Camera>();
    public ObservableCollection<Group> Groups { get; set; } = new ObservableCollection<Group>();

    public MainWindow()
    {
        InitializeComponent();
        DataContext = this;
    }
}

And this class

public class Group : INotifyPropertyChanged
{
    private int _number;
    [XmlAttribute("Number")]
    public int Number
    {
        get { return _number; }
        set
        {
            _number = value;
            OnPropertyChanged();
        }
    }
    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

This is part of the MainWindow.xaml (the relevant part)

<StackPanel>

    <Button Click="Button_Click_1" Margin="55,0,0,0" Padding="4">Add Group</Button>
    <ListView Grid.ColumnSpan="3" Grid.Row="1" ItemsSource="{Binding Groups,Mode=TwoWay}">
        <ListView.ItemTemplate>
            <DataTemplate>
                <Grid>
                    <TextBlock Margin="3" Width="30" Grid.Column="0" Text="{Binding Number}"></TextBlock>
                    <ComboBox Margin="3" Width="50" Grid.Column="5" ItemsSource="{Binding DataContext.Cameras, RelativeSource={RelativeSource AncestorType=ListView}}">
                        <ComboBox.ItemTemplate>
                            <DataTemplate>
                                <StackPanel Orientation="Horizontal">
                                    <CheckBox Width="20" VerticalAlignment="Center" Tag="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListView}}, Path=DataContext.Number}" Checked="OnCbObjectCheckBoxChecked" Unchecked="OnCbObjectCheckBoxChecked" />
                                    <!--<CheckBox Width="20" VerticalAlignment="Center" Tag="{Binding Path=DataContext.Number, RelativeSource={RelativeSource AncestorType=ListView}}" Checked="OnCbObjectCheckBoxChecked" Unchecked="OnCbObjectCheckBoxChecked" />-->
                                    <TextBlock Text="{Binding Path=Name, Mode=TwoWay}"></TextBlock>
                                </StackPanel>
                            </DataTemplate>
                        </ComboBox.ItemTemplate>
                    </ComboBox>
                </Grid>
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>
    
    
</StackPanel>

The list of checkbox inside the comboxbox will be filled according to the list of the cameras. I want to bind the property "Tag" of the inner checkbox to the member Groups.Number like i did with the textblock above it. The reason behind this (maybe you have another solution) is that the list of groups is a dynamic group, and i want to identify from which group the checkbox was checked. I've tried everything with the ancestor issue but nothing seems to work. other things i've tried are:

                                        <CheckBox Width="20" VerticalAlignment="Center" Tag="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListView}}, Path=DataContext.Number}" Checked="OnCbObjectCheckBoxChecked" Unchecked="OnCbObjectCheckBoxChecked" />
                                    <CheckBox Width="20" VerticalAlignment="Center" Tag="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListView}}, Path=DataContext.Groups.Number}" Checked="OnCbObjectCheckBoxChecked" Unchecked="OnCbObjectCheckBoxChecked" />
                                    <CheckBox Width="20" VerticalAlignment="Center" Tag="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListView}}, Path=Number}" Checked="OnCbObjectCheckBoxChecked" Unchecked="OnCbObjectCheckBoxChecked" />
                                    <CheckBox Width="20" VerticalAlignment="Center" Tag="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListView}}, Path=Groups.Number}" Checked="OnCbObjectCheckBoxChecked" Unchecked="OnCbObjectCheckBoxChecked" />

What do i miss here? Ty!


Solution

  • ListView has the wron DataContext. It is outside the DataTemplate and is set to MainWindow. The DataTemplate that targets Group has the proper DataContext, of course the current Group item. You must chose an element of this DataTemplate as binding source. You couls bind to the ComboBox.DataContext:

    <CheckBox Tag="{Binding RelativeSource={RelativeSource AncestorType=ComboBox}, Path=DataContext.Number}" />