C# WPF DataGrid:DataGridComboxBox ItemsSource 绑定到集合的集合

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1633800/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 19:34:25  来源:igfitidea点击:

WPF DataGrid: DataGridComboxBox ItemsSource Binding to a Collection of Collections

c#wpfdatagriditemssourcedatagridcomboboxcolumn

提问by Partial

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 绑定到一个简单的集合,但我想要做的是将它绑定到一个字符串集合的集合,这样对于每一行,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?

采纳答案by Timothy Khouri

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

回答by Anvaka

EDITI'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 Introanswers your question. Does it?

编辑对不起,我在午夜有点慢:)。这是更新的答案。它看起来像是 Vincent Sibal WPF DataGrid 的好文章- DataGridComboBoxColumn v1 Intro回答了您的问题。可以?

回答by AndyG

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<string>>.

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 在列中创建组合框。我已经从我自己的代码中复制粘贴了,所以在你的情况下,只需将 'dg' 替换为 'WPFToolkit':

<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 的集合。祝你好运!

回答by John Bowen

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.

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

回答by Charles Prakash Dasari

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 的建议修复绑定后您到底卡在哪里。