Page 32 - MSDN Magazine, May 2019
P. 32

Figure 5 Using the Class Attribute to Set the Content Property
Accessing Internal Controls The x:Name directive declares the field name auto-generated in a codebehind. Give a checkbox an x:Name of MyCheckBox and the generator will create a field in your class called MyCheckBox.
By contrast, x:Key (for resources only) doesn’t create a field. It adds resources to a dictionary of unresolved types until they’re first used. For resources, x:Key offers performance improvements.
Because x:Name creates a backing field, it can’t be used in a ControlTemplate; templates are decoupled from any backing class. Instead, you use the Name property.
Name is a dependency property on FrameworkElement, an ancestor of Control. You use it when you can’t use x:Name. Name and x:Name are mutually exclusive in a given scope because of FindName.
FindName is a XAML method used to locate objects by name; it works with Name or x:Name. It’s reliable in the codebehind, but not in templated controls where you must use GetTemplateChild:
protected override void OnApplyTemplate() {
if (GetTemplateChild("AgreeCheckbox") is CheckBox c) {
[ContentProperty(Name = "Text")] public sealed class MyControl : Control {
public MyControl() => DefaultStyleKey = typeof(MyControl); public string Text
{
get => (string)GetValue(TextProperty);
set => SetValue(TextProperty, value); }
public static readonly DependencyProperty TextProperty = DependencyProperty.Register(nameof(Text), typeof(string),
typeof(MyControl), new PropertyMetadata(default(string))); }
control, and the binding is executed and rendered at design time:
<controls:MyControl Text="My outside value." />
The syntax to use my custom control is simple. I’ll make it better by allowing the developer to use inline text. This is the most intuitive syntax to set an element’s content. XAML provides a class attribute to help me do that, as Figure 5 shows.
Notice the ContentProperty attribute, which comes from the Windows.UI.Xaml.Markup namespace. It indicates to which prop- erty direct, inline content declared in XAML should be written. So, now, I can declare my content like this:
<controls:MyControl> My inline value! </controls:MyControl>
It’s beautiful. Templated controls give you the flexibility to design control interaction and syntax in whatever way seems most intuitive to you. Figure 6 shows the result of introducing ContentProperty to the control.
The ContentControl Where previously I had to create a custom property and map that property to the content of the control, XAML provides a control already built for that. It’s known as ContentControl and its property is called Content. ContentControl also provides the ContentTemplate and ContentTransition prop- erties to handle visualization and transitions. Button, CheckBox, Frame and many standard XAML controls inherit ContentControl. Mine could have, too; I’d just use Content instead of Text:
public sealed class MyControl2 : ContentControl {
// Empty }
In this code, notice the terse syntax to create a custom con- trol with a Content property. ContentControl auto-renders as a ContentPresenter when declared. It’s a fast, easy solution. There’s a caveat, however: ContentControl doesn’t support literal strings in XAML. Because it violates my goal to make my control support literal strings, I’ll stick to Control, considering ContentControl another time.
Figure 6 Design Preview 26 msdn magazine
c.Content = "I really agree!";
}
GetTemplateChild is a helper method used in the OnApply- Template override to find controls created by a ControlTemplate. Use it to find references to internal controls.
Changing the Template Re-templating the control is simple, but I’ve built the class to expect controls with certain names. I must ensure the new template maintains this dependency. Let’s build a new ControlTemplate:
<ControlTemplate TargetType="controls:MyControl" x:Key="MyNewStyle">
Small changes to a ControlTemplate are normal. You don’t need to start from scratch. In the Visual Studio Document Outline pane, right-click any control and extract a copy of its current template (see Figure 7).
If I maintain its dependencies, my new ControlTemplate can totally change the visuals and behaviors of a control. Declaring an explicit style on the control tells the framework to ignore the default implicit style:
<controls:MyControl Style="{StaticResource MyControlNewStyle}">
But this rewriting of the ControlTemplate comes with a warn- ing. Control designers and developers must be careful to support accessibility and localization capabilities. It’s easy to remove these by mistake.
TemplatePartAttribute It would be handy if a custom control could communicate the named elements it expects. Some named
}
Figure 7 Extracting a Control Template
XAML


































































































   30   31   32   33   34