ContentPropertyAttribute

ContentPropertyAttribute

本文介绍了添加孩子用户控件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的任务



创建一个用户控件这应该能够包含任何视觉孩子这是可以在WPF ,孩子们都显示在一个容器,是用户控件



的子

我的问题



我不能设法让孩子们在我的容器正确显示,我试过薮方式,并没有发现其在设计工作的方式。我还试图用 ContentControl中,但没有被显示出来。



我的方法



首先,我发现链​​接,和我有一些变化试了一下。我设法显示在右侧容器中的内容,但由于内容的属性设置,私营和设计师要覆盖它,它不会在设计师的工作。在XAML配售一切正常,但是这跟设计师合作的时候并不好。这是可能最喜欢的方式。



这之后我试图通过结合使用 ContentControl中内容 -property到 UIElementCollection 型的绑定属性。这是形式给出不扔任何错误的设计师,但我不得不承认,我从来没有看到任何的控制(如按钮)在我的容器中。它保持为空,但孩子们说。



结论



寻找一个方便,快捷的薮小时后解决方案我决定寻求解决方案在这里。我有点失望。这将是非常有益的,如果微软能得到一个样品放入MSDN。



我敢肯定,必须有存档这个简单的方法。



现状



感谢的安德烈加夫里拉的和的 jberger 的我归档创建它显示的内容节点(见下面的代码),但仍存在两个问题:
- 无设计器支持
- 边境(请参见XAML)的设计师,而不是没有显示时,应用程序运行时有显示甚至无余量

 公共类NodeContent:ContentControl中
{
静态NodeContent()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof运算(NodeContent),新FrameworkPropertyMetadata(typeof运算(NodeContent)));
}
}

公共部分类节点:用户控件,INotifyPropertyChanged的
{
UIElementCollection _Elements;

公共事件PropertyChangedEventHandler的PropertyChanged;

公共UIElementCollection NodeContent
{
{返回_Elements; }

{
_Elements =价值;
OnPropertyChanged(NodeContent);
}
}

公共节点()
{
的InitializeComponent();
NodeContent =新UIElementCollection(NodeContentContainer,这一点);
}



保护无效OnPropertyChanged(字符串名称)
{
PropertyChangedEventHandler处理器=的PropertyChanged;
如果(处理!= NULL)
{
处理器(这一点,新PropertyChangedEventArgs(名));
}
}
}



节点的XAML:

 <用户控件X:类=Pipedream.Nodes.Node
的xmlns =htt​​p://schemas.microsoft .COM / WinFX的/ 2006 / XAML /演示
的xmlns:X =http://schemas.microsoft.com/winfx/2006/xaml
的xmlns:MC =HTTP://模式.openxmlformats.org /标记兼容性/ 2006
的xmlns:D =http://schemas.microsoft.com/expression/blend/2008
MC:可忽略=D
D:DesignHeight =216D:DesignWidth =174背景=透明NAME =NodeControl的xmlns:我=CLR的命名空间:Pipedream.Nodes>

< BORDER了borderThickness =1CornerRadius =20BorderBrush =黑背景=白>
<网格和GT;
<我:NodeContent X:NAME =NodeContentContainer保证金=20CONTENT ={绑定源= NodeControl,路径= NodeContent}/>
< /网格和GT;
< /边框>
< /用户控件>



通用 - 的XAML:

 < ResourceDictionary的
的xmlns =htt​​p://schemas.microsoft.com/winfx/2006/xaml/presentation
的xmlns:X =HTTP://模式。 microsoft.com/winfx/2006/xaml
的xmlns:地方=CLR的命名空间:Pipedream.Nodes>


<风格的TargetType ={X:类型本地:NodeContent}>
< setter属性=模板>
< Setter.Value>
<的ControlTemplate的TargetType ={X:类型本地:节点}>
<边框背景={TemplateBinding背景}
BorderBrush ={TemplateBinding BorderBrush}
了borderThickness ={TemplateBinding了borderThickness}>
< ContentPresenter />
< /边框>
< /控件模板>
< /Setter.Value>
< /二传手>
< /样式和GT;
< / ResourceDictionary的>


解决方案

您不能绑定类型的依赖属性 UIElementCollection 一般。尝试是这样的:



MultiChildDemo.xaml



没什么在这里看到。该StackPanel中会保留我们的子元素。你可以明显地做相当多的



代码:

  <用户控件X:类=Demo.MultiChildDemo
