简体   繁体   中英

Binding DataGridComboBoxColumn when AutoGenerateColumns=true WPF

I am building a WPF MVVM application.

What I have:

I have a DataTable , binded to a DataGrid as such:

<DataGrid
       Name="Map"
       AutoGenerateColumns="True"
       AutoGeneratingColumn="Map_AutoGeneratingColumn"
       EnableColumnVirtualization="True"
       EnableRowVirtualization="True"
       IsReadOnly="True"
       ItemsSource="{Binding MapDataTable}"
       VirtualizingPanel.VirtualizationMode="Recycling" />

Here is how I am creating the data table in the 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 SomeModel but an error pops up

    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 DisplayName { get; set; }

    public double Value { get; set; }

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

Map_AutoGeneratingColumn in the xaml.cs:

if (e.PropertyName == "Second")
{
      var comboBoxColumn = new DataGridComboBoxColumn
      {
           Header = e.PropertyName,
           ElementStyle = (sender as FrameworkElement).FindResource(typeof(ComboBox)) as Style,
           EditingElementStyle = (sender as FrameworkElement).FindResource(typeof(ComboBox)) as Style,
           DisplayMemberPath = "DisplayName"
      };

      e.Column = comboBoxColumn;
}

In the View: (the binding here is definitely wrong)

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

What I want to achieve:

I want the SomeValues ' display names to be displayed in the DataGridComboBoxColumn . Instead, nothing is displayed.

How do I achieve this?

EDIT:

From this comment ( https://stackoverflow.com/a/35212223/17198402 ) I understand how to bind SomeValues IF the columns were hardcoded and not autogenerated, but I still can't wrap my head around how to do it when they are autogenerated. Setting the ItemsSource in the code-behind is still a mystery to me. As far as I understand, DataGridComboBoxColumns don't inherit the DataContext , unlike DataGridTextColumns .

There are some things wrong with your binding:

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

First of all, DataContext. is unnecessary whichever way you look at it. DataContext is, by definition, the path WPF bindings look at to resolve their binding by default. If you don't set the DataContext, it is null. Now you can either set the DataContext to something other than null, or you can specify a path for the binding. You're mixing up different ways of binding data here. DataContext. shouldn't be part of your binding in any case, but if you use RelativeSource you'll have to specify the Path of the binding and set it to the property you want to bind to.

The first answer to this question here is a great explanation of DataContext and how to use RelativeSource: How do I use WPF bindings with RelativeSource?

All that aside, your binding cannot work: MapDataList is an ObservableCollection, and the elements of that collection have a list called "SomeValues". If you want to access SomeValues, you're going to have to specify an index of your collection at some point. After all: which element of the collection should the binding go to?

You seem to be mixing up a lot of different systems here.

I recommend you read through these questions and their answers thoroughly to get an idea of how to do this properly:

How to bind collection to WPF:DataGridComboBoxColumn

Binding a WPF ComboBox to a custom list

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM