I'm new both to WinUI and XAML and I'm creating a WinUI 3 Library that contains various CustomControl
.
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
<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.
Here in the XAML I've used TemplateBinding
with 2 DependecyProperty
that I should declare on the code behind of CustomContainer
.
Code behind of CustomTextBlock
control
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? Do they still need to be DependencyProperty
type?
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.
CodePudding user response:
In this sample, we have:
InnerControl
with aTextBlock
and anInnerText
dependency-property bound to theTextBlock
OuterControl
with anInnerControl
and aTextForInnerControl
dependency-property bound to theInnerControl
MainWindow
with aTextBox
and anOuterControl
where itsTextForInnerControl
is bound to theTextBox
The text coming form the TextBox
in the MainWindow
will be passed to the OuterControl
and then to the InnerControl
.
Here's the code:
InnerControl.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
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
<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
<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
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();
}
}