简体   繁体   English

在 C# WinUI 3 中创建包含其他 CustomControls 的 CustomControl

[英]Create a CustomControl in C# WinUI 3 containing other CustomControls

I'm new both to WinUI and XAML and I'm creating a WinUI 3 Library that contains various CustomControl .我是 WinUI 和 XAML 的新手,我正在创建一个包含各种CustomControlWinUI 3 库

They're all independent and can be used stand alone.它们都是独立的,可以单独使用。 But one of those controls, is made by embedding some other custom controls that are in the library.但是其中一个控件是通过嵌入库中的其他一些自定义控件来制作的。

XAML of Container control XAML 容器控制

<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:MyCustomControls">
    
    <Style TargetType="local:CustomContainer">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="local:CustomContainer">
                    <StackPanel>
                        <local:CustomTextBlock x:Name="Text"
                                            DisplayMode="{TemplateBinding DisplayMode}"
                                            Message="{TemplateBinding Message}">
                        </local:CustomTextBlock>

                        <local:CustomIndicator x:Name="Indicator"></local:CustomIndicator>
                    </StackPanel>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
    
</ResourceDictionary>

As you can see in the sample, the CustomTextBlock custom control contains 2 DependecyProperty ( DisplayMode and Message ) that I need to "replicate" on the CustomContainer control to be able to set them when I want to use the CustomContainer on a page.正如您在示例中看到的那样, CustomTextBlock自定义控件包含 2 个DependecyPropertyDisplayModeMessage ),当我想在页面上使用CustomContainer时,我需要在CustomContainer控件上“复制”它们以便能够设置它们。

Here in the XAML I've used TemplateBinding with 2 DependecyProperty that I should declare on the code behind of CustomContainer .在 XAML 中,我使用了带有 2 个DependecyPropertyTemplateBinding ,我应该在CustomContainer后面的代码中声明它。

Code behind of CustomTextBlock control CustomTextBlock控件背后的代码

private static readonly DependencyProperty DisplayModeProperty = DependencyProperty.Register(
    nameof(DisplayMode), typeof(bool), typeof(CustomTextBlock), new PropertyMetadata(null));

public bool DisplayMode
{
    get => (bool)GetValue(DisplayModeProperty);
    set => SetValue(DisplayModeProperty, value);
}

private static readonly DependencyProperty MessageProperty = DependencyProperty.Register(
    nameof(Message), typeof(string), typeof(CustomTextBlock), new PropertyMetadata(default(string), (d, e) => ((CustomTextBlock)d).MessageChanged(d, e)));

public string Message
{
    get => (string)GetValue(MessageProperty);
    set => SetValue(MessageProperty, value);
}

How can I expose the 2 properties of CustomTextBlock on the CustomContainer control so that those values directly sets the underlying properties?如何在CustomContainer控件上公开CustomTextBlock的 2 个属性,以便这些值直接设置基础属性? Do they still need to be DependencyProperty type?他们还需要是DependencyProperty类型吗?

It seems something like wrapping or inheritance concept, but I'm not able to figure it out, especially for the Message property that is also registered with an event handler.它似乎类似于包装或 inheritance 概念,但我无法弄清楚,特别是对于也注册到事件处理程序的Message属性。

In this sample, we have:在此示例中,我们有:

  • InnerControl with a TextBlock and an InnerText dependency-property bound to the TextBlock带有TextBlockInnerControl和绑定到TextBlockInnerText依赖属性
  • OuterControl with an InnerControl and a TextForInnerControl dependency-property bound to the InnerControl带有OuterControlTextForInnerControl依赖属性的InnerControl绑定到InnerControl
  • MainWindow with a TextBox and an OuterControl where its TextForInnerControl is bound to the TextBox带有TextBoxOuterControlMainWindow ,其中TextForInnerControl绑定到TextBox

The text coming form the TextBox in the MainWindow will be passed to the OuterControl and then to the InnerControl .来自MainWindowTextBox的文本将被传递给OuterControl ,然后传递给InnerControl

Here's the code:这是代码:

InnerControl.cs内部控件.cs

using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;

namespace WinUI3CustomControlTest;

public sealed class InnerControl : Control
{
    public static readonly DependencyProperty InnerTextProperty =
        DependencyProperty.Register(
            nameof(InnerText),
            typeof(string),
            typeof(InnerControl),
            new PropertyMetadata(string.Empty));

    public InnerControl()
    {
        this.DefaultStyleKey = typeof(InnerControl);
    }

    public string InnerText
    {
        get => (string)GetValue(InnerTextProperty);
        set => SetValue(InnerTextProperty, value);
    }
}

OuterControl.cs外部控件.cs

using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;

namespace WinUI3CustomControlTest;

public sealed class OuterControl : Control
{
    public static readonly DependencyProperty TextForInnerControlProperty =
        DependencyProperty.Register(
            nameof(TextForInnerControl),
            typeof(string),
            typeof(OuterControl),
            new PropertyMetadata(string.Empty));

    public OuterControl()
    {
        this.DefaultStyleKey = typeof(OuterControl);
    }

    public string TextForInnerControl
    {
        get => (string)GetValue(TextForInnerControlProperty);
        set => SetValue(TextForInnerControlProperty, value);
    }
}

Generic.xaml通用.xaml

<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:WinUI3CustomControlTest">

    <Style TargetType="local:OuterControl">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="local:OuterControl">
                    <StackPanel Orientation="Vertical">
                        <local:InnerControl InnerText="{TemplateBinding TextForInnerControl}" />
                    </StackPanel>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

    <Style TargetType="local:InnerControl">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="local:InnerControl">
                    <StackPanel>
                        <TextBlock Text="{TemplateBinding InnerText}" />
                    </StackPanel>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</ResourceDictionary>

MainWindow.xaml主窗口.xaml

<Window
    x:Class="WinUI3CustomControlTest.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:local="using:WinUI3CustomControlTest"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">

    <StackPanel>
        <TextBox
            x:Name="InputTextBox"
            PlaceholderText="Enter you text.." />
        <Button
            Click="Button_Click"
            Content="Set text programmatically" />
        <local:OuterControl
            x:Name="MyOuterControl"
            TextForInnerControl="{x:Bind InputTextBox.Text, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
    </StackPanel>

</Window>

MainWindow.xaml.cs主窗口.xaml.cs

using Microsoft.UI.Xaml;
using System;

namespace WinUI3CustomControlTest;

public sealed partial class MainWindow : Window
{
    public MainWindow()
    {
        this.InitializeComponent();
    }

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        this.MyOuterControl.TextForInnerControl = DateTime.Now.ToString();
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM