使用子元素创建WPF用户控件

时间:2018-04-04 12:53:16

标签: wpf user-controls

我尝试创建一个“容器”用户控件,可以在WPF中将UIElement个对象显示为子对象。控件的用法应如下所示:

<general:DisplayContainer Title="Hello">
  <TextBlock x:Name="AnyUIElement" />
</general:DisplayContainer>

其中TextBlock只是一个例子。到目前为止,我创建了UserControl并绑定了Title属性,如下所示:

<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>

Codebehind文件如下所示:

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文件中的子元素?应通过Border_Main.Child属性显示孩子。

提前致谢,
弗兰克

3 个答案:

答案 0 :(得分:1)

只需设置UserControl的模板属性

即可
// obtain a validator
ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
Validator validator = factory.getValidator();

// do a test
Set<ConstraintViolation<User>> constraintViolations = validator.validate(user2);
Assert.assertEquals(0, constraintViolations.size());

并将显示的元素放在UserControl的内容中:

<UserControl ...>
    <UserControl.Template>
        <ControlTemplate TargetType="UserControl">
            <StackPanel>
                <TextBlock Text="{Binding Title,
                           RelativeSource={RelativeSource AncestorType=UserControl}}"/>
                <ContentPresenter />
            </StackPanel>
        </ControlTemplate>
    </UserControl.Template>
</UserControl>

答案 1 :(得分:1)

或者您可以将DisplayContainer定义为ContentControl,而不是.xaml文件但ControlTemplate

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>

答案 2 :(得分:0)

或者,换句话说。

  • 创建一个DependencyProperty&#39; Child&#39; DisplayContainer中的UIElement类型
  • 将ContentPresenter添加到Border_Main,并将其内容绑定到Child DependencyProperty。
  • 使用ContentProperty属性标记DisplayContainer(值&#34; Child&#34;)

如果您需要不同的部分,可以添加许多DP。只需添加更多绑定到不同DP(Content,Header,Footer等)的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>