【问题标题】:Representing the first element of a list of list of list in DataGrid XAML表示 DataGrid XAML 中列表列表的第一个元素
【发布时间】:2020-05-21 00:16:04
【问题描述】:

我正在编写一个 C# WPF 应用程序,用户可以在其中将测试架中的样本条码到应用程序中。

机架由行组成。每行包含多个样本。

每个示例都可以有一个示例详细信息列表(每次用户进行更改时的标识符和日期时间)。

这里有一张图片可以更好地可视化它:Picture of Rack

我想在 DataGrid 中表示这一点,用户可以在其中编辑网格中的每个样本。

我发现 XAML 相当困难。我已经设法使用代码隐藏(见下文)实现了我想要的,但我想在 XAML 中做到这一点。这是picture of output

这可能吗?

谢谢

附加信息:

  • 列数和行数是用户定义的,并且会因机架而异
  • 行标题绑定到Row 类的RackPosition 属性
  • 列标题绑定到Sample 类的ColumnPosition
  • DataGridCell 内的文本绑定到History[0].Identifier
  • Caliburn Micro 将用于处理用户对样本的更新

我的代码:

类:

public class Rack
{
    public string Name { get; set; }
    public DateTime DateCreated { get; set; }
    public List<Row> Rows { get; set; } = new List <Row>();
}

public class Row
{
    public int RackPosition { get; set; }
    public string Name { get; set; }
    public List<Sample> Samples { get; set; } = new List <Sample>();
}

public class Sample
{
    public int ColumnPosition { get; set; }
    public List<SampleDetails> History { get; set; } = new List <SampleDetails>();
}

public class SampleDetails
{
    public string Identifier { get; set; }
    public DateTime TimeStamp { get; set; }
}

数据网格:

<DataGrid x:Name="MainDG" AutoGenerateColumns="False" CanUserAddRows="False">
    <DataGrid.RowHeaderStyle>
        <Style TargetType="{x:Type DataGridRowHeader}">
            <Setter Property="Content" Value="{Binding RackPosition}"/>
        </Style>
    </DataGrid.RowHeaderStyle>
</DataGrid>

代码背后:

public Rack CurrentRack { get; set; }

public MainWindow()
{
    InitializeComponent();
    SetupDataGrid();

}

//Gets a dummy rack
public Rack GetExampleRack()
{
    Rack rack = new Rack();
    for (int i = 0; i < 4; i++)
    {
        Row row = new Row();
        row.Samples = new List<Sample>();
        row.RackPosition = i;
        for (int j = 0; j < 5; j++)
        {
            row.Samples.Add(new Sample { ColumnPosition = j });
        }
        rack.Rows.Add(row);
    }
    SampleDetails testSample1 = new SampleDetails { Identifier = "Test ID 1", TimeStamp = DateTime.Now };
    SampleDetails testSample2 = new SampleDetails { Identifier = "Test ID 2", TimeStamp = DateTime.Now };
    rack.Rows[0].Samples[0].History.Add(testSample1);
    rack.Rows[1].Samples[3].History.Add(testSample2);
    return rack;
}

private void SetupDataGrid()
{
    MainDG.Columns.Clear();
    CurrentRack = GetExampleRack();

    foreach (var sample in CurrentRack.Rows[0].Samples)
    {
        var sampleIndex = CurrentRack.Rows[0].Samples.IndexOf(sample);

        DataGridTemplateColumn col = new DataGridTemplateColumn();
        col.Header = sampleIndex;

        FrameworkElementFactory textBox = new FrameworkElementFactory(typeof(TextBox));

        var binding = new Binding();
        binding.BindingGroupName = ".";
        binding.Path = new PropertyPath($"Samples[{sampleIndex}].History[0].Identifier");

        textBox.SetBinding(TextBox.TextProperty, binding);

        DataTemplate dt = new DataTemplate { VisualTree = textBox };
        dt.Seal();
        col.CellTemplate = dt;

        MainDG.Columns.Add(col);
    }
    MainDG.ItemsSource = CurrentRack.Rows;
}

【问题讨论】:

  • 为什么不使用multidimensional-arrays
  • 单个样品架中的所有行的样本数是否相等?
  • @Keith 是的。 Cfun 我会调查的。谢谢

标签: c# wpf xaml datagrid


【解决方案1】:

在花了一些时间考虑这个问题之后,我认为没有任何实用的方法可以在 XAML 中使用 DataGrid 来做到这一点。我真的不认为DataGrid 旨在以您需要的方式处理动态列 - 至少不是通过数据绑定自动处理。我也不知道有任何其他控件可以完成这项工作。

即使接受您必须使用 some 代码隐藏,我也无法挑选出您的代码中可以轻松替换为 XAML 的任何部分。

  • 没有比通过计算Row.Samples 来确定列数更好的方法了 - 即使您设计了一些可以在 XAML 中使用的组件,它最终还是会调用隐藏代码来执行此操作。李>
  • 我认为您至少可以在 XAML 中定义DataTemplate,但是因为您需要基于sampleIndex 动态绑定,所以您必须使用MultiBinding 之类的东西和自定义@987654327 @。虽然这样可行,但我认为它最终只会使代码更复杂 - 保持原样更简单。

我的另一个想法是完全放弃DataGrid。我考虑使用ItemsControl,其中行的ItemTemplate 包含另一个ItemsControl 用于显示单元格。然后您可以将主ItemsControl.ItemsSource 绑定到Rack.Rows 并将行级ItemsControl.ItemsSource 绑定到Row.Samples。这会自动为您生成所有单元格,但它会给您带来其他问题:

  • 必须在ItemsControl 之外创建列标题。
  • 除非每个单元格大小相同,否则它们不会排列。你几乎可以通过使用GridSharedSizeGroup 列来解决这个问题,但是Grid 不支持来自ItemsSource 的自动动态列,所以我们回到了从DataGrid 开始的地方。
  • 用户无法拖动列或行并调整其大小。

不胜枚举,在解决这些问题时,您基本上最终会重新创建 DataGrid 控件中已经存在的所有这些功能。

TL;DR:
我认为没有更好的、以 XAML 为中心的方式来做到这一点。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多