Page 31 - MSDN Magazine, May 2019
P. 31
The dependency property is necessary to support data binding. Robust controls support basic use cases like data binding. Plus, the dependency property adds only a single line to my code base:
<TextBox Text="{x:Bind Text, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
Two-way data binding for custom properties in user controls is supported without INotifyPropertyChanged. This is because dependency properties raise internal changed events that the binding framework monitors. It’s its own kind of INotifyPropertyChanged.
The preceding code reminds us that UpdateSourceTrigger deter- mines when changes are registered. Possible values are Explicit, Lost- Focus and PropertyChanged. The latter occurs as changes are made.
Roadblocks The consuming developer may want to set the con- tent property of the user control. This is an intuitive approach, but it’s not supported by user controls. The property is already set to the XAML I declared:
<Controls:MyUserControl> Lorem Ipsum
</Controls:MyUserControl>
This syntax overwrites the content property: the TextBlock, CheckBox and Button. If I consider re-templating a basic XAML use case, my user control fails to deliver a complete, robust experi- ence. User controls are easy, but offer little control or extensibility. An intuitive syntax and re-templating support are part of a common experience. It’s time to consider a templated control.
XAML has seen massive improvements in memory consumption, performance, accessibility and visual consistency.
Templated Controls
XAML has seen massive improvements in memory consumption, performance, accessibility and visual consistency. Developers love XAML because it’s flexible. Templated controls are a case in point.
Templated controls can define something completely new, but are typically a composite of several existing controls. The example here of a TextBlock, CheckBox and Button together is a classic scenario.
By the way, don’t confuse templated controls with custom con- trols. A templated control is a custom layout. A custom control is just a class inheriting an existing control without any custom styling. Sometimes, if all you need is an extra method or property on an existing control, custom controls are a great option; their visu- als and logic are already in place and you’re simply extending them.
Control Template A control’s layout is defined by a ControlTem- plate. This special resource is applied at run time. Every box and button resides in the ControlTemplate. A control’s template can be easily accessed by the Template property. That Template property isn’t read-only. Developers can set it to a custom ControlTemplate, msdnmagazine.com
transforming a control’s visuals and behavior to meet their partic- ular needs. That’s the power of re-templating:
<ControlTemplate> <StackPanel Padding="20">
<ContentControl Content="{TemplateBinding Content}" /> <CheckBox>I agree!</CheckBox> <Button>Submit1</Button>
</StackPanel> </ControlTemplate>
ControlTemplate XAML looks like any other layout declaration. In the preceding code, notice the special TemplateBinding markup extension. This special binding is tuned for one-way template oper- ations. Since Windows 10 version 1809, x:Bind syntax is supported in UWP ControlTemplate definitions. This allows for performant, com- piled, two-way and function bindings in templates. TemplateBinding works great in most cases.
Generic.xaml To create a templated control, select Templated Control in the Add New Item dialog. This introduces three files: the XAML file; its codebehind; and themes/generic.xaml, which holds the ControlTemplate. The themes/generic.xaml file is identical to WPF. It’s special. The framework merges it into your app’s resources auto- matically. Resources defined here are scoped at the application level:
<Style TargetType="controls:MyControl"> <Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="controls:MyControl" />
</Setter.Value> </Setter>
</Style>
ControlTemplates are applied using implicit styles: styles without a key. Explicit styles have a key used to apply them to controls; implicit styles are applied based on TargetType. So, you must set DefaultStyleKey:
public sealed class MyControl : Control {
public MyControl() => DefaultStyleKey = typeof(MyControl); }
This code sets the DefaultStyleKey, determining which style is implicitly applied to your control. I’m setting it to the correspond- ing value of the TargetType in the ControlTemplate:
<ControlTemplate TargetType="controls:MyControl"> <StackPanel Padding="20">
<TextBlock Text="{TemplateBinding Text}" /> <CheckBox Name="AgreeCheckbox">I agree!</CheckBox> <Button IsEnabled="{Binding IsChecked,
ElementName=AgreeCheckbox}">Submit</Button> </StackPanel>
</ControlTemplate>
TemplateBinding binds the TextBlock’s Text property to the custom dependency property copied from the user control to the templated control. TemplateBinding is one way, very efficient and generally the best option.
Figure 4 shows the result of my work in the designer. The custom layout declared in the ControlTemplate is applied to my custom
Figure 4 Preview Transparently Using Internal Properties
May 2019 25