我的任务
创建一个UserControl,它应该能够包含任何在WPF中可用的可视子程序,这些子元素显示在一个容器中,容器是UserControl的一个子容器。
我的问题
我无法使孩子们正确地显示在我的容器中,我尝试了服务方式,但没有找到在设计师中工作的方法。我也尝试使用ContentControl,但没有显示任何内容。
我的方法
首先,我找到了这链接,并尝试了一些变体。我设法在正确的容器中显示内容,但是它在设计器中不工作,因为是设置为私有的,而设计器想要覆盖它。将所有内容都放在XAML中是可行的,但在使用设计器时这并不好。这可能是最受欢迎的方式。
在此之后,我尝试通过将ContentControl的Content-property绑定到UIElementCollection-type的可绑定属性来使用UIElementCollection。这并不是在设计器中抛出任何错误,但我必须承认,我从未在容器中看到任何控件(例如Button )。它仍然是空的,但是孩子们补充说。
结论
经过几个小时的努力寻找一个简单快捷的解决方案后,我决定在这里寻求解决方案。我有点失望。如果微软能够在MSDN中获得一个示例,这将是非常有帮助的。
我相信一定有一个简单的方法来存档这个。
现状
由于Andrei Gavrila和jberger,我创建了一个显示内容的节点(见下面的代码),但仍然存在两个问题:-不支持设计器--在designer中没有显示边框(见xaml ),在应用程序运行时也没有显示,甚至没有空白。
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));
}
}
}节点-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>通用-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>发布于 2012-02-08 01:07:24
通常,不能绑定UIElementCollection类型的依赖项属性。试着做这样的事情:
MultiChildDemo.xaml
这里没什么可看的。StackPanel将保存我们的子元素。显然你可以做得更多。
代码:
<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
值得注意的是:
ContentPropertyAttribute属性设置将由此类型的父元素所包含的任何元素设置的属性。因此,<MultiChildDemo></MultiChildDemo>中的任何元素都将添加到Children属性中。UserControl。这并不需要一个完全自定义的控件。DependencyProperty.Register()和变体创建属性是很好的实践。您将注意到,Children属性没有备份变量:DependencyProperty负责为我们存储数据。如果我们没有创建一个只读属性,这将允许使用绑定和其他酷WPF功能。因此,重要的是养成使用依赖属性的习惯,而不是通常在Internet上的示例中看到的普通属性。UIElementCollection.Add。还有更复杂的例子,特别是在MSDN上。代码:
using System.Windows;
using System.Windows.Controls;
using System.Windows.Markup;
namespace Demo
{
[ContentProperty(nameof(Children))] // Prior to C# 6.0, replace nameof(Children) with "Children"
public partial class MultiChildDemo : UserControl
{
public static readonly DependencyPropertyKey ChildrenProperty = DependencyProperty.RegisterReadOnly(
nameof(Children), // Prior to C# 6.0, replace nameof(Children) with "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
注意标签是<demo:MultiChildDemo>元素的直接后代。您还可以将它们括在<demo:MultiChildDemo.Children>元素中。但是,我们添加到ContentPropertyAttribute类中的MultiChild属性允许我们省略这个步骤。
代码:
<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>发布于 2012-02-03 12:50:11
首先,尝试理解用户控制和自定义控件(控制/内容控制)之间的区别。
为了保持简单:
“标准的WPF控件提供了大量内置功能。如果预置控件的功能(如进度条或滑块)与要合并的功能匹配,则应为该预先存在的控件创建一个新模板,以实现您想要的外观。创建一个新模板是创建自定义元素的最简单解决方案,因此您应该首先考虑该选项。 如果要合并到应用程序中的功能可以通过现有控件和代码的组合来实现,请考虑创建用户控件。用户控件使您能够将单个接口中的多个预先存在的控件绑定在一起,并添加确定它们的行为方式的代码。 如果没有预先存在的控件或控件组合可以实现所需的功能,请创建自定义控件。自定义控件使您能够创建一个全新的模板,该模板定义控件的可视化表示形式,并添加确定控件功能的自定义代码。“
亚当内森- WPF释放4
现在,如果您只想要一个ContentControl:
对于作为内容的多个项,请查看ItemsControl
上述步骤修改如下:
派生项控制
public class MyCtrl : ItemsControl
{
static MyCtrl()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(MyCtrl), new FrameworkPropertyMetadata(typeof(MyCtrl)));
}
}修改Generic.xaml以包括ItemsPresenter
<Style TargetType="{x:Type local:MyCtrl}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:MyCtrl}">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<ItemsPresenter />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>使用控件
<StackPanel>
<ctrl:MyCtrl>
<Button Width="100" Height="50">Click</Button>
<Button Width="100" Height="50">Click</Button>
<Button Width="100" Height="50">Click</Button>
</ctrl:MyCtrl>
</StackPanel>如前所述,对于这种简单的情况,不需要派生ItemsControl,而只需使用ItemsControl并为其定义一个模板。在计划通过添加功能进行扩展时派生ItemsControl
编辑:
在设计器中没有显示边框(参见xaml ),在应用程序运行时也没有显示边框,甚至没有边距。
应该在控件本身上设置边框属性:
<ctrl:MyCtrl BorderBrush="Red" BorderThickness="3" Background="Green" >发布于 2013-09-20 13:01:47
只需移除UserControl标记并用网格替换
https://stackoverflow.com/questions/9094486
复制相似问题