的xmlns =htt​​p://schemas.microsoft.com/winfx/2006/xaml/presentation
的xmlns:X =HTTP:// schemas.microsoft.com/winfx/2006/xaml
的xmlns:MC =http://schemas.openxmlformats.org/markup-compatibility/2006
的xmlns:D =HTTP:// schemas.microsoft.com/expression/blend/2008
的xmlns:试玩=CLR的命名空间:演示
MC:可忽略=D
D:DesignHeight =300D: DesignWidth =300>
< StackPanel的X:名称=PART_Host/>
< /用户控件>



MultiChildDemo.xaml.cs



重要要注意:




  • ContentPropertyAttribute 属性设置将由任何设置的属性通过这种类型的父元素包围的元件。因此,在<的任何元素; MultiChildDemo>< / MultiChildDemo方式> 将被添加到孩子属性

  • 我们正在扩展在用户控件。这并不需要一个完全自定义的控制。

  • 这是WPF好习惯使用,使性能 DependencyProperty.Register()和变种。你会发现,没有为儿童没有靠山变量属性:的DependencyProperty 需要存储的数据对我们的照顾。要是我们没有创造一个只读属性,这将使使用绑定和其他很酷的WPF功能。因此,要养成使用依赖属性,而不是普通的属性,你经常在互联网例子中看到的习惯是很重要的。

  • 这是一个相对简单的依赖属性的例子。我们所要做的就是复制引用了孩子的依赖属性,从而转发到 UIElementCollection.Add 来电。更为复杂的例子是在那里,特别是在MSDN



代码:

 使用System.Windows;使用System.Windows.Controls的
;
使用System.Windows.Markup;

命名空间演示
{
[ContentProperty(孩子)]
公共部分类MultiChildDemo:用户控件
{
公共静态只读由其DependencyPropertyKey ChildrenProperty = DependencyProperty.RegisterReadOnly(
儿童,
typeof运算(UIElementCollection),
typeof运算(MultiChildDemo),
新PropertyMetadata());

公共UIElementCollection儿童
{
{返回(UIElementCollection)的GetValue(ChildrenProperty.DependencyProperty); }
私人集合{的SetValue(ChildrenProperty,值); }
}

公共MultiChildDemo()
{
的InitializeComponent();
=儿童PART_Host.Children;
}
}
}



MultiChildDemoWindow.xaml



请注意标签是如何在<的直接后裔;演示:MultiChildDemo> 元素。你也可以将它们括在<演示:MultiChildDemo.Children> 元素。我们加入到MultiChild类 ContentPropertyAttribute 属性让我们可以省略这一步,虽然



代码:

 <窗​​口x:类=Demo.MultiChildDemoWindow
的xmlns =htt​​p://schemas.microsoft。 COM / WinFX的/ 2006 / XAML /演示
的xmlns:X =http://schemas.microsoft.com/winfx/2006/xaml
的xmlns:试玩=CLR的命名空间:演示
标题=MultiChildDemoWindowHEIGHT =300WIDTH =300>
<演示:MultiChildDemo>
<标签>测试1 LT; /标签>
<标签>测试2版; /标签>
<标签>测试3'; /标签>
< /演示:MultiChildDemo>
< /窗GT;


My task

Create a UserControl which should be able to contain any visual child which is available in WPF, the children are displayed in a container which is a child of the UserControl.

My Problem

I can't manage to get the children displayed correctly in my container, i tried serval ways and did not find a way which works in the designer. I also tried to use ContentControl but nothing gets displayed.

My approaches

First i found this link and i tried it with some variations. I managed to display the content in the right container but it does not work in the designer because the content-property is set-private and the designer want to override it. Placing everything in XAML works but this is not good when working with designers. This is may favorite way.

After this i tried to use ContentControl by binding it's Content-property to a bindable property of the UIElementCollection-type. This aproach is not throwing any errors in the designer, but i have to admit that i never see any control ( e.g. a Button ) in my container. It stays empty but has the children added.

Conclusion

After serval hours of searching for a easy and quick solution i decided to ask for solutions here. I'm a little disappointed. It would be really helpful if Microsoft could get a sample into MSDN.

I'm sure there must be a easy way to archive this.

Current situation

Thanks to Andrei Gavrila and jberger i archived to create a node which displays the content ( see code below ) but there are still two issues:- No designer support- The border ( see xaml ) is not shown in designer and not shown when the app is running there is even no margin

public class NodeContent : ContentControl
{
    static NodeContent()
    {
        DefaultStyleKeyProperty.OverrideMetadata(typeof(NodeContent), new FrameworkPropertyMetadata(typeof(NodeContent)));
    }
}

public partial class Node : UserControl, INotifyPropertyChanged
{
    UIElementCollection _Elements;

    public event PropertyChangedEventHandler PropertyChanged;

    public UIElementCollection NodeContent
    {
        get { return _Elements; }
        set
        {
            _Elements = value;
            OnPropertyChanged("NodeContent");
        }
    }

    public Node()
    {
        InitializeComponent();
        NodeContent = new UIElementCollection(NodeContentContainer, this);
    }



    protected void OnPropertyChanged(string name)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(name));
        }
    }
}

Node-Xaml:

<UserControl x:Class="Pipedream.Nodes.Node"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             mc:Ignorable="d"
             d:DesignHeight="216" d:DesignWidth="174" Background="Transparent" Name="NodeControl" xmlns:my="clr-namespace:Pipedream.Nodes">

    <Border BorderThickness="1" CornerRadius="20" BorderBrush="Black" Background="White">
        <Grid>
            <my:NodeContent x:Name="NodeContentContainer" Margin="20" Content="{Binding Source=NodeControl, Path=NodeContent}" />
        </Grid>
    </Border>
</UserControl>

Generic-Xaml:

<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:Pipedream.Nodes">


    <Style TargetType="{x:Type local:NodeContent}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type local:Node}">
                    <Border Background="{TemplateBinding Background}"
                            BorderBrush="{TemplateBinding BorderBrush}"
                            BorderThickness="{TemplateBinding BorderThickness}">
                        <ContentPresenter />
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</ResourceDictionary>
解决方案

You cannot bind dependency properties of type UIElementCollection, generally. Try something like this:

MultiChildDemo.xaml

Nothing much to see here. The StackPanel will hold our child elements. You could obviously do quite a bit more.

Code:

<UserControl x:Class="Demo.MultiChildDemo"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:demo="clr-namespace:Demo"
             mc:Ignorable="d"
             d:DesignHeight="300" d:DesignWidth="300">
    <StackPanel x:Name="PART_Host" />
</UserControl>

MultiChildDemo.xaml.cs

Important to note:

  • The ContentPropertyAttribute attribute sets the property that will be set by any elements enclosed by the parent element of this type. Thus, any elements within <MultiChildDemo></MultiChildDemo> will be added to the Children property.
  • We are extending a UserControl. This does not necessitate a completely custom control.
  • It is good practice in WPF to make properties using DependencyProperty.Register() and variants. You will notice that there is no backing variable for the Children property: DependencyProperty takes care of storing the data for us. Were we not creating a read-only property, this would enable the use of bindings and other cool WPF features. Thus, it is important to get into the habit of using dependency properties, rather than plain properties as you often see in examples around the Internet.
  • This is a relatively simple dependency property example. All we do is copy the reference to a child's dependency property, thereby forwarding calls to UIElementCollection.Add. Much more complex examples are out there, especially on MSDN.

Code:

using System.Windows;
using System.Windows.Controls;
using System.Windows.Markup;

namespace Demo
{
    [ContentProperty("Children")]
    public partial class MultiChildDemo : UserControl
    {
        public static readonly DependencyPropertyKey ChildrenProperty = DependencyProperty.RegisterReadOnly(
            "Children",
            typeof(UIElementCollection),
            typeof(MultiChildDemo),
            new PropertyMetadata());

        public UIElementCollection Children
        {
            get { return (UIElementCollection)GetValue(ChildrenProperty.DependencyProperty); }
            private set { SetValue(ChildrenProperty, value); }
        }

        public MultiChildDemo()
        {
            InitializeComponent();
            Children = PART_Host.Children;
        }
    }
}

MultiChildDemoWindow.xaml

Note how the labels are direct descendants of the <demo:MultiChildDemo> element. You could also enclose them in a <demo:MultiChildDemo.Children> element. The ContentPropertyAttribute attribute that we added to the MultiChild class allows us to omit this step, though.

Code:

<Window x:Class="Demo.MultiChildDemoWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:demo="clr-namespace:Demo"
        Title="MultiChildDemoWindow" Height="300" Width="300">
    <demo:MultiChildDemo>
        <Label>Test 1</Label>
        <Label>Test 2</Label>
        <Label>Test 3</Label>
    </demo:MultiChildDemo>
</Window>

这篇关于添加孩子用户控件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-21 01:29