0

I want to bind an nested DataGrid (RowDetailsTemplate) to different data-object with resp. to the data-object for the outer DataGrid.

It works properly for the outer object "Outer", but how can I access the inner data object "Inner".

The xaml:

<Window.Resources>
    <local:MainWindowModel x:Key="vm"/>
</Window.Resources>
<Grid Name="grdMain" Height="170" VerticalAlignment="Top" DataContext="{Binding Source={StaticResource vm}}">
    <DataGrid x:Name="datagridOuter"
              ItemsSource="{Binding Outer}"
              AutoGenerateColumns="False"
              Height="170">
        <DataGrid.Columns>
            <DataGridTextColumn Header="Outer"
                                Binding="{Binding Path=Name}"
                                MinWidth="150"/>
        </DataGrid.Columns>
        <DataGrid.RowDetailsTemplate>
            <DataTemplate>
                <DataGrid Name="datagridInner"
                          ItemsSource="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Grid}}, Path=DataContext.Inner}"
                          Height="50"
                          AutoGenerateColumns="False"
                          IsReadOnly="True">
                    <DataGrid.Columns>
                        <DataGridTextColumn Header="Inner"
                                            Binding="{Binding Path=Name}"
                                            MinWidth="150"/>
                    </DataGrid.Columns>
                </DataGrid>
            </DataTemplate>
        </DataGrid.RowDetailsTemplate>
    </DataGrid>
</Grid>

The Item class:

public class Item
{
    public string Name { get; set; }

    public Item ( string name_ )
    {
        this.Name = name_;
    }
} //eoClass

The MainWindowModel class:

class MainWindowModel : Notifier
{
    public ObservableCollection<Item> outer;
    public ObservableCollection<Item> Outer
    {
        get { return this.outer; }
        set
        {
            this.outer = value;
            OnPropertyChanged ( "Outer" );
        }
    }

    public ObservableCollection<Item> inner;
    public ObservableCollection<Item> Inner
    {
        get { return this.inner; }
        set
        {
            this.inner = value;
            OnPropertyChanged ( "Inner" );
        }
    }
} //eoClass
3
  • I got a little bit stucked with what you are asking, because for me it looks like your model did not fit/represents your needs. Could it be possible that you want to bind some kind of ` Outer0 { Inner01, Inner02, Inner03 }, Outer1 { Inner11, Inner12, Inner13, ... } ...` instead of { Outer0, Outer1 } and { Inner01, Inner02, Inner03, Inner11, Inner12, Inner13, ... } Commented Oct 31, 2017 at 15:01
  • From the MainWindowModel view there is no coupling between the two collections Inner and Outer. The coupling is done in the underlaying datamodel. The "Inner" collection is updated in the underlaying datamodel so that the "Inner" collection corresponds to the actual seleted data of the "Outer" collection. My question is, how to apply the binding of the details-datagrid and the "Inner" collection. Commented Oct 31, 2017 at 17:59
  • Have you tested the first part of my Answer. Change the binding of the ItemSource to ItemsSource="{Binding ElementName=grdMain, Path=DataContext.Inner}" Commented Oct 31, 2017 at 18:20

1 Answer 1

0

Looking for an ancestor of the type Grid can be really annoying, because most controls containing some nested Grids. I personally try to avoid this.

For example when you look at the VisualLiveTree of your DataGrid you will find some occurrences:

The VisualLiveTree of your <code>DataGrid</code>

The reason why you did not get your binding, is that FindAncestor will start at your binding target and will search upward all parents in the VisualTree until it finds the first Grid. And your grdMain is probably the last in this chain.


So your are already had given your Grid a name, just so use it. Changing your inner ItemSource binding from:

ItemsSource="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Grid}}, Path=DataContext.Inner}"

to:

ItemsSource="{Binding ElementName=grdMain, Path=DataContext.Inner}"

will do the trick. It will look for the requested binding at the element specified with the name grdMain.


Based on your comment, I rolled back my answer, to fit your needs.

From the MainWindowModel view there is no coupling between the two collections Inner and Outer. The coupling is done in the underlaying datamodel. The "Inner" collection is updated in the underlaying datamodel so that the "Inner" collection corresponds to the actual seleted data of the "Outer" collection. My question is, how to apply the binding of the details-datagrid and the "Inner" collection.

Sign up to request clarification or add additional context in comments.

5 Comments

Your first solution fits my requirements. It works. I thought that I already had tried to address ElementName=grdMain, but most likely I have made other mistakes with binding parameters. You helped me get out of that circle. Besides: Outer collection is from database and Inner collection is received as measured signals from the process.
Forgot to mention for reader: Martin's first solution: <... ItemsSource="{Binding ElementName=grdMain, Path=DataContext.Inner}" ../>
@Ruebezaehler: I rolled back to my previous solution, to shorten things up. If my answer really fits your needs allow me to link you to: What should I do when someone answers my question?. If somebody wants to see my extended answer please look in the history and feel free to rollback the rollback.
Feel free to shorten/modify or link your answer. Can I do something for your reputation (voting)? If yes, could you please tell me where?
@Ruebezaehler: You can mark this as answer and/or vote if it really helps you but you are not committed to do this. Just take a look at: What should I do when someone answers my question? & Accepting Answers

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.