繁体   English   中英

WPF 自定义控件 - 如何正确循环并显示子内容

[英]WPF Custom Control - How to properly loop through and display child content

试图编写一个自定义控件来允许子内容的集合。 最终目标是根据自定义附加依赖属性对子元素进行一些功能过滤; 然而,在此之前,我为收集和重新显示子 UIElements 所做的任何尝试都以在 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.

为什么要使用UIElementCollection而不是List<UIElement> 您不应该绑定到模板中的UIElementCollection

如果您定义List<UIElement>依赖项属性,您的示例应该可以工作:

[ContentProperty(nameof(Children))]
public class CustomFilter : Control
{
    static CustomFilter()
    {
        DefaultStyleKeyProperty.OverrideMetadata(typeof(CustomFilter), new FrameworkPropertyMetadata(typeof(CustomFilter)));
    }

    public CustomFilter()
    {
        SetValue(ChildrenPropertyKey, new List<UIElement>());
    }

    private static readonly DependencyPropertyKey ChildrenPropertyKey =
            DependencyProperty.RegisterReadOnly(
              nameof(Children),
              typeof(List<UIElement>),
              typeof(CustomFilter),
              new FrameworkPropertyMetadata(new List<UIElement>())
            );
    public static readonly DependencyProperty ChildrenProperty =
        ChildrenPropertyKey.DependencyProperty;

    public List<UIElement> Children
    {
        get { return (List<UIElement>)GetValue(ChildrenProperty); }
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM