WPF DataGrid:DataGridComboxBox ItemsSource绑定到集合集合

时间:2022-07-10 17:01:38

Situation:

I've created a DataGrid in XAML and the ItemsSource is binded to an ObservableCollection of a certain class that contains properties. Then in C#, I create a DataGridTextColumn and a DataGridComboBoxColumn and binded these to the properties of the objects inside the ObservableCollection. I can bind the DataGridComboBoxColumn to a simple Collection but what I want to do is bind it to a collection of collections of strings so that for each row the ComboBox inside the DataGrid has a different collection of string. I have failed to do so...

我在XAML中创建了一个DataGrid,并将ItemsSource绑定到包含属性的某个类的ObservableCollection。然后在C#中,我创建了一个DataGridTextColumn和一个DataGridComboBoxColumn,并将这些绑定到ObservableCollection内对象的属性。我可以将DataGridComboBoxColumn绑定到一个简单的Collection,但我想要做的是将它绑定到一组字符串集合,这样对于每一行,DataGrid中的ComboBox都有一个不同的字符串集合。我没有这样做......

Question:

How can I bind the DataGridCombBoxColumn so that I can have a different collection of strings for each row of this type of column?

如何绑定DataGridCombBoxColumn以便为此类列的每一行提供不同的字符串集合?

Code Sample:

XAML:

XAML:

<Window>
  <!-- ... -->
  WPFToolkit:DataGrid
           x:Name="DG_Operations"
           Margin="10,5,10,5" 
           Height="100" 
           HorizontalAlignment="Stretch" 
           FontWeight="Normal" 
           ItemsSource="{Binding Path=OperationsStats}"
           AlternatingRowBackground="{DynamicResource SpecialColor}" 
           HorizontalScrollBarVisibility="Auto" 
           VerticalScrollBarVisibility="Visible" 
           SelectionMode="Extended"
           CanUserAddRows="False" 
           CanUserDeleteRows="False"
           CanUserResizeRows="True" 
           CanUserSortColumns="True"
           AutoGenerateColumns="False" 
           IsReadOnly="False" 
           IsEnabled="True"
           BorderThickness="1,1,1,1" 
           VerticalAlignment="Stretch"/>
  <!-- ... -->
</Window>

C#:

C#:

public class DataModelStatsOperations
{
   public ObservableCollection<IStatsOperation> OperationsStats { get; set; }
}

public interface IStatsOperation
{
   string Operation { get; set; }
   Collection<string> Data{ get; set; }
}

public class StatsOperation : IStatsOperation
{
    public StatsOperation(string operation, Collection<string> data)
    {
        Operation = operation;
        Data = data;
    }
    public string Operation { get; set; }
    public Collection<string> Data{ get; set; }
}

private ObservableCollection<IStatsOperation> dataOperations_ =
        new ObservableCollection<IStatsOperation>();

//...
 Binding items = new Binding();
 PropertyPath path = new PropertyPath("Operation");
 items.Path = path;
 DG_Operations.Columns.Add(new DataGridTextColumn()
 {
     Header = "Operations",
     Width = 133,
     Binding = items
  });
  DG_Operations.Columns.Add(new DataGridComboBoxColumn()
  {
     Header = "Data",
     Width = 190,
     ItemsSource = /*???*/,
     SelectedValueBinding = new Binding("Data"),
     TextBinding = new Binding("Data")
  });
dataOperations_.Add(new StatsOperation(CB_Operation.SelectedItem.ToString(),
                                                           dataCollection));
DG_Operations.DataContext = new DataModelStatsOperations
{
    OperationsStats = dataOperations_
};
//...

Any help would be greatly appreciated!

任何帮助将不胜感激!

Notes:

Okay, so after reading the two first answers I noticed something. My binding is really not right! Now, what I want to do is something similar to what AndyG proposed:

好的,所以在看了两个第一个答案之后我注意到了一些东西。我的绑定真的不对!现在,我想要做的是类似于AndyG提出的建议:

DG_Operations.Columns.Add(new DataGridComboBoxColumn()
{
    Header = "Data",
    Width = 190,
    ItemsSource = new Binding("Data"), //notice this here does not work (have a look at the following error)
    SelectedValueBinding = new Binding("Operation"),
    TextBinding = new Binding("Operation")
});

Error: "Cannot implicitly convert type 'System.Windows.Data.Binding' to 'System.Collections.IEnumerable'."

错误:“无法将类型'System.Windows.Data.Binding'隐式转换为'System.Collections.IEnumerable'。”

How can the ItemsSource be bound to Data?

ItemsSource如何绑定到Data?

5 个解决方案

#1


11  

Firstly, this should be easy... secondly, why are you building (and binding) columns in C#? Eek.

