在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 属性