代表DataGrid XAML中列表列表的第一个元素

问题描述 投票:0回答:1

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

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

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

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

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

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

这可能吗?

谢谢

附加信息:

  • 列和行的数量是用户定义的,并且在机架之间会有所不同
  • 行标题绑定到RackPosition类的Row属性
  • 列标题绑定到ColumnPosition类的Sample
  • 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:

<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;
}
c# wpf xaml datagrid
1个回答
0
投票

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

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

  • [确定列数没有比计数DataGrid更好的方法了-即使您设计了一些可以在XAML中使用的组件,它最终还是会调用后台代码来完成此操作。
  • 我以为您至少可以在XAML中定义Row.Samples,但是由于您需要基于DataTemplate动态绑定,因此您必须使用带有自定义sampleIndex的类似MultiBinding的东西。尽管这行得通,但我认为它最终只会使代码变得更复杂-仅保留它就更简单了。

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

  • [列标题必须在Row.Samples之外创建。
  • 除非每个单元格都相同,否则它们不会对齐。您可以通过将ItemsControlGrid列一起使用来解决此问题,但是SharedSizeGroup不支持来自Grid的自动动态列,因此我们回到了从ItemsSource开始的地方。 >
  • 用户将无法拖动并调整列或行的大小。
  • 清单继续,解决这些问题,您基本上将最终重新创建DataGrid控件中已经存在的所有这些功能。

TL; DR:我认为没有更好的以XAML为中心的方法。

热门问题
推荐问题
最新问题