【问题标题】:Binding a collectionviewsource in datagrid celltemplate在datagrid celltemplate中绑定collectionviewsource
【发布时间】:2021-12-30 01:56:48
【问题描述】:

我遇到了一个棘手的问题,希望您能提供帮助。我正在创建一个涉及动态创建列的数据网格。这是我的课程的一些伪代码:

GameLibrary
    ObservableCollection<Game> Games

Game
    ObservableCollection<CustomField> CustomFields

Customfield
    ObservableCollection<string> Values

数据网格绑定到使用 GameLibrary.Games 作为其源的 CollectionViewSource。当我设置了列时,数据网格在每一行中显示 Game 的其他属性,然后我让它为 CustomFields 中的每个 CustomField 动态创建一列,并在单元格的 itemscontrol 中显示相关的 CustomField 值。

这一切都很好,没问题。不过,现在我想按字母顺序对值进行排序以显示。我知道对此的最佳实践是使用 CollectionViewSource,并且我已经设法设置了一个,附加到 DataTemplate 并显示在 itemscontrol 中 - 但它只有在作为测试时才有效,我将 CVS 的源设置为外部的东西到数据网格。这会显示,但当然它会在每一行中显示相同的内容。

如何将 DataTemplate 的 CVS 绑定到表的当前行中的内容?不使用 CVS 时这很容易,因为我可以使用绑定的 Path 并只说“CustomFields[i].Values”,但我不知道它如何转换为 CVS 源。

这是我现在拥有的,效果很好:

            FrameworkElementFactory listbox = new FrameworkElementFactory(typeof(ItemsControl));
            Binding b = new Binding();
            string pathb = "CustomFields[" + i + "].Values";
            b.Path = new PropertyPath(pathb);
            b.Mode = BindingMode.TwoWay;
            b.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
            listbox.SetBinding(ItemsControl.ItemsSourceProperty, b);
            listbox.SetValue(ItemsControl.PaddingProperty, new Thickness(5));
            dock.AppendChild(listbox);

            DataTemplate dt = new DataTemplate { VisualTree = dock };
            dt.Seal();
            newcolumn.CellTemplate = dt;
            gameDataDisplay.Columns.Add(newcolumn);

这就是我想要的:

            DataTemplate dt = new DataTemplate { VisualTree = dock };

            CollectionViewSource listboxCVS = new CollectionViewSource();
            SortDescription listboxsortDescription = new SortDescription(".", ListSortDirection.Ascending);
            listboxCVS.SortDescriptions.Add(listboxsortDescription);
            listboxCVS.Source = SOMETHING HERE BUT I DONT KNOW WHAT;
            dt.Resources.Add("customCVS" + i, listboxCVS);

            FrameworkElementFactory listbox = new FrameworkElementFactory(typeof(ItemsControl));
            Binding b = new Binding();
            b.Source = listboxCVS;
            listbox.SetBinding(ItemsControl.ItemsSourceProperty, b);
            listbox.SetValue(ItemsControl.PaddingProperty, new Thickness(5));
            dock.AppendChild(listbox);

            dt.Seal();
            newcolumn.CellTemplate = dt;
            gameDataDisplay.Columns.Add(newcolumn);

我也尝试过而不是使用 CVS 绑定到 CustomFields 中的属性,该属性返回值的排序列表并且显示正常,但我知道这不是最佳做法,并且在您滚动项目之前它不会更新离屏又回来,所以我认为这是一条死胡同。

感谢您提供的任何帮助,

汤姆。

PS:这里的 ObservableCollections 并不是严格意义上的 ObservableCollections,它们是带有几个额外方法的派生类,但在所有实际用途中它们的行为完全相同。为了完整起见,这里仅提及。

【问题讨论】:

    标签: c# wpf binding datagrid


    【解决方案1】:

    我以不同的方式解决了这个问题。我没有以编程方式为每个自定义列创建新的数据模板,而是在窗口的资源中定义了一个数据模板,然后使用 ContentPresenter 来填充绑定。

    XAML:

    <DataTemplate x:Key="customfieldtemplate">
        <DockPanel x:Name="customfieldHolder" VerticalAlignment="Center">
            <DockPanel.Resources>
                <CollectionViewSource x:Key="customfieldview" x:Name="customfieldview" Source="{Binding Values}">
                    <CollectionViewSource.SortDescriptions>
                        <scm:SortDescription PropertyName="."/>
                    </CollectionViewSource.SortDescriptions>
                </CollectionViewSource>
                <CollectionViewSource x:Key="customfieldsview" x:Name="customfieldsview" Source="{Binding PossibleValues}">
                    <CollectionViewSource.SortDescriptions>
                        <scm:SortDescription PropertyName="."/>
                    </CollectionViewSource.SortDescriptions>
                </CollectionViewSource>
            </DockPanel.Resources>
    
            <customcontrols:MultiComboBox Width="17" DockPanel.Dock="Right" Margin="5,0" ShowText="False" x:Name="customfieldMiniCombo" ItemsSource="{Binding Source={StaticResource customfieldsview}}" SelectedItems="{Binding Values}" SelectionMode="Multiple" BorderBrush="{DynamicResource MahApps.Brushes.TextBox.Border}" Background="{DynamicResource MahApps.Brushes.ThemeBackground}" Foreground="{DynamicResource MahApps.Brushes.Text}"/>
    
            <ItemsControl ItemsSource="{Binding Source={StaticResource customfieldview}}" Padding="5"/>
        </DockPanel>
    </DataTemplate>
    

    代码隐藏:

            for (int i = 0; i < maindatafile.CurrentGameLibrary.CustomFields.Count; i++)
            {
                CustomColumn newcolumn = new CustomColumn();
                newcolumn.Header = maindatafile.CurrentGameLibrary.CustomFields[i].Name;
    
                gameDataDisplay.Columns.Add(newcolumn);
    
                var template = FindResource("customfieldtemplate");
                FrameworkElementFactory factory = new FrameworkElementFactory(typeof(ContentPresenter));
                factory.SetValue(ContentPresenter.ContentTemplateProperty, template);
    
                Binding newBinding = new Binding("CustomFields[" + i + "]");
                newBinding.Mode = BindingMode.TwoWay;
                newBinding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
    
                factory.SetBinding(ContentPresenter.ContentProperty, newBinding);
    
                DataTemplate dt = new DataTemplate { VisualTree = factory };
    
                newcolumn.CellTemplate = dt;
            }
    

    模板中的 multicombobox 用户控件(找到 here)包含一组“允许”值,可以添加到 observablecollection 或从 observablecollection 中删除。它的 ItemsSource 是 CustomField 中的另一个属性,它的 getter 返回该 CustomField 的允许值列表。多组合框的 SelectedItems 属性使用与 ItemsControl 相同的绑定。

    最终结果?该单元格在相应的 CustomField 中显示值列表,旁边有一个 lil 下拉按钮。该下拉列表包含该字段的所有可能值,以及当前在列表中选择的值。当您在此组合框中选择和取消选择值时,列表会实时更新,并且当这些值在程序的其他部分发生更改时也会实时更新。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-10-24
      • 2013-09-13
      • 2017-08-26
      • 2012-07-01
      • 2013-12-09
      相关资源
      最近更新 更多