使用 child 元素创建 WPF 用户控件
Creating a WPF user control with a child element
我尝试创建一个 "container" 用户控件,它可以在 WPF 中将 UIElement
objects 显示为 child。控件的用法应如下所示:
<general:DisplayContainer Title="Hello">
<TextBlock x:Name="AnyUIElement" />
</general:DisplayContainer>
其中 TextBlock 只是一个示例。到目前为止,我创建了 UserControl 并像这样绑定标题 属性:
<Grid x:Name="Grid_Main">
<Border x:Name="Border_Main" BorderThickness="2" Margin="10" CornerRadius="5" Padding="7" />
<TextBlock x:Name="TextBlock_Title" Background="{Binding Background, ElementName=Grid_Main}" HorizontalAlignment="Left" VerticalAlignment="Top" Text="{Binding Path=Title, FallbackValue=Title}" Margin="20,2,0,0" Padding="3,0" />
</Grid>
代码隐藏文件如下所示:
public partial class DisplayContainer : UserControl
{
public DisplayContainer()
{
InitializeComponent();
this.DataContext = this;
}
public string Title
{
get { return (string)GetValue(TitleProperty); }
set { SetValue(TitleProperty, value); }
}
public static readonly DependencyProperty TitleProperty =
DependencyProperty.Register("Title",typeof(string), typeof(DisplayContainer));
}
现在,我如何修改我的控件,使我在使用控件时接受 XAML-file 中的 child 元素? child 应通过 Border_Main.Child
属性 显示。
提前致谢,
弗兰克
只需设置用户控件的模板属性
<UserControl ...>
<UserControl.Template>
<ControlTemplate TargetType="UserControl">
<StackPanel>
<TextBlock Text="{Binding Title,
RelativeSource={RelativeSource AncestorType=UserControl}}"/>
<ContentPresenter />
</StackPanel>
</ControlTemplate>
</UserControl.Template>
</UserControl>
并将显示的元素放在用户控件的内容中:
<local:DisplayContainer Title="A Title">
<TextBlock Text="Hello"/>
</local:DisplayContainer>
或者您可以将 DisplayContainer
定义为没有 .xaml
文件但带有 ControlTemplate
的 ContentControl
:
public partial class DisplayContainer : ContentControl
{
public DisplayContainer()
{
this.DataContext = this;
}
public string Title
{
get { return (string)GetValue(TitleProperty); }
set { SetValue(TitleProperty, value); }
}
public static readonly DependencyProperty TitleProperty =
DependencyProperty.Register("Title", typeof(string), typeof(DisplayContainer));
}
XAML:
<Window x:Class="WpfApp1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApp1"
mc:Ignorable="d"
Title="MainWindow" Height="300" Width="300">
<Window.Resources>
<Style TargetType="local:DisplayContainer">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:DisplayContainer">
<Grid x:Name="Grid_Main">
<Border x:Name="Border_Main" BorderThickness="2" Margin="10" CornerRadius="5" Padding="7">
<ContentPresenter />
</Border>
<TextBlock x:Name="TextBlock_Title" Background="{Binding Background, ElementName=Grid_Main}"
HorizontalAlignment="Left" VerticalAlignment="Top"
Text="{Binding Path=Title, RelativeSource={RelativeSource AncestorType=local:DisplayContainer}, FallbackValue=Title}" Margin="20,2,0,0" Padding="3,0" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<StackPanel>
<local:DisplayContainer Title="Hello">
<TextBlock Text="AnyUIElement..." />
</local:DisplayContainer>
</StackPanel>
</Window>
或者,另一种方式。
- 在 DisplayContainer
中创建 UIElement 类型的 DependencyProperty 'Child'
- 将 ContentPresenter 添加到 Border_Main,其内容绑定到 Child DependencyProperty。
- 使用 ContentProperty 属性("Child" 的值)标记 DisplayContainer
如果您需要有不同的部分,您可以添加多个 DP。只需添加更多绑定到不同 DP(子、页眉、页脚等)的 ContentPresenters。
DisplayContainer.cs
[System.Windows.Markup.ContentProperty("Child")]
public partial class DisplayContainer : UserControl
{
public DisplayContainer()
{
InitializeComponent();
}
public string Title
{
get { return (string)GetValue(TitleProperty); }
set { SetValue(TitleProperty, value); }
}
public static readonly DependencyProperty TitleProperty = DependencyProperty.Register("Title", typeof(string), typeof(DisplayContainer));
public UIElement Child
{
get { return (UIElement)GetValue(ChildProperty); }
set { SetValue(ChildProperty, value); }
}
public static readonly DependencyProperty ChildProperty = DependencyProperty.Register("Child", typeof(UIElement), typeof(DisplayContainer));
}
DisplayContainer.xaml
<UserControl x:Class="WpfApp19.DisplayContainer"
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:local="clr-namespace:WpfApp19"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid x:Name="Grid_Main">
<Border x:Name="Border_Main" BorderThickness="2" Margin="10" CornerRadius="5" Padding="7">
<ContentPresenter Content="{Binding Child, RelativeSource={RelativeSource AncestorType=UserControl}}" />
</Border>
<TextBlock x:Name="TextBlock_Title" Background="{Binding Background, ElementName=Grid_Main}" HorizontalAlignment="Left" VerticalAlignment="Top" Text="{Binding Path=Title, FallbackValue=Title, RelativeSource={RelativeSource AncestorType=UserControl}}" Margin="20,2,0,0" Padding="3,0" />
</Grid>
</UserControl>
MainWindow.xaml
<Window x:Class="WpfApp19.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:general="clr-namespace:WpfApp19"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid>
<general:DisplayContainer Title="Hello">
<StackPanel>
<TextBlock Text="Test1" />
<TextBlock Text="Test2" />
</StackPanel>
<!-- Alternative way of setting Child - if you had more DPs (Header, Footer, etc..) you would have to set their content this way
<general:DisplayContainer.Child>
<TextBlock Text="AnyUIElement" />
</general:DisplayContainer.Child>
-->
</general:DisplayContainer>
</Grid>
</Window>
我尝试创建一个 "container" 用户控件,它可以在 WPF 中将 UIElement
objects 显示为 child。控件的用法应如下所示:
<general:DisplayContainer Title="Hello">
<TextBlock x:Name="AnyUIElement" />
</general:DisplayContainer>
其中 TextBlock 只是一个示例。到目前为止,我创建了 UserControl 并像这样绑定标题 属性:
<Grid x:Name="Grid_Main">
<Border x:Name="Border_Main" BorderThickness="2" Margin="10" CornerRadius="5" Padding="7" />
<TextBlock x:Name="TextBlock_Title" Background="{Binding Background, ElementName=Grid_Main}" HorizontalAlignment="Left" VerticalAlignment="Top" Text="{Binding Path=Title, FallbackValue=Title}" Margin="20,2,0,0" Padding="3,0" />
</Grid>
代码隐藏文件如下所示:
public partial class DisplayContainer : UserControl
{
public DisplayContainer()
{
InitializeComponent();
this.DataContext = this;
}
public string Title
{
get { return (string)GetValue(TitleProperty); }
set { SetValue(TitleProperty, value); }
}
public static readonly DependencyProperty TitleProperty =
DependencyProperty.Register("Title",typeof(string), typeof(DisplayContainer));
}
现在,我如何修改我的控件,使我在使用控件时接受 XAML-file 中的 child 元素? child 应通过 Border_Main.Child
属性 显示。
提前致谢,
弗兰克
只需设置用户控件的模板属性
<UserControl ...>
<UserControl.Template>
<ControlTemplate TargetType="UserControl">
<StackPanel>
<TextBlock Text="{Binding Title,
RelativeSource={RelativeSource AncestorType=UserControl}}"/>
<ContentPresenter />
</StackPanel>
</ControlTemplate>
</UserControl.Template>
</UserControl>
并将显示的元素放在用户控件的内容中:
<local:DisplayContainer Title="A Title">
<TextBlock Text="Hello"/>
</local:DisplayContainer>
或者您可以将 DisplayContainer
定义为没有 .xaml
文件但带有 ControlTemplate
的 ContentControl
:
public partial class DisplayContainer : ContentControl
{
public DisplayContainer()
{
this.DataContext = this;
}
public string Title
{
get { return (string)GetValue(TitleProperty); }
set { SetValue(TitleProperty, value); }
}
public static readonly DependencyProperty TitleProperty =
DependencyProperty.Register("Title", typeof(string), typeof(DisplayContainer));
}
XAML:
<Window x:Class="WpfApp1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApp1"
mc:Ignorable="d"
Title="MainWindow" Height="300" Width="300">
<Window.Resources>
<Style TargetType="local:DisplayContainer">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:DisplayContainer">
<Grid x:Name="Grid_Main">
<Border x:Name="Border_Main" BorderThickness="2" Margin="10" CornerRadius="5" Padding="7">
<ContentPresenter />
</Border>
<TextBlock x:Name="TextBlock_Title" Background="{Binding Background, ElementName=Grid_Main}"
HorizontalAlignment="Left" VerticalAlignment="Top"
Text="{Binding Path=Title, RelativeSource={RelativeSource AncestorType=local:DisplayContainer}, FallbackValue=Title}" Margin="20,2,0,0" Padding="3,0" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<StackPanel>
<local:DisplayContainer Title="Hello">
<TextBlock Text="AnyUIElement..." />
</local:DisplayContainer>
</StackPanel>
</Window>
或者,另一种方式。
- 在 DisplayContainer 中创建 UIElement 类型的 DependencyProperty 'Child'
- 将 ContentPresenter 添加到 Border_Main,其内容绑定到 Child DependencyProperty。
- 使用 ContentProperty 属性("Child" 的值)标记 DisplayContainer
如果您需要有不同的部分,您可以添加多个 DP。只需添加更多绑定到不同 DP(子、页眉、页脚等)的 ContentPresenters。
DisplayContainer.cs
[System.Windows.Markup.ContentProperty("Child")]
public partial class DisplayContainer : UserControl
{
public DisplayContainer()
{
InitializeComponent();
}
public string Title
{
get { return (string)GetValue(TitleProperty); }
set { SetValue(TitleProperty, value); }
}
public static readonly DependencyProperty TitleProperty = DependencyProperty.Register("Title", typeof(string), typeof(DisplayContainer));
public UIElement Child
{
get { return (UIElement)GetValue(ChildProperty); }
set { SetValue(ChildProperty, value); }
}
public static readonly DependencyProperty ChildProperty = DependencyProperty.Register("Child", typeof(UIElement), typeof(DisplayContainer));
}
DisplayContainer.xaml
<UserControl x:Class="WpfApp19.DisplayContainer"
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:local="clr-namespace:WpfApp19"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid x:Name="Grid_Main">
<Border x:Name="Border_Main" BorderThickness="2" Margin="10" CornerRadius="5" Padding="7">
<ContentPresenter Content="{Binding Child, RelativeSource={RelativeSource AncestorType=UserControl}}" />
</Border>
<TextBlock x:Name="TextBlock_Title" Background="{Binding Background, ElementName=Grid_Main}" HorizontalAlignment="Left" VerticalAlignment="Top" Text="{Binding Path=Title, FallbackValue=Title, RelativeSource={RelativeSource AncestorType=UserControl}}" Margin="20,2,0,0" Padding="3,0" />
</Grid>
</UserControl>
MainWindow.xaml
<Window x:Class="WpfApp19.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:general="clr-namespace:WpfApp19"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid>
<general:DisplayContainer Title="Hello">
<StackPanel>
<TextBlock Text="Test1" />
<TextBlock Text="Test2" />
</StackPanel>
<!-- Alternative way of setting Child - if you had more DPs (Header, Footer, etc..) you would have to set their content this way
<general:DisplayContainer.Child>
<TextBlock Text="AnyUIElement" />
</general:DisplayContainer.Child>
-->
</general:DisplayContainer>
</Grid>
</Window>