【问题标题】:WPF DataGrid: DataGridComboxBox ItemsSource Binding to a Collection of CollectionsWPF DataGrid:DataGridComboxBox ItemsSource 绑定到集合的集合
【发布时间】:2010-12-10 15:59:48
【问题描述】:

情况:

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

问题:

如何绑定 DataGridCombBoxColumn 以便我可以为此类列的每一行拥有不同的字符串集合?

代码示例:

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#:

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_
};
//...

任何帮助将不胜感激!

注意事项:

好的,所以在阅读了前两个答案后,我注意到了一些事情。我的绑定真的不对!现在,我想做的是类似于 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")
});

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

ItemsSource如何绑定到Data?

【问题讨论】:

    标签: c# wpf datagrid itemssource datagridcomboboxcolumn


    【解决方案1】:

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

    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#

    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;
    }
    

    结果:

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

    【讨论】:

    • 因为我想用不同的 ObservableCollections 绑定 DataGridComboBoxColumn 的多行。
    • 您的解决方案有效,但我想知道 WPF DataGrid 是否可行。
    • 是的,绝对是 100%...“DataGrid”与 GridView 100% 相似,因为每一行都有它所代表的项目的 DataContext,所以以同样的方式“Choices”完全可以绑定到 ComboBox :)
    【解决方案2】:

    我认为错误在于您完成绑定的方式。定义列时,绑定与由特定行表示的对象相关。据我了解,每行都有一个 StatsOperation,因此 TextBox 列绑定到操作,这就是你拥有它的方式,而 ComboBox 列 ItemsSource 应该绑定到一个 Collection。现在它看起来像是绑定到Collection&lt;Collection&lt;string&gt;&gt;

    我之前没有在代码隐藏中定义列,所以这里是 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>
    

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

    【讨论】:

    • 我也觉得我的装订不对。我正在寻找类似 ItemsSource = new Binding("Data") 但这样做会产生错误...“无法将类型'System.Windows.Data.Binding'隐式转换为'System.Collections.IEnumerable'。”感谢您发现这个错字!
    • 哦我相信应该是SelectedValueBinding = new Binding("Data"), TextBinding = new Binding("Data")
    • 很抱歉,我通常在 XAML 中定义我的列。也许使用 SetBinding 会起作用:comboBoxCol = new DataGridComboBoxColumn() {...properties but not itemsource...}; comboBoxCol.SetBinding(DataGridComboBoxColumn.ItemsSourceProperty, new Binding() { Source = Data }); DG_Operations.Columns.Add(comboBoxCol);您正在寻找的选定值是字符串还是字符串集合?
    • 字符串和 .SetBinding 不适用于 DataGridComboBoxColumn :S
    • 嗯,正如我提到的,我总是在 XAML 中定义我的列。让我知道您是否需要这样设置它,我会更新我的答案。
    【解决方案3】:

    要修复您的 ItemsSource 绑定错误,请使用以下表单:

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

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

    【讨论】:

      【解决方案4】:

      编辑对不起,我在午夜有点慢:)。这是一个更新的答案。看起来来自 Vincent Sibal WPF DataGrid - DataGridComboBoxColumn v1 Intro 的精彩文章回答了您的问题。是吗?

      【讨论】:

      • 它是 DataGridComboBoxColumn 而不是 DataGridCheckBoxColumn。我希望将此 DataGridComboBoxColumn 绑定到字符串集合的集合,以便每一行包含一个绑定到不同字符串集合的 ComboBox。
      • 不,有问题!事实上,我读过他的文章。当您想在每个 ComboBox 中拥有相同的数据时,它非常有用,但我想要实现的是在每行的 ComboBox 中拥有不同的数据。
      【解决方案5】:

      部分 - 我认为您所说的内容令人困惑。您说您需要每行中的字符串集合,以便组合框可以为不同的行显示不同的字符串。但是,对于显示一组字符串的组合框,您只需要每行的字符串集合,而不需要字符串集合的集合。

      现在,由于您需要每行的字符串集合,您可能会认为您需要字符串集合的集合。

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

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

      为了取得进展,我建议您编辑您的问题,并指出在按照 AndyG 的建议修复绑定后您卡在哪里。

      【讨论】:

      • 每一列都是我创建的类中的一个属性,我使用 ObservableCollection 将每一行的数据保存在内存中并在 DataGrid 中显示该数据。我所说的集合集合的意思是,对于每一行,我需要为 DataGridComboBoxColumn 提供不同的字符串集合。
      【解决方案6】:

      让我们将 ComboBox 的 ItemsSource 绑定到一个属性,例如您的视图模型的 CurrentChoices。此属性应根据您当前的数据网格行选择返回一个过滤列表。 CompareWithSelectedRow 只是一个伪函数来说明示例。每次单击 ComboBox 填充选项列表时,都会调用此属性并返回正确的选项列表。请参见下面的示例,EntireChoiceList 是字符串和列表的元组列表。有改进的余地,例如使用字典或查找。

          List<(string Key, List<string> Choices)> EntireChoiceList= new List<(string, List<string>)>();
      
          public List<string> CurrentChoices
          {
            get => CurrentChoices.Where(q => CompareWithSelectedRow(q.Key, CurrentRow )).FirstOrDefault().Choices;
          }
      
      public object CurrentRow { get => ItemsView.CurrentItem; }
      
      bool CompareWithSelectedRow(string key, object row)
      {
          return key == row; // here you should define compare expression
      }
      

      使用 CollectionViewSource 获取数据网格中的选定行。 Items 是视图模型中绑定到数据网格的列表。

            ItemsView = (CollectionView)CollectionViewSource.GetDefaultView(Items);
            ItemsView.CurrentItem
      

      【讨论】:

        猜你喜欢
        • 2018-07-16
        • 1970-01-01
        • 2023-03-07
        • 2012-12-10
        • 2013-04-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-09-08
        相关资源
        最近更新 更多