Моя задача
Создайте UserControl
, который должен содержать любого визуального дочернего элемента, доступного в WPF, дочерние элементы отображаются в контейнере, который является дочерним элементом UserControl
.
Моя проблема
Мне не удается правильно отобразить детей в моем контейнере, я пробовал сервальные способы и не нашел способа, который работает в конструкторе. Я также пытался использовать ContentControl
, но ничего не отображается.
Мои подходы
Сначала я нашел эту ссылку, и я попробовал ее с некоторыми вариациями. Мне удалось отобразить контент в нужном контейнере, но он не работает в конструкторе, потому что свойство content установлено в private и дизайнер хочет переопределить его. Размещение всего в XAML работает, но это не очень хорошо при работе с дизайнерами. Это может быть любимый способ.
После этого я попытался использовать ContentControl
, привязав его Content
-свойство к привязываемому свойству UIElementCollection
-типа. Этот подход не вызывает каких-либо ошибок в конструкторе, но я должен признать, что никогда не вижу никакого элемента управления (например, Button
) в своем контейнере. Он остается пустым, но к нему добавляются дети.
Заключение
После нескольких часов поисков простого и быстрого решения я решил спросить здесь. Я немного разочарован. Было бы очень полезно, если бы Microsoft смогла получить образец в MSDN.
Я уверен, что должен быть простой способ заархивировать это.
Текущая ситуация
Благодаря Андрею Гавриле и jberger я заархивировал, чтобы создать узел, который отображает контент (см. Код ниже), но есть еще две проблемы:
- Нет дизайнерской поддержки
- Граница (см. 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));
}
}
}
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>