【问题标题】:Infinite nested DataGrid data template无限嵌套 DataGrid 数据模板
【发布时间】:2014-07-05 12:00:39
【问题描述】:

我正在开发一个基于 MVVM 的 wpf 应用程序。我所做的只是尝试将嵌套的 DataGrids 与我的 DataTable 绑定。我有类 CustomTable

public class CustomTable : INotifyPropertyChanged
{
        public List<DataTable> Main { get; set; }
        public CustomTable Child { get; set; } 
        public DataRowView _selectedItem;
        public DataRowView SelectedItem
        {
            get
            {
                return _selectedItem;
            }
            set
            {
                _selectedItem = value;
                Child = new CustomTable();
                OnPropertyChanged("SelectedItem");
            }
        }  

        public CustomTable()
        {
            Main = new List<DataTable>();
            Main.Add(someRandomTable());

        }

        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);
            return table;
        }



        public event PropertyChangedEventHandler PropertyChanged;

        protected void OnPropertyChanged(string caller)
        {

            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(caller));
            }
        }

}

自定义表由 DataTables 列表 -> Main、SelectedItem 和 CustomTable 类型的子级组成。我正在为这个类实现 INotifyPropertyChanged。

所以我有 ItemsControl,其 DataContext 是此类,并且 ItemSource 绑定到 Main。我的 ItemControl.Template 由 DataGrid 组成。在成功运行时,它不会显示绑定到主列表中每个元素的 DataGrid。现在我将 DataGrid 的 SelectedItem 属性绑定到 CustomTable 的 SelectedItem 属性。我也能做到这一点。现在,当我选择一行并调用 customTable 的 SelectedItem 的设置器时,我正在创建其中包含预定义 Main 的 Child 的新实例(仅供示例,实际逻辑很复杂,与问题无关)。现在我想将我的 Child 绑定到我的 selectesRow 的 RowDetailsTemplate 以便显示嵌套的 dataGrids。这应该是递归的,单击 Child 的 DataGrid 中的一行也应该显示 Child->Child->Main。 我无法做到这一点,并在最近几天尝试没有任何进展。除此之外的任何其他方法也受到欢迎。

编辑

XAML 文件

<Window x:Class="HierDataGrid.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:tvcc="clr-namespace:HierDataGrid"
    Title="MainWindow" Height="350" Width="525" xmlns:metro="http://schemas.codeplex.com/elysium">
<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 DataContext="{Binding}">
    <StackPanel>

        <ItemsControl ItemsSource="{Binding Path=TableCollection.Main}">
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                    <DataGrid Name="dg" SelectedItem="{Binding SelectedItem, Mode=TwoWay}" CanUserAddRows="False" RowDetailsTemplate="{StaticResource Nested}"   ItemsSource="{Binding}" AutoGenerateColumns="True" >

                    </DataGrid>
                </DataTemplate>
        </ItemsControl.ItemTemplate>
        </ItemsControl>
    </StackPanel>
</ScrollViewer>

【问题讨论】:

  • TableCollectionCustomTable 类型吗?
  • 如果您还可以发布预期输出的图片,我们将不胜感激。

标签: c# wpf mvvm datagrid datatable


【解决方案1】:

我确实尝试根据一些假设制作递归模板

屏幕截图

我也对你的班级做了一些改变,实现的通知改为Child属性

    private CustomTable _child;
    public CustomTable Child
    {
        get
        {
            return _child;
        }
        set
        {
            _child = value;
            OnPropertyChanged("Child");
        }
    }

其他的可以根据需要做

xaml

<ScrollViewer>
    <ScrollViewer.Resources>
        <DataTemplate DataType="{x:Type l:CustomTable}">
            <StackPanel>
                <ItemsControl ItemsSource="{Binding Path=Main}">
                    <ItemsControl.ItemTemplate>
                        <DataTemplate>
                            <DataGrid SelectedItem="{Binding DataContext.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>

l: 在上面的例子中引用类 CustomTable 的名称空间,用这个替换你的 xaml。您也可以删除窗口资源中的模板。

我也重组了模板

  • 删除了命名模板并为CustomTable 创建了一个数据模板。
  • 使用ContentControl 绑定到TableCollection,WPF 将解析我们定义的相同模板。
  • 同样适用于绑定到ChildDataTemplate 中的ContentControl

所以这将创建一个递归模板,如屏幕截图所示

您可以根据需要调整模板。请询问您是否需要任何澄清。

行级子级

xaml

<ScrollViewer>
    <ScrollViewer.Resources>
        <DataTemplate DataType="{x:Type l:CustomTable}">
            <StackPanel>
                <ItemsControl ItemsSource="{Binding Path=Main}">
                    <ItemsControl.ItemTemplate>
                        <DataTemplate>
                            <DataGrid Name="dg" SelectedItem="{Binding DataContext.SelectedItem, Mode=TwoWay, RelativeSource={RelativeSource FindAncestor,AncestorType=ItemsControl}}"
                                  CanUserAddRows="False"  ItemsSource="{Binding}" AutoGenerateColumns="True" >
                                <DataGrid.RowDetailsTemplate>
                                    <DataTemplate>
                                        <ContentControl Margin="10"
                                                        Content="{Binding DataContext.Child, RelativeSource={RelativeSource FindAncestor,AncestorType=ItemsControl,AncestorLevel=2}}"/>
                                    </DataTemplate>
                                </DataGrid.RowDetailsTemplate>
                            </DataGrid>
                        </DataTemplate>
                    </ItemsControl.ItemTemplate>
                </ItemsControl>
            </StackPanel>
        </DataTemplate>
    </ScrollViewer.Resources>

    <ContentControl Content="{Binding TableCollection}"/>

</ScrollViewer>

结果

【讨论】:

  • 非常感谢。您的解决方案效果很好,但是您能否建议我如何在 RowDetailsTemplate 中显示孩子,以便每个孩子都直接位于父行下方。非常感谢,非常感谢您的帮助。
  • 在这种情况下,您可能需要重组数据类。目前自定义表中有很多行,只有一个孩子。您需要具有与您希望看到或期望的完全相同的结构。例如,每行一个孩子。
  • 我根据我的假设从当前结构中添加了一个样本。
  • 这就是为什么我在 setter 中设置我孩子的值而不是重新定义它的原因。我的方法是当用户单击一行时-> 将调用 SelectedItem 的 Setter-> 在 setter 中根据单击的行定义子项。
  • 非常感谢。这就是我想要的。 :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-12-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-06-01
  • 2019-10-28
  • 1970-01-01
相关资源
最近更新 更多