1

我正在构建一个 WPF MVVM 应用程序。

我有的:

我有一个DataTable, 绑定到 aDataGrid这样的:

<DataGrid
       Name="Map"
       AutoGenerateColumns="True"
       AutoGeneratingColumn="Map_AutoGeneratingColumn"
       IsReadOnly="True"
       ItemsSource="{Binding MapDataTable}" />

这是我在以下位置创建数据表的方式ViewModel

ObservableCollection<ObservableCollection<MapModel>> MapDataList { get; set; }

private void CreateDataTable(IEnumerable<MapModel> mapDataItems)
{
    MapDataTable.Clear();

    DataTable dataTable = new DataTable("MapDataTable");
    dataTable.Columns.Add("First", typeof(string));
    dataTable.Columns.Add("Second", typeof(string)); //typeof might need to be changed to ObservableCollection<SomeModel> (still works) or ComboBox

    var mapData = new ObservableCollection<MapModel>();

    foreach (var item in mapDataItems)
    {
         mapData.Add(item);
    }

    MapDataList.Add(mapData);

    foreach (MapModel item in mapDataItems)
    {
         DataRow dataRow = dataTable.NewRow();

         dataRow[0] = item.Name;
         dataRow[1] = item.SomeValues; //mistake could be here

         dataTable.Rows.Add(dataRow);
     }

     MapDataTable = dataTable;
 }

MapModel.cs:

public class MapModel
{
    public string Name { get; set; }

    public ObservableCollection<SomeModel> SomeValues { get; set; } = new ObservableCollection<SomeModel>
    {
        new SomeModel(),
        new SomeModel()
    };
}

SomeModel.cs:

public class SomeModel
{
    public string Name { get; set; }

    public double Value { get; set; }

    public SomeModel()
    {
        Name = "test";
        Value = 0;
    }
}

xaml.cs 中的 Map_AutoGeneratingColumn:

if (e.PropertyName == "Second")
{
      var templateColumn = new DataGridTemplateColumn
      {
            Header = e.PropertyName,
            CellTemplate = (sender as FrameworkElement).FindResource("SecondCellTemplate") as DataTemplate,
            CellEditingTemplate = (sender as FrameworkElement).FindResource("SecondCellEditingTemplate") as DataTemplate
      };

      e.Column = templateColumn;
}

在视图中:

<Grid.Resources>
    <DataTemplate x:Key="SecondCellTemplate">
       <TextBlock Text="{Binding Path=???, Mode=OneWay}" />
    </DataTemplate>
    <DataTemplate x:Key="SecondCellEditingTemplate">
       <ComboBox
           DisplayMemberPath="Name"
           ItemsSource="{Binding Path=SomeValues, Mode=OneWay}" //wrong binding
           SelectedValue="{Binding Path=???, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
           SelectedValuePath="Name" />
    </DataTemplate>
</Grid.Resources>

我想要达到的目标:

我希望SomeValues' 名称显示ComboBoxDataGridTemplateColumn.

我如何实现这一目标?

编辑:

从这个评论(https://stackoverflow.com/a/35212223/17198402)我了解如何绑定SomeValues如果列是硬编码而不是自动生成的,但是当它们自动生成时我仍然无法理解如何去做. 在代码隐藏中设置ItemsSource对我来说仍然是一个谜。据我了解,DataGridTemplateColumn不继承DataContext, 不像DataGridTextColumn.

编辑2:

我能够以ViewModel这种方式绑定到一个属性:

视图模型.cs

public ObservableCollection<SomeModel> SomeValues { get; set; } = new ObservableCollection<SomeModel>
{
      new SomeModel(),
      new SomeModel()
};

xml:

<Grid.Resources>
    <DataTemplate x:Key="SecondColumnTemplate" DataType="DataGridCell">
         <ComboBox 
             DisplayMemberPath="Name" 
             ItemsSource="{Binding Path=DataContext.SomeValues, RelativeSource={RelativeSource AncestorType=Page}}" />
    </DataTemplate>
</Grid.Resources>

自动生成列:

 var templateColumn = new DataGridTemplateColumn
 {
       Header = e.PropertyName,
       CellTemplate = (sender as FrameworkElement).FindResource("SecondColumnTemplate") as DataTemplate
 };

 e.Column = templateColumn;

这成功地绑定了 ViewModel 中的新属性,但这当然不是我想要的。如何绑定到当前item.SomeValues

4

1 回答 1

1

您的绑定有一些问题:

<Setter Property="ItemsSource" Value="{Binding DataContext.MapDataList.SomeValues, RelativeSource={RelativeSource AncestorType=Page}}" />

首先,DataContext.无论你怎么看,都是不必要的。根据定义,DataContext 是 WPF 绑定在默认情况下解析其绑定的路径。如果不设置 DataContext,则为空。现在,您可以将 DataContext 设置为 null 以外的值,也可以指定绑定的路径。您在这里混合了不同的数据绑定方式。DataContext.在任何情况下都不应该成为绑定的一部分,但是如果您使用 RelativeSource,则必须指定Path绑定并将其设置为要绑定的属性。

这里对这个问题的第一个答案是对 DataContext 以及如何使用 RelativeSource 的一个很好的解释:如何将 WPF 绑定与 RelativeSource 一起使用?

除此之外,您的绑定无法工作:MapDataList 是一个 ObservableCollection,并且该集合的元素有一个名为“SomeValues”的列表。如果您想访问 SomeValues,您将不得不在某个时候指定您的集合的索引。毕竟:绑定应该转到集合的哪个元素?

您似乎在这里混合了许多不同的系统。

我建议您通读这些问题及其答案,以了解如何正确执行此操作:

如何将集合绑定到 WPF:DataGridComboBoxColumn

将 WPF ComboBox 绑定到自定义列表

于 2021-10-26T11:42:45.567 回答