首先,这应该很容易......其次,为什么要在C#中构建(和绑定)列?伊克。

XAML (I'm using a regular grid because I'm lazy):

XAML(我使用常规网格,因为我很懒):

<ListView Name="MyListView">
    <ListView.View>
        <GridView>

            <GridView.Columns>

                <GridViewColumn DisplayMemberBinding="{Binding Operation}" />

                <GridViewColumn>
                    <GridViewColumn.CellTemplate>
                        <DataTemplate>
                            <ComboBox ItemsSource="{Binding Choices}" />
                        </DataTemplate>
                    </GridViewColumn.CellTemplate>
                </GridViewColumn>

            </GridView.Columns>

        </GridView>
    </ListView.View>
</ListView>

C#:

C#:

void Window1_Loaded(object sender, RoutedEventArgs e)
{
    var dahList = new List<StatsOperation>();

    dahList.Add(new StatsOperation
    {
        Operation = "Op A",
        Choices = new string[] { "One", "Two", "Three" },
    });

    dahList.Add(new StatsOperation
    {
        Operation = "Op B",
        Choices = new string[] { "4", "5", "6" },
    });

    this.MyListView.ItemsSource = dahList;
}

The Results:

结果:

WPF grid with dynamic combo box choices http://www.singingeels.com/Articles/Articles/UserImage.aspx?ImageID=b1e3f880-c278-4d2b-bcc2-8ad390591200

具有动态组合框选项的WPF网格http://www.singingeels.com/Articles/Articles/UserImage.aspx?ImageID=b1e3f880-c278-4d2b-bcc2-8ad390591200

#2


4  

I think the mistake is in how you've done your binding. When you define a column, the binding is related to the object that is represented by a particular row. So as I understand, you have a StatsOperation for each row, so the TextBox column is bound to operation, which is how you have it, and the ComboBox column ItemsSource should be bound to a Collection. Right now it looks like it's bound to a Collection<Collection<string>>.

我认为错误在于你是如何完成绑定的。定义列时,绑定与特定行表示的对象相关。据我所知,每行都有一个StatsOperation,因此TextBox列绑定到操作,这就是你拥有它的方式,ComboBox列ItemsSource应绑定到Collection。现在它看起来像绑定了Collection >。

I've not defined columns in code-behind before so here is an example in XAML. I've found ComboBoxColumn can be tricky sometimes so i've shown how you can have a combobox in the column by using either a TemplateColumn or a ComboBoxColumn. I've copy pasted from my own code so just replace 'dg' with 'WPFToolkit' in your case:

我之前没有在代码隐藏中定义列,所以这里是XAML中的一个例子。我发现ComboBoxColumn有时会很棘手所以我已经展示了如何使用TemplateColumn或ComboBoxColumn在列中添加组合框。我从我自己的代码中复制粘贴,所以在你的情况下用'WPFToolkit'替换'dg':

<dg:DataGrid
      ...
      ...>
      <dg:DataGrid.Columns>
            <dg:DataGridTextColumn Binding="{Binding Operation}" CanUserReorder="True" CanUserResize="True" Header="Operation" />
            <dg:DataGridTemplateColumn CanUserReorder="True" CanUserResize="True" Header="Template Column">
                <dg:DataGridTemplateColumn.CellTemplate>
                    <DataTemplate>
                        <ComboBox ItemsSource="{Binding Data}" SelectedItem="{Binding Operation}" />
                    </DataTemplate>
                </dg:DataGridTemplateColumn.CellTemplate>
            </dg:DataGridTemplateColumn>
            <dg:DataGridComboBoxColumn
                Header="ComboBox Column"                                                                                    
                 SelectedValueBinding="{Binding Operation}"                     
                 SelectedItemBinding="{Binding Operation}">
                <dg:DataGridComboBoxColumn.ElementStyle>
                    <Style TargetType="ComboBox">
                        <Setter Property="IsSynchronizedWithCurrentItem" Value="False" />
                        <Setter Property="ItemsSource" Value="{Binding Data}" />
                    </Style>
                </dg:DataGridComboBoxColumn.ElementStyle>
                <dg:DataGridComboBoxColumn.EditingElementStyle>
                    <Style TargetType="ComboBox">
                        <Setter Property="ItemsSource" Value="{Binding Data}" />
                        <Setter Property="IsDropDownOpen" Value="True" />
                    </Style>
                </dg:DataGridComboBoxColumn.EditingElementStyle>
            </dg:DataGridComboBoxColumn>
      </dg:DataGrid.Columns>

</dg:DataGrid>

I'm assuming that Operation is the selected item, Data is the items to select from, and that your DataGrid is bound to a collection of StatsOperation. Good luck!

我假设Operation是所选项,Data是要从中选择的项,并且DataGrid绑定到StatsOperation的集合。祝你好运!

