【发布时间】:2019-08-25 17:15:04
【问题描述】:
正在尝试编写一个允许收集子内容的自定义控件。最终目标是基于自定义附加依赖属性对子元素进行一些功能过滤;但是,在此之前,我为收集和重新显示子 UIElement 所做的任何尝试都在 XAML 解析/显示期间以异常结束。
我有一个类CustomFilter : Control,它在附近的xaml 文件中有一个关联的默认样式。它有一个 Children 的依赖属性,它当前收集 UIElementCollection 中的子元素。
我相信我的问题可能是我如何尝试渲染孩子的集合。我知道在 XAML 中循环内容的唯一方法是使用 ItemsControl,我将我的 Children 集合作为 ItemsSource 传递给它,感觉相当落后(使用 UIElements 作为数据模型?)
之后,我们尝试通过 ItemTemplate 内的内容呈现器呈现元素。我在许多其他示例中看到使用内容呈现器呈现控件子级,因此我希望这可能至少部分正确(尽管所有示例都只使用单个元素)。
示例类
[ContentProperty(nameof(Children))]
public class CustomFilter : Control
{
static CustomFilter()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(CustomFilter), new FrameworkPropertyMetadata(typeof(CustomFilter)));
}
public CustomFilter()
{
Children = new UIElementCollection(this, this);
}
public static readonly DependencyProperty ChildrenProperty = DependencyProperty.Register(nameof(Children), typeof(UIElementCollection), typeof(CustomFilter), new FrameworkPropertyMetadata(RefreshFilter));
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
public UIElementCollection Children
{
get { return (UIElementCollection)GetValue(ChildrenProperty); }
private set { SetValue(ChildrenProperty, value); }
}
}
示例模板
<Style TargetType="{x:Type local:CustomFilter}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:CustomFilter}">
<StackPanel>
<ItemsControl ItemsSource="{TemplateBinding Children}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel>
<ContentPresenter Content="{Binding}"/>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
用例
<local:CustomFilter>
<TextBlock Text="X"/>
<TextBlock Text="Y"/>
<TextBlock Text="Z"/>
</local:CustomFilter>
尝试运行使用此控件会导致它在到达 ItemsControl 时失败,而不是到达 ItemTemplate,以下异常:
ArgumentException: Specified Visual is already a child of another Visual or the root of a CompositionTarget.
我尝试为 Children 创建一个包装器类,将一个子级传递给包装器的每个实例,并将其作为 ItemsSource 绑定 - 它成功循环通过 ItemTemplate,但尝试在其中使用 ContentPresenter包装的子元素为我提供了以下异常:
ArgumentException: Must disconnect specified child from current parent Visual before attaching to new parent Visual.
【问题讨论】:
-
你为什么不从 itemscontrol 继承?这听起来像是一个过滤内容的itemscontrol。它只是过滤你正在做的事情吗?因为你可以在 viewmodel 层中使用 collectionview 来做到这一点。
-
@Andy 这个概念闪过我的脑海,但我想尝试不先继承,只是为了确保我可以从基础开始。我以后肯定想这样做,利用该功能来定义您自己的面板和其他样式等。