Search code examples
wpfxamlwpfdatagrid

Navigating between data in DataGrid WPF XAML


I have checkboxes that represent the modules in my program that a user can access.

You can see from the DataGrid that the modules in the fourth column are created from "DataContext.ModuleCollection", where as the rows for the DataGrid are created from UserCollection. I would like the User_ID to be the content for each checkbox. This will be set in the checkbox style which I have attempted at the bottom without much success.

My issue is, the checkbox is at Module level (in the data) and I need to figure a way to get back to the User level to get the User_ID.

User_ID is part of the row's dataset, e.g. a User record.

How do I get User_ID in the below style is the question?

enter image description here

Below is my datagrid:

<DataGrid  ItemsSource="{Binding UserCollection}" >
    <DataGrid.Columns>
        <DataGridTextColumn Header="Name" Binding="{Binding Path=Name}"/>
        <DataGridTextColumn Header="Job Title" Binding="{Binding Path=Job_Title}"/>
        <DataGridTextColumn Header="Company" Binding="{Binding Path=Company}"/>
        <DataGridTemplateColumn CanUserReorder="True">
            <DataGridTemplateColumn.Header>
                <ItemsControl ItemsSource="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}, Path=DataContext.ModuleCollection}" >
                    <ItemsControl.ItemsPanel>
                        <ItemsPanelTemplate>
                            <StackPanel Orientation="Horizontal" Background="Transparent" CanVerticallyScroll="False" CanHorizontallyScroll="False"></StackPanel>
                        </ItemsPanelTemplate>
                    </ItemsControl.ItemsPanel>
                    <ItemsControl.ItemTemplate>
                        <DataTemplate>
                            <TextBlock Style="{StaticResource ListViewItemRotatedText}" Text="{Binding ModuleName}" >
                            </TextBlock>
                        </DataTemplate>
                    </ItemsControl.ItemTemplate>
                </ItemsControl>
            </DataGridTemplateColumn.Header>
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <ItemsControl ItemsSource="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}, Path=DataContext.ModuleCollection}" >
                        <ItemsControl.ItemsPanel>
                            <ItemsPanelTemplate>
                                <StackPanel Orientation="Horizontal" Background="Transparent" CanVerticallyScroll="False" CanHorizontallyScroll="False"></StackPanel>
                            </ItemsPanelTemplate>
                        </ItemsControl.ItemsPanel>
                        <ItemsControl.ItemTemplate>
                            <DataTemplate>
                                <CheckBox Style="{StaticResource ListViewItemCheckbox}" />
                            </DataTemplate>
                        </ItemsControl.ItemTemplate>
                    </ItemsControl>
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>
    </DataGrid.Columns>
</DataGrid>

Below is my check style:

<Style x:Key="ListViewItemCheckbox" TargetType="CheckBox">
        <Setter Property="Content" Value="{Binding Path=User_ID, RelativeSource={RelativeSource AncestorType={x:Type DataGridRow}}}"/>
</Style>

Solution

  • Your current Binding Path won't work because you're trying to access the User_ID property from the DataGridRow, which of course, doesn't have one... you should have an error in your Output Window in Visual Studio... pay close attention to these errors, as they'll help you fix your problems.

    So what Binding Path can you use? Well, you're right as far as the fact that we have to use a RelativeSource Binding... try this instead:

    <Style x:Key="ListViewItemCheckbox" TargetType="CheckBox">
        <Setter Property="Content" Value="{Binding Path=DataContext.User_ID, 
            RelativeSource={RelativeSource AncestorType={x:Type DataGridRow}}}" />
    </Style>
    

    What we're attempting to do here is to data bind to the User_ID value that should be found in the object set as the DataContext of the DataGridRow.


    UPDATE >>>

    Ahhh yeah, what I was thinking wouldn't work anyway as I was trying to bind to the whole collection and you need to bind to the current item. You're only getting these horrible problems though because of the way that you've organised (or disorganised) your data model. Those CheckBoxes should be data bound from one or more properties that are actually in your User class and not in this separate collection. I'd fix your model now before you get worse problems.


    UPDATE 2 >>>

    You now want to know how to bind to the whole data object rather than a property from that object. For future reference, please see the PropertyPath XAML Syntax page on MSDN for more information. However, you just need to think about this... if DataContext.User_ID gets you the User_ID property value of a User object, what do you think would return the whole User object? That's right... just remove the property:

    <Style x:Key="ListViewItemCheckbox" TargetType="CheckBox">
        <Setter Property="Content" Value="{Binding Path=DataContext, 
            RelativeSource={RelativeSource AncestorType={x:Type DataGridRow}}}" />
    </Style>