DataRow中DataRowTemplate内部的WPF DataTable

5hcedyr0  于 2023-10-22  发布在  其他
关注(0)|答案(1)|浏览(126)

我正在寻找一个无限嵌套的DataGrid在DataRowTemplate。因此,当单击一个Row时,我希望显示另一个DataGrid等等。我的主类是“CustomTable”,它继承自BaseViewModel,该类提供了PropertyChanged事件来更新视图。
这是我的.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;
}

}
这是我的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>

我不知道为什么我的输出看起来像这样:

我从Infinite nested DataGrid data template得到了一些灵感,但那并不真的有帮助。我还不能发表评论,我不得不在这里寻求帮助。
我真的不明白问题出在哪里。谢谢你的帮助!!!

mwyxok5s

mwyxok5s1#

一个最小的可重复的例子是需要一个准确的答案。如果你能把它发布到GitHub上并提供一个链接,那将非常有帮助。这将使我们不局限于一般的话和建议,而是向您展示一个解决方案选项。
我将根据我对你发布的代码片段的分析得出的假设来写我的建议和评论。
1.主视图创建一个ItemsControl,它显示来自根CustomTableObservableCollection<DataTable> Main属性的表集合。至少需要从CustomTable中删除ContentControl TableCollection属性。这是一个Visual类,不应该在ViewModel中。此外,绑定到ContentControl.Conten属性的可视类会导致忽略数据模板。此行为内置于ContentControl逻辑中。

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>

测试结果:

1.这不是你需要的结果,但已经是“前进”了。每个ItemsControl行都应显示一个单独的DataTable。为了进行正确的测试,您需要在Main中放置至少两个DataTable。

public CustomTable()
        {
            Main = new ObservableCollection<DataTable>
            {
                someRandomTable(),
                someRandomTable()
            };
        }

测试结果:

1.我不能完全理解CustomTable.SelectedItem属性的含义。根据XAML,Main属性的表中的一行绑定到该属性。但是有很多这样的表,但只有一个属性用于绑定。如果选定的行位于多个表中,您希望出现什么行为?
在大多数实现中,集合的属性和其中选定的元素是同一级别的属性。因此,如果没有您的进一步澄清,我将无法给予一个适合您的准确答案。
1.我的实现选项基于我的猜测:

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>

结果

选择行之前:

在第一级中选择行后:

在第二级中选择行后:

相关问题