在datagrid celltemplate中绑定collectionviewsource

Posted

技术标签:

【中文标题】在datagrid celltemplate中绑定collectionviewsource【英文标题】:Binding a collectionviewsource in datagrid celltemplate 【发布时间】: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,它们是带有几个额外方法的派生类,但在所有实际用途中它们的行为完全相同。为了完整起见,这里仅提及。

【问题讨论】:

【参考方案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 下拉按钮。该下拉列表包含该字段的所有可能值,以及当前在列表中选择的值。当您在此组合框中选择和取消选择值时,列表会实时更新,并且当这些值在程序的其他部分发生更改时也会实时更新。

【讨论】:

以上是关于在datagrid celltemplate中绑定collectionviewsource的主要内容,如果未能解决你的问题,请参考以下文章

DataGrid 或 GridView CellTemplate 中的动态内容

wpf DataGrid 如何获取DataGridTemplateColumn.CellTemplate 中的TextBox的Text值

WPF开发中页面加载时DataGrid如何隐藏数据源中DataGridTemplateColumn之外的列

DataBinding 不适用于 DataGrid 中的 Combobox

WPF 在 GridViewColumn.CellTemplate 的 DataTemplate 中绑定 UserControl 属性

如何从 DataGridTemplateColumn.CellTemplate 访问按钮