#3


2  

To fix your ItemsSource Binding Error use the form:

要修复ItemsSource绑定错误,请使用以下格式:

BindingOperations.SetBinding(new DataGridComboBoxColumn(), DataGridComboBoxColumn.ItemsSourceProperty, new Binding("Data"));

You obviously can't do this in the intializer so you'll have to move your declarations around a bit but that should take care of that error in your update.

您显然无法在初始化程序中执行此操作,因此您必须稍微移动声明,但这应该在更新中处理该错误。

#4


1  

EDIT I'm sorry, I'm little slow at midnights :). Here is an updated answer. It looks like great article from Vincent Sibal WPF DataGrid - DataGridComboBoxColumn v1 Intro answers your question. Does it?

编辑对不起,我在中午的时候有点慢:)。这是一个更新的答案。它看起来像Vincent Sibal WPF DataGrid的精彩文章 - DataGridComboBoxColumn v1 Intro回答了你的问题。可以?

#5


0  

Partial - I think there is a confusion in what you are saying. You said you need a collection of collection of strings in each row so that the combo box could show different strings for different rows. However, for a combo box to show a set of strings, you only need a collection of strings, per row, not a collection of collection of strings.

部分 - 我认为你说的是​​混乱。您说您需要在每一行中收集字符串集合,以便组合框可以显示不同行的不同字符串。但是,对于显示一组字符串的组合框,您只需要每行的字符串集合,而不是字符串集合的集合。

Now since you need the collection of strings per row you might be thinking that you would need collection of collection of strings.

既然你需要每行的字符串集合,你可能会认为你需要收集字符串集合。

Is my understanding of your question correct? If so, then your mention of collection of collection of strings is wrong.

我对你的问题的理解是否正确?如果是这样,那么你提到的字符串集合是错误的。

What you actually need is collection of StatOperations in which each StatOperation should have a collection of strings. This is exactly how you had as shown in your classes above.

你真正需要的是StatOperations的集合,其中每个StatOperation都应该有一个字符串集合。这正是您在上面的课程中所展示的。

To make progress, I suggest you edit your question and point out where exactly you were stuck after fixing the binding as suggested by AndyG.

为了取得进展,我建议你编辑你的问题,并指出在修复AndyG建议的绑定之后你到底陷入了什么。

#1


11  

Firstly, this should be easy... secondly, why are you building (and binding) columns in C#? Eek.

首先,这应该很容易......其次,为什么要在C#中构建(和绑定)列?伊克。

XAML (I'm using a regular grid because I'm lazy):

XAML(我使用常规网格,因为我很懒):

<ListView Name="MyListView">
    <ListView.View>
        <GridView>

            <GridView.Columns>

                <GridViewColumn DisplayMemberBinding="{Binding Operation}" />

                <GridViewColumn>
                    <GridViewColumn.CellTemplate>
                        <DataTemplate>
                            <ComboBox ItemsSource="{Binding Choices}" />
                        </DataTemplate>
                    </GridViewColumn.CellTemplate>
                </GridViewColumn>

            </GridView.Columns>

        </GridView>
    </ListView.View>
</ListView>

C#:

C#:

void Window1_Loaded(object sender, RoutedEventArgs e)
{
    var dahList = new List<StatsOperation>();

    dahList.Add(new StatsOperation
    {
        Operation = "Op A",
        Choices = new string[] { "One", "Two", "Three" },
    });

    dahList.Add(new StatsOperation
    {
        Operation = "Op B",
        Choices = new string[] { "4", "5", "6" },
    });

    this.MyListView.ItemsSource = dahList;
}

The Results:

结果:

WPF grid with dynamic combo box choices http://www.singingeels.com/Articles/Articles/UserImage.aspx?ImageID=b1e3f880-c278-4d2b-bcc2-8ad390591200

具有动态组合框选项的WPF网格http://www.singingeels.com/Articles/Articles/UserImage.aspx?ImageID=b1e3f880-c278-4d2b-bcc2-8ad390591200

#2


4  

I think the mistake is in how you've done your binding. When you define a column, the binding is related to the object that is represented by a particular row. So as I understand, you have a StatsOperation for each row, so the TextBox column is bound to operation, which is how you have it, and the ComboBox column ItemsSource should be bound to a Collection. Right now it looks like it's bound to a Collection<Collection<string>>.

我认为错误在于你是如何完成绑定的。定义列时,绑定与特定行表示的对象相关。据我所知,每行都有一个StatsOperation,因此TextBox列绑定到操作,这就是你拥有它的方式,ComboBox列ItemsSource应绑定到Collection。现在它看起来像绑定了Collection >。

