DataGrid 行无法在 WPF 中显示不同的值

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

我想在我的 WPF 应用程序中创建一个具有 2 行和 14 列的 DataGrid。我定义了一种在运行时创建此数据网格的方法。

我面临的问题是两行显示相同的文本。

Screenshot

如附图所示,两行都显示从 C01 到 C14 的车厢号码。但是,我希望第一行保持原样,第二行显示从 C15 到 C28 的车厢编号。

我目前使用的方法是:

private void CreateCoachCompositionDataGrid()
{
    // Clear the existing columns in the data grid
    dataGridCoachComposition.Columns.Clear();

    // Set the margin for the data grid
    dataGridCoachComposition.Margin = new Thickness(16, 468, 230, 18);

    // Hide the column headers
    dataGridCoachComposition.HeadersVisibility = DataGridHeadersVisibility.None;

    // Set the row height
    dataGridCoachComposition.RowHeight = 50; // Set this to your desired row height

    // Set the vertical alignment to top to remove empty space at the bottom
    dataGridCoachComposition.VerticalAlignment = VerticalAlignment.Top;

    // Create 14 columns
    for (int i = 1; i <= 14; i++)
    {
        // Create a new DataGridTemplateColumn
        DataGridTemplateColumn column = new DataGridTemplateColumn();
        column.Width = new DataGridLength(1, DataGridLengthUnitType.Star); // Set the column width to fill the available space

        // Create a DataTemplate for the cell template
        DataTemplate cellTemplate = new DataTemplate();

        // Create a StackPanel to hold the TextBlock and ComboBox
        FrameworkElementFactory stackPanel = new FrameworkElementFactory(typeof(StackPanel));
        stackPanel.SetValue(StackPanel.OrientationProperty, Orientation.Vertical);

        // Create a TextBlock for the coach number
        FrameworkElementFactory textBlock = new FrameworkElementFactory(typeof(TextBlock));
        textBlock.SetValue(TextBlock.TextProperty, "C" + i.ToString("00"));
        textBlock.SetValue(TextBlock.HorizontalAlignmentProperty, HorizontalAlignment.Center); // Center the text block horizontally
        stackPanel.AppendChild(textBlock);

        // Create a ComboBox for the coach type
        FrameworkElementFactory comboBox = new FrameworkElementFactory(typeof(ComboBox));
        comboBox.SetValue(ComboBox.ItemsSourceProperty, new string[] { "ENG", "HIN" });
        comboBox.SetValue(FrameworkElement.MarginProperty, new Thickness(5)); // Set a margin around the ComboBox
        stackPanel.AppendChild(comboBox);

        // Set the cell template's visual tree to the StackPanel
        cellTemplate.VisualTree = stackPanel;

        // Set the column's cell template
        column.CellTemplate = cellTemplate;

        // Add the column to the data grid
        dataGridCoachComposition.Columns.Add(column);
    }

    // Add two empty rows to the data grid
    dataGridCoachComposition.Items.Add(new object());
    dataGridCoachComposition.Items.Add(new object());
}

我尝试过这样的事情:

// Adjust the labels for each cell
    for (int i = 0; i < 14; i++)
    {
        ((TextBlock)((StackPanel)dataGridCoachComposition.Columns[i].GetCellContent(dataGridCoachComposition.Items[0])).Children[0]).Text = "C" + (i + 1).ToString("00");
        ((TextBlock)((StackPanel)dataGridCoachComposition.Columns[i].GetCellContent(dataGridCoachComposition.Items[1])).Children[0]).Text = "C" + (i + 15).ToString("00");
    }

但是,这引发了 NullReferenceException。为了解决这个问题,我尝试使用 Dispatcher 类来安排代码的执行。

错误仍然存在。

更新:通过创建数据表尝试了不同的方法。

我的XAML代码:

<DataTemplate x:Key="ComboBoxTemplate">
    <StackPanel>
        <TextBlock Text="{Binding}" />
        <ComboBox Margin="5">
            <ComboBoxItem>ENG</ComboBoxItem>
            <ComboBoxItem>HIN</ComboBoxItem>
        </ComboBox>
    </StackPanel>
</DataTemplate>

<DataGrid x:Name="dataGridCoachComposition" AutoGenerateColumns="True" CanUserAddRows="False" HeadersVisibility="None" Margin="16,468,14,0" VerticalAlignment="Top" RowHeight="50" ColumnWidth="*"/>

我的SetupDataGrid()方法:

private void SetupDataGrid()
{
    DataTable dataTable = new DataTable();

    // Define 14 columns
    for (int i = 1; i <= 14; i++)
    {
        dataTable.Columns.Add($"C{i:D2}");
    }

    // Add two rows of data
    string[] firstRow = new string[14];
    string[] secondRow = new string[14];

    for (int i = 0; i < 14; i++)
    {
        firstRow[i] = $"C{i + 1:D2}";
        secondRow[i] = $"C{i + 15:D2}";
    }

    dataTable.Rows.Add(firstRow);
    dataTable.Rows.Add(secondRow);

    // Bind the DataTable to the DataGrid
    dataGridCoachComposition.ItemsSource = dataTable.DefaultView;

    // Clear auto generated columns
    dataGridCoachComposition.AutoGenerateColumns = false;
    dataGridCoachComposition.Columns.Clear();

    // Add columns with ComboBox
    for (int i = 0; i < 14; i++)
    {
        DataGridTemplateColumn column = new DataGridTemplateColumn();
        column.Header = $"C{i + 1:D2}";
        column.CellTemplate = this.FindResource("ComboBoxTemplate") as DataTemplate;
        dataGridCoachComposition.Columns.Add(column);
    }
}

这显示了教练号码和组合框。然而,不是只显示教练号码,而是显示整个 DataRow 对象。

类似这样的:[错误 SS] (https://i.stack.imgur.com/FXs66.png)

有什么解决办法吗?

c# wpf datagrid
1个回答
0
投票

此答案假设您已正确创建

DataTable
将呈现的
DataGrid

以下示例展示了如何使用共享的

DataGridTemplateColumn
定义实现完全动态的 DataGrid。更高程度的泛化是可能的,但需要更复杂的逻辑。

关键是启用自动列生成(默认启用)并拦截生成的列并替换它们(如果需要)。然后我们将模板内部绑定到父级

DataGridCell
并在
IValueConverter
的帮助下提取单元格值。
DataGridCell
是首选对象,因为它提供了对列上下文的完全访问:单元格容器 (
DataGridCell
)、数据上下文 (
DataRowView
)、列 (
DataGridTemplateColumn
) 以及通过我们得到的列列的索引 (
DataGridColumn.DisplayIndex
)。

MainWindow.xaml

<DataGrid ItemsSource="{Binding TableData}"
          AutoGenerateColumns="True"
          AutoGeneratingColumn="DataGrid_AutoGeneratingColumn">  
  <DataGrid.Resources>
    <local:DataRowViewToCellValueConverter x:Key="DataRowViewToCellValueConverter" />
    <DataTemplate x:Key="DefaultCellTemplate">
      <StackPanel>
        <TextBlock Text="{Binding RelativeSource={RelativeSource AncestorType=DataGridCell}, Converter={StaticResource DataRowViewToCellValueConverter}}" />

        <!-- 
             To bind ComboBox.ItemsSource to an ObservableCollection you would 
             have to use a value converter in a similar fashion to the one used to 
             get the current cell value. 
             But instead of using the column index to access the 
             DataRowView, you would use it to retrieve the appropriate
             source collection from a static Dictionary, 
             where the key is the column index and the value the ObservableCollection.
        -->
        <ComboBox>
          <ComboBoxItem>ENG</ComboBoxItem>
          <ComboBoxItem>HIN</ComboBoxItem>
        </ComboBox>
      </StackPanel>
    </DataTemplate>
  </DataGrid.Resources>
</DataGrid>

MainWindow.xaml.cs

// Handling the AutoGeneratingColumn event allows to replace (and rearrange) 
// the originally generated column.
private void DataGrid_AutoGeneratingColumn_2(object sender, DataGridAutoGeneratingColumnEventArgs e)
{
  var dataGrid = (DataGrid)sender;
  var cellTemplate = (DataTemplate)dataGrid.Resources["DefaultCellTemplate"];
  var templateColumn = new DataGridTemplateColumn()
  {
    Header = e.Column.Header,
    CellTemplate = cellTemplate,
        
  };
      
  e.Column = templateColumn;
}

DataGridCellToCellValueConverter.cs

public class DataGridCellToCellValueConverter : IValueConverter
{
  public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
  {
    var dataGridCell = (DataGridCell)value;

    // Current row could be the placeholder row
    if (dataGridCell.DataContext is not DataRowView dataRowView)
    {
      return Binding.DoNothing;
    }

    int columnIndex = dataGridCell.Column.DisplayIndex;
    return dataRowView[columnIndex];
  }

  public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 
    => throw new NotSupportedException();
}
© www.soinside.com 2019 - 2024. All rights reserved.