如何使自定义控件上的 DependencyProperty 接受 CollectionViewSource 绑定?
How to make a DependencyProperty on a Custom Control accept a CollectionViewSource Binding?
背景:
- 我可以在 XAML 中创建一个
CollectionViewSource
,从 Window 上的 ObservableCollection
获取数据。
- 将
CollectionViewSource
绑定到 DataGrid
的行为完全符合预期 (ItemsSource="{Binding Source={StaticResource ClustersView}}"
)
- 过滤
CollectionViewSource
工作正常。
- 我的
CustomControl
工作正常(至少,所有其他绑定和功能)
问题:
我无法(或不知道如何)在我的 CustomControl
上创建将绑定到 CollectionViewSource
和 update/trigger 的 DependencyProperty
当 ColelctionViewSource 的 View 发生变化时(即当 Filtering 发生变化时)。
DependencyProperty
应该是什么类型才能绑定到 CollectionViewSource
? Object
类型显示绑定 CollectionViewSource
将作为 ListCollectionView
传递给我的 CustomControl
DependencyProperty
- 但 ListCollectionView
不提供事件(可见,即不 Internal
) CollectionChanged
.
将 ItemsControl
派生为我的 CustomControl
的 BaseClass
不是一个选项。 旁注 - 我不需要从 ItemsControl
派生来实现此功能:我将如何创建一个 CustomControl
具有 2 个接受 2 个不同 CollectionViewSources
的绑定( ItemsControl
不能这样做)?
代码:
CollectionViewSource
"ClustersView"
DataGrid
:ItemsSource
绑定到 "ClustersView"(这很好用)
NavigatorControl
: 这是我的CustomControl
代码:
<CollectionViewSource x:Key="ClustersView"
Source="{Binding EventClusters, ElementName=me}"
Filter="ClustersViewSource_Filter"></CollectionViewSource>
<DataGrid ItemsSource="{Binding Source={StaticResource ClustersView}}">
<LightMapperControls:NavigatorControl Clusters="{Binding Source={StaticResource ClustersView}}">
</LightMapperControls:NavigatorControl>
//The DP on NavigatorControl that I bind the CollectionViewSource to
public object Clusters
{
get { return (object)GetValue(ClustersProperty); }
set { SetValue(ClustersProperty, value); }
}
// Using a DependencyProperty as the backing store for Clusters. This enables animation, styling, binding, etc...
public static readonly DependencyProperty ClustersProperty =
DependencyProperty.Register("Clusters", typeof(object), typeof(NavigatorControl), new PropertyMetadata(null, OnClustersChanged));
private static void OnClustersChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
{
ListCollectionView lcv = (ListCollectionView)e.NewValue; //e.NewValue is of type ListCollectionView
//lcv.Items //no such property
//lcv.CollectionChanged //no such event
}
解决办法是让WPF
做所有的工作!我做了Clusters
DependencyObject
类型object
,然后添加 FrameworkPropertyMetadataOption.AffectsRender
以触发 OnRender
以在 Clusters
更改时重绘 canvas(即在 CollectionViewSource 上进行过滤)。 (重绘 canvas 的实际方法是从 OnRender
调用的 DrawClusters
)。 DrawClusters
包含从 Clusters
(object
) 到 ICollectionView
的转换,我在 for..each
循环中列举了它以访问每个单独的 Cluster
。
感谢@PeterDuniho 提出的问题,这些问题迫使我重新审视我自以为知道的事情!
相关代码如下
public object Clusters
{
get { return (object)GetValue(ClustersProperty); }
set { SetValue(ClustersProperty, value); }
}
// Using a DependencyProperty as the backing store for MyProperty. This enables animation, styling, binding, etc...
public static readonly DependencyProperty ClustersProperty =
DependencyProperty.Register("Clusters", typeof(object), typeof(NavigatorControl), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.AffectsRender));
private void DrawClusters(ref DrawingContext dc, ref double SquareWidth, ref double SquareHeight)
{
if (Clusters == null)
return;
if (ClustersVisibility == Visibility.Visible)
{
ICollectionView cv = (ICollectionView)Clusters;
foreach (ClusterBase cluster in cv)
{
PathGeometry geometry = new PathGeometry();
foreach (ClusterSquare square in cluster.Squares)
{
geometry = Geometry.Combine(geometry, new RectangleGeometry(square.ToRect(SquareWidth, SquareHeight)), GeometryCombineMode.Union, null);
}
dc.DrawGeometry(clustersbrush, clusterspen, geometry);
}
}
}
背景:
- 我可以在 XAML 中创建一个
CollectionViewSource
,从 Window 上的ObservableCollection
获取数据。 - 将
CollectionViewSource
绑定到DataGrid
的行为完全符合预期 (ItemsSource="{Binding Source={StaticResource ClustersView}}"
) - 过滤
CollectionViewSource
工作正常。 - 我的
CustomControl
工作正常(至少,所有其他绑定和功能)
问题:
我无法(或不知道如何)在我的 CustomControl
上创建将绑定到 CollectionViewSource
和 update/trigger 的 DependencyProperty
当 ColelctionViewSource 的 View 发生变化时(即当 Filtering 发生变化时)。
DependencyProperty
应该是什么类型才能绑定到 CollectionViewSource
? Object
类型显示绑定 CollectionViewSource
将作为 ListCollectionView
传递给我的 CustomControl
DependencyProperty
- 但 ListCollectionView
不提供事件(可见,即不 Internal
) CollectionChanged
.
将 ItemsControl
派生为我的 CustomControl
的 BaseClass
不是一个选项。 旁注 - 我不需要从 ItemsControl
派生来实现此功能:我将如何创建一个 CustomControl
具有 2 个接受 2 个不同 CollectionViewSources
的绑定( ItemsControl
不能这样做)?
代码:
CollectionViewSource
"ClustersView"
DataGrid
:ItemsSource
绑定到 "ClustersView"(这很好用)
NavigatorControl
: 这是我的CustomControl
代码:
<CollectionViewSource x:Key="ClustersView"
Source="{Binding EventClusters, ElementName=me}"
Filter="ClustersViewSource_Filter"></CollectionViewSource>
<DataGrid ItemsSource="{Binding Source={StaticResource ClustersView}}">
<LightMapperControls:NavigatorControl Clusters="{Binding Source={StaticResource ClustersView}}">
</LightMapperControls:NavigatorControl>
//The DP on NavigatorControl that I bind the CollectionViewSource to
public object Clusters
{
get { return (object)GetValue(ClustersProperty); }
set { SetValue(ClustersProperty, value); }
}
// Using a DependencyProperty as the backing store for Clusters. This enables animation, styling, binding, etc...
public static readonly DependencyProperty ClustersProperty =
DependencyProperty.Register("Clusters", typeof(object), typeof(NavigatorControl), new PropertyMetadata(null, OnClustersChanged));
private static void OnClustersChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
{
ListCollectionView lcv = (ListCollectionView)e.NewValue; //e.NewValue is of type ListCollectionView
//lcv.Items //no such property
//lcv.CollectionChanged //no such event
}
解决办法是让WPF
做所有的工作!我做了Clusters
DependencyObject
类型object
,然后添加 FrameworkPropertyMetadataOption.AffectsRender
以触发 OnRender
以在 Clusters
更改时重绘 canvas(即在 CollectionViewSource 上进行过滤)。 (重绘 canvas 的实际方法是从 OnRender
调用的 DrawClusters
)。 DrawClusters
包含从 Clusters
(object
) 到 ICollectionView
的转换,我在 for..each
循环中列举了它以访问每个单独的 Cluster
。
感谢@PeterDuniho 提出的问题,这些问题迫使我重新审视我自以为知道的事情!
相关代码如下
public object Clusters
{
get { return (object)GetValue(ClustersProperty); }
set { SetValue(ClustersProperty, value); }
}
// Using a DependencyProperty as the backing store for MyProperty. This enables animation, styling, binding, etc...
public static readonly DependencyProperty ClustersProperty =
DependencyProperty.Register("Clusters", typeof(object), typeof(NavigatorControl), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.AffectsRender));
private void DrawClusters(ref DrawingContext dc, ref double SquareWidth, ref double SquareHeight)
{
if (Clusters == null)
return;
if (ClustersVisibility == Visibility.Visible)
{
ICollectionView cv = (ICollectionView)Clusters;
foreach (ClusterBase cluster in cv)
{
PathGeometry geometry = new PathGeometry();
foreach (ClusterSquare square in cluster.Squares)
{
geometry = Geometry.Combine(geometry, new RectangleGeometry(square.ToRect(SquareWidth, SquareHeight)), GeometryCombineMode.Union, null);
}
dc.DrawGeometry(clustersbrush, clusterspen, geometry);
}
}
}