I've not defined columns in code-behind before so here is an example in XAML. I've found ComboBoxColumn can be tricky sometimes so i've shown how you can have a combobox in the column by using either a TemplateColumn or a ComboBoxColumn. I've copy pasted from my own code so just replace 'dg' with 'WPFToolkit' in your case:

我之前没有在代码隐藏中定义列,所以这里是XAML中的一个例子。我发现ComboBoxColumn有时会很棘手所以我已经展示了如何使用TemplateColumn或ComboBoxColumn在列中添加组合框。我从我自己的代码中复制粘贴,所以在你的情况下用'WPFToolkit'替换'dg':

<dg:DataGrid
      ...
      ...>
      <dg:DataGrid.Columns>
            <dg:DataGridTextColumn Binding="{Binding Operation}" CanUserReorder="True" CanUserResize="True" Header="Operation" />
            <dg:DataGridTemplateColumn CanUserReorder="True" CanUserResize="True" Header="Template Column">
                <dg:DataGridTemplateColumn.CellTemplate>
                    <DataTemplate>
                        <ComboBox ItemsSource="{Binding Data}" SelectedItem="{Binding Operation}" />
                    </DataTemplate>
                </dg:DataGridTemplateColumn.CellTemplate>
            </dg:DataGridTemplateColumn>
            <dg:DataGridComboBoxColumn
                Header="ComboBox Column"                                                                                    
                 SelectedValueBinding="{Binding Operation}"                     
                 SelectedItemBinding="{Binding Operation}">
                <dg:DataGridComboBoxColumn.ElementStyle>
                    <Style TargetType="ComboBox">
                        <Setter Property="IsSynchronizedWithCurrentItem" Value="False" />
                        <Setter Property="ItemsSource" Value="{Binding Data}" />
                    </Style>
                </dg:DataGridComboBoxColumn.ElementStyle>
                <dg:DataGridComboBoxColumn.EditingElementStyle>
                    <Style TargetType="ComboBox">
                        <Setter Property="ItemsSource" Value="{Binding Data}" />
                        <Setter Property="IsDropDownOpen" Value="True" />
                    </Style>
                </dg:DataGridComboBoxColumn.EditingElementStyle>
            </dg:DataGridComboBoxColumn>
      </dg:DataGrid.Columns>

</dg:DataGrid>

I'm assuming that Operation is the selected item, Data is the items to select from, and that your DataGrid is bound to a collection of StatsOperation. Good luck!

我假设Operation是所选项,Data是要从中选择的项,并且DataGrid绑定到StatsOperation的集合。祝你好运!

#3


2  

To fix your ItemsSource Binding Error use the form:

要修复ItemsSource绑定错误,请使用以下格式:

BindingOperations.SetBinding(new DataGridComboBoxColumn(), DataGridComboBoxColumn.ItemsSourceProperty, new Binding("Data"));

You obviously can't do this in the intializer so you'll have to move your declarations around a bit but that should take care of that error in your update.

您显然无法在初始化程序中执行此操作,因此您必须稍微移动声明,但这应该在更新中处理该错误。

#4


1  

EDIT I'm sorry, I'm little slow at midnights :). Here is an updated answer. It looks like great article from Vincent Sibal WPF DataGrid - DataGridComboBoxColumn v1 Intro answers your question. Does it?

编辑对不起,我在中午的时候有点慢:)。这是一个更新的答案。它看起来像Vincent Sibal WPF DataGrid的精彩文章 - DataGridComboBoxColumn v1 Intro回答了你的问题。可以?

#5


0  

Partial - I think there is a confusion in what you are saying. You said you need a collection of collection of strings in each row so that the combo box could show different strings for different rows. However, for a combo box to show a set of strings, you only need a collection of strings, per row, not a collection of collection of strings.

部分 - 我认为你说的是​​混乱。您说您需要在每一行中收集字符串集合,以便组合框可以显示不同行的不同字符串。但是,对于显示一组字符串的组合框,您只需要每行的字符串集合,而不是字符串集合的集合。

Now since you need the collection of strings per row you might be thinking that you would need collection of collection of strings.

既然你需要每行的字符串集合,你可能会认为你需要收集字符串集合。

Is my understanding of your question correct? If so, then your mention of collection of collection of strings is wrong.

我对你的问题的理解是否正确?如果是这样,那么你提到的字符串集合是错误的。

What you actually need is collection of StatOperations in which each StatOperation should have a collection of strings. This is exactly how you had as shown in your classes above.

你真正需要的是StatOperations的集合,其中每个StatOperation都应该有一个字符串集合。这正是您在上面的课程中所展示的。

To make progress, I suggest you edit your question and point out where exactly you were stuck after fixing the binding as suggested by AndyG.

为了取得进展,我建议你编辑你的问题,并指出在修复AndyG建议的绑定之后你到底陷入了什么。