i am looking for a infinite nested DataGrid in a DataRowTemplate. So, when clicking onto a Row, i want to have displayed another DataGrid and so on. My main class is "CustomTable" which inherits from BaseViewModel, that class provides the PropertyChanged Event to update the View.
this is my .cs:
public class CustomTable : BaseViewModel
{
private ObservableCollection<DataTable> _main;
public ObservableCollection<DataTable> Main
{
get
{
return _main;
}
set
{
_main = value;
RaisePropertyChanged();
}
}
private CustomTable _child;
public CustomTable Child
{
get
{
return _child;
}
set
{
_child = value;
RaisePropertyChanged();
}
}
private DataRowView _selectedItem;
public DataRowView SelectedItem
{
get
{
return _selectedItem;
}
set
{
_selectedItem = value;
Child = new CustomTable();
RaisePropertyChanged();
}
}
private ContentControl _tableCollection;
public ContentControl TableCollection
{
get
{
return _tableCollection;
}
set
{
_tableCollection = value;
RaisePropertyChanged();
}
}
public CustomTable()
{
Main = new ObservableCollection<DataTable>();
Main.Add(someRandomTable());
TableCollection = new ContentControl();
TableCollection.Content = Main;
}
private DataTable someRandomTable()
{
DataTable table = new DataTable();
table.Columns.Add("Dosage", typeof(int));
table.Columns.Add("Drug", typeof(string));
table.Columns.Add("Patient", typeof(string));
table.Columns.Add("Date", typeof(DateTime));
table.Rows.Add(25, "Indocin", "David", DateTime.Now);
table.Rows.Add(50, "Enebrel", "Sam", DateTime.Now);
table.Rows.Add(10, "Hydralazine", "Christoff", DateTime.Now);
table.Rows.Add(21, "Combivent", "Janet", DateTime.Now);
table.Rows.Add(100, "Dilantin", "Melanie", DateTime.Now);
table.Rows.Add(53, "ACC", "Foobar", DateTime.Now);
return table;
}
}
and this is my xaml:
<Window.DataContext>
<local:CustomTable/>
</Window.DataContext>
<Window.Resources>
<DataTemplate x:Key="Nested">
<ItemsControl ItemsSource="{Binding DataContext.Tables, RelativeSource={RelativeSource AncestorType=DataGrid, Mode=FindAncestor}}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<DataGrid CanUserAddRows="False" RowDetailsTemplate="{DynamicResource Nested}" ItemsSource="{Binding Main}" AutoGenerateColumns="True" >
</DataGrid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</DataTemplate>
</Window.Resources>
<ScrollViewer>
<ScrollViewer.Resources>
<DataTemplate DataType="{x:Type local:CustomTable}">
<StackPanel>
<ItemsControl ItemsSource="{Binding Path=Main}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<DataGrid SelectedItem="{Binding SelectedItem, Mode=TwoWay, RelativeSource={RelativeSource FindAncestor,AncestorType=ItemsControl}}"
CanUserAddRows="False" ItemsSource="{Binding}" AutoGenerateColumns="True" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<Expander Header="Child" Margin="10" IsExpanded="True" x:Name="child">
<ContentControl Content="{Binding Child}"/>
</Expander>
</StackPanel>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding Child}" Value="{x:Null}">
<Setter TargetName="child" Property="Visibility" Value="Collapsed"/>
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</ScrollViewer.Resources>
<ContentControl Content="{Binding TableCollection}"/>
</ScrollViewer>
i can not figure out why my output looks like this:
i got some inspiration from Infinite nested DataGrid data template but that does'nt really help. i can not comment yet and am forced to ask here for help.
i dont really understand where the problem is. thanks for your help!!!
A minimal reproducible example is required for an accurate answer. It would be very helpful if you could post it on GitHub and provide a link to it. This would allow us not to limit ourselves to general words and advice, but to show you a solution option.
I will write my advice and comments based on my assumptions obtained from the analysis of the code fragments you posted.
ObservableCollection<DataTable> Main
property of the root CustomTable
.
At a minimum, you need to remove the ContentControl TableCollection
property from the CustomTable
. This is a Visual class and should not be in the ViewModel. In addition, binding to the visual class of the ContentControl.Conten
property causes Data Templates to be ignored. This behavior is built into the ContentControl
logic. public class CustomTable : BaseViewModel
{
//private ObservableCollection<DataTable> _main;
public ObservableCollection<DataTable> Main { get; }
//{
// get
// {
// return _main;
// }
// set
// {
// _main = value;
// RaisePropertyChanged();
// }
//}
private CustomTable? _child;
public CustomTable? Child
{
get
{
return _child;
}
set
{
_child = value;
RaisePropertyChanged();
}
}
private DataRowView? _selectedItem;
public DataRowView? SelectedItem
{
get
{
return _selectedItem;
}
set
{
_selectedItem = value;
Child ??= new CustomTable();
RaisePropertyChanged();
}
}
//private ContentControl? _tableCollection;
//public ContentControl? TableCollection
//{
// get
// {
// return _tableCollection;
// }
// set
// {
// _tableCollection = value;
// RaisePropertyChanged();
// }
//}
public CustomTable()
{
Main = new ObservableCollection<DataTable>
{
someRandomTable()
};
//TableCollection = new ContentControl();
//TableCollection.Content = Main;
}
private DataTable someRandomTable()
{
DataTable table = new DataTable();
table.Columns.Add("Dosage", typeof(int));
table.Columns.Add("Drug", typeof(string));
table.Columns.Add("Patient", typeof(string));
table.Columns.Add("Date", typeof(DateTime));
table.Rows.Add(25, "Indocin", "David", DateTime.Now);
table.Rows.Add(50, "Enebrel", "Sam", DateTime.Now);
table.Rows.Add(10, "Hydralazine", "Christoff", DateTime.Now);
table.Rows.Add(21, "Combivent", "Janet", DateTime.Now);
table.Rows.Add(100, "Dilantin", "Melanie", DateTime.Now);
table.Rows.Add(53, "ACC", "Foobar", DateTime.Now);
return table;
}
}
</ScrollViewer.Resources>
<ContentControl Content="{Binding}"/>
</ScrollViewer>
public CustomTable()
{
Main = new ObservableCollection<DataTable>
{
someRandomTable(),
someRandomTable()
};
}
CustomTable.SelectedItem
property. According to XAML, a row from one of the tables of the Main
property is bound to this property. But there are many of these tables, but there is only one property for binding. What behavior do you expect if the selected rows are in multiple tables?In most implementations, the properties of a collection and the element selected in it are properties of the same level. Therefore, without your additional clarification, I will could not give an accurate answer suitable for you.
using System;
using System.Collections.ObjectModel;
using System.Data;
namespace Core2023.SO.niconice.InfiniteDataGrid
{
public class CustomTable : BaseViewModel
{
public ObservableCollection<DataTable> Main { get; }
private CustomTable? _child;
public CustomTable? Child
{
get
{
return _child;
}
set
{
_child = value;
RaisePropertyChanged();
}
}
private DataRowView? _selectedItem;
public DataRowView? SelectedItem
{
get
{
return _selectedItem;
}
set
{
_selectedItem = value;
Child ??= new CustomTable();
RaisePropertyChanged();
}
}
public CustomTable()
{
Main = new ObservableCollection<DataTable>
{
someRandomTable(),
someRandomTable()
};
}
private static DataTable someRandomTable()
{
DataTable table = new DataTable();
table.Columns.Add("Dosage", typeof(int));
table.Columns.Add("Drug", typeof(string));
table.Columns.Add("Patient", typeof(string));
table.Columns.Add("Date", typeof(DateTime));
table.Rows.Add(25, "Indocin", "David", DateTime.Now);
table.Rows.Add(50, "Enebrel", "Sam", DateTime.Now);
table.Rows.Add(10, "Hydralazine", "Christoff", DateTime.Now);
table.Rows.Add(21, "Combivent", "Janet", DateTime.Now);
table.Rows.Add(100, "Dilantin", "Melanie", DateTime.Now);
table.Rows.Add(53, "ACC", "Foobar", DateTime.Now);
return table;
}
}
}
<Window x:Class="Core2023.SO.niconice.InfiniteDataGrid.InfiniteDataGridWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Core2023.SO.niconice.InfiniteDataGrid"
mc:Ignorable="d"
Title="InfiniteDataGridWindow" Height="1000" Width="400">
<Window.DataContext>
<local:CustomTable/>
</Window.DataContext>
<Window.Resources>
<DataTemplate x:Key="Nested">
<ItemsControl ItemsSource="{Binding DataContext.Tables, RelativeSource={RelativeSource AncestorType=DataGrid, Mode=FindAncestor}}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<DataGrid CanUserAddRows="False" RowDetailsTemplate="{DynamicResource Nested}" ItemsSource="{Binding Main}" AutoGenerateColumns="True" >
</DataGrid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</DataTemplate>
</Window.Resources>
<ScrollViewer>
<ScrollViewer.Resources>
<DataTemplate DataType="{x:Type local:CustomTable}">
<StackPanel>
<ItemsControl x:Name="Main_ItemsControl" ItemsSource="{Binding Path=Main}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<DataGrid SelectedItem="{Binding DataContext.SelectedItem, Mode=TwoWay, ElementName=Main_ItemsControl}"
CanUserAddRows="False" ItemsSource="{Binding}" AutoGenerateColumns="True" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<Expander Header="Child" Margin="10" IsExpanded="True" x:Name="child">
<ContentControl Content="{Binding Child}"/>
</Expander>
</StackPanel>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding Child}" Value="{x:Null}">
<Setter TargetName="child" Property="Visibility" Value="Collapsed"/>
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</ScrollViewer.Resources>
<ContentControl Content="{Binding}"/>
</ScrollViewer>
</Window>
Results.
Before selecting a row: