【问题标题】:WPF Custom Control - How to properly loop through and display child contentWPF 自定义控件 - 如何正确循环并显示子内容
【发布时间】: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 这个概念闪过我的脑海,但我想尝试不先继承,只是为了确保我可以从基础开始。我以后肯定想这样做,利用该功能来定义您自己的面板和其他样式等。

标签: c# wpf xaml


【解决方案1】:

您为什么使用UIElementCollection 而不是List&lt;UIElement&gt;?您不应该绑定到模板中的UIElementCollection

如果您定义 List&lt;UIElement&gt; 依赖属性,您的示例应该可以工作:

[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); }
    }
}

【讨论】:

  • 我不知道使用 UIElementCollection 的含义...但是,我最终还是用 List 替换了它。虽然我找到了解决我的整体问题的不同方法,但我会接受你的回答 - 给你一些时间来尝试。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-06-24
  • 1970-01-01
相关资源
最近更新 更多