
So, we again talk about controls on the UWP platform.
In the
previous part, we learned about the means of expanding existing controls without interfering with their internal structure. However, it is not always possible to achieve the desired result with little blood by means of attached properties (Attached Properties) or behaviors (Behaviors).
Part 2. Modifying Existing Controls')
For a better understanding of which vector the further discussion will develop in, let us give a picture illustrating the vision of what “levels” of influence on controls can be distinguished.
Impact Levels on ControlsIt shows that the previous part concerned the outermost level. On it we influence the control through the above means of extensions, as well as through the redefinition of styles. To complete the picture, this level can also include the indication of the values of the properties of the controls that they provide to the outside world.
The next level of exposure is to interfere with the layout of the template of an existing control.
To start working with the markup, we obviously need to get it. Two sources will help us with this:
•
Official Microsoft
documentation . This page contains a list of controls supplied with UWP for each of which you can get a markup template.
• A Blend For Visual Studio application that can provide control patterns

Creating a copy of the control pattern in Blend

Create a copy of the
Button template

Copy of the
button template
Both methods have their own advantages.
• Documentation:
- easier and faster access to the template,
- explicit attention to the
ThemeResources and
VisualStateManager states it
uses• Blend:
- can be used as a sandbox to work with the desired template
- easy access to child object templates,
- additional IDE features to facilitate the work when creating animations
Having templates, we can start working with them. At first, they can cause a slight confusion in markup volumes, but it becomes much easier to navigate if you remember that the control patterns of UWP and most third-party developers adhere to a certain unwritten convention.
The general structure of the control templateLet's take a look at the example of the
CheckBox control template.
<Style TargetType="CheckBox"> <Setter Property="Background" Value="Transparent" /> <Setter Property="Foreground" Value="{ThemeResource SystemControlForegroundBaseHighBrush}"/> <Setter Property="Padding" Value="8,5,0,0" /> <Setter Property="HorizontalAlignment" Value="Left" /> <Setter Property="VerticalAlignment" Value="Center" /> <Setter Property="HorizontalContentAlignment" Value="Left"/> <Setter Property="VerticalContentAlignment" Value="Top"/> <Setter Property="FontFamily" Value="{ThemeResource ContentControlThemeFontFamily}" /> <Setter Property="FontSize" Value="{ThemeResource ControlContentThemeFontSize}" /> <Setter Property="MinWidth" Value="120" /> <Setter Property="MinHeight" Value="32" /> <Setter Property="UseSystemFocusVisuals" Value="True" /> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="CheckBox"> <Grid Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}"> <Grid.ColumnDefinitions> <ColumnDefinition Width="20" /> <ColumnDefinition Width="*" /> </Grid.ColumnDefinitions> <Grid VerticalAlignment="Top" Height="32"> <Rectangle x:Name="NormalRectangle" Fill="Transparent" Stroke="{ThemeResource SystemControlForegroundBaseMediumHighBrush}" StrokeThickness="{ThemeResource CheckBoxBorderThemeThickness}" UseLayoutRounding="False" Height="20" Width="20" /> <FontIcon x:Name="CheckGlyph" FontFamily="{ThemeResource SymbolThemeFontFamily}" Glyph="" FontSize="20" Foreground="{ThemeResource SystemControlHighlightAltChromeWhiteBrush}" Opacity="0" /> </Grid> <ContentPresenter x:Name="ContentPresenter" ContentTemplate="{TemplateBinding ContentTemplate}" ContentTransitions="{TemplateBinding ContentTransitions}" Content="{TemplateBinding Content}" Margin="{TemplateBinding Padding}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" Grid.Column="1" AutomationProperties.AccessibilityView="Raw" TextWrapping="Wrap" /> </Grid> </ControlTemplate> </Setter.Value> </Setter> </Style>
Copy of
checkbox template
In this template, we can distinguish several parts of it:
• A set of simple setters of the form
<Setter Property = "Property_Name" Value = "Property_Value" /> . They perform the function of specifying default values for the control's properties. In particular, for example, the default
CheckBox cannot have a width less than 120. In this example, it can be seen that some problems in the layout process can come from the default template, which can “hinder” the achievement of the desired result.
• The list of simple setters ends with the
<Setter Property = "Template"> ... </ Setter> setter, which defines the framework of the control structure. This framework can be divided into two main parts:
- Directly the markup of the control template consisting of other controls with an indication of the default property values
- The VisualStateGroups collection defines a set of visual states of controls, in one of which it can be located at a specific moment.

List of Visual States
CheckBoxAfter reviewing the list of visual states of the
CheckBox control, we see that there are definitely 4 visual states for each of the 3 values of the
IsChecked property
: true, false, null.For example, switching to the
UncheckedPointerOver visual state sets the color of the
NormalRectangle element to the
SystemControlHighlightBaseHighBrush value, taken from the theme of the application.
<VisualState x:Name="UncheckedPointerOver"> <Storyboard> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="NormalRectangle" Storyboard.TargetProperty="Stroke"> <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightBaseHighBrush}" /> </ObjectAnimationUsingKeyFrames> </Storyboard> </VisualState> <VisualState x:Name="UncheckedPressed"> <Storyboard> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="NormalRectangle" Storyboard.TargetProperty="Fill"> <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlBackgroundBaseMediumBrush}" /> </ObjectAnimationUsingKeyFrames> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="NormalRectangle" Storyboard.TargetProperty="Stroke"> <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightTransparentBrush}" /> </ObjectAnimationUsingKeyFrames> <DoubleAnimation Storyboard.TargetName="NormalRectangle" Storyboard.TargetProperty="StrokeThickness" To="{ThemeResource CheckBoxCheckedStrokeThickness}" Duration="0" /> </Storyboard> </VisualState>
A couple of visual states
CheckBoxAlso note that the visual state of
<VisualState x: Name = "UncheckedNormal" /> specified in the collection is empty. The reason for this is that the mechanics of the visual state manager are such that when transitioning from state A to state B, those properties that were affected by state A but not state B take the values defined as default. This mechanic repeats the trigger mechanics implemented in WPF, but not included in UWP.
After reviewing the general structure of control templates, we will begin to work with them to obtain the required results.
With the existing control pattern, you can do the following:
• Remove "extra" items
• Modify required items already defined in it
• Add new items.
Modifying a template by removing its constituent elementsA common task we faced was to remove the text clear button from the
TextBox control. Imagine one of the possible solutions to this problem. Having received the template, we find in it an element that needs to be deleted -
<Button x: Name = "DeleteButton" ... /> <Button x:Name="DeleteButton" Grid.Row="1" Style="{StaticResource DeleteButtonStyle}" BorderThickness="{TemplateBinding BorderThickness}" Margin="{ThemeResource HelperButtonThemePadding}" IsTabStop="False" Grid.Column="1" Visibility="Collapsed" FontSize="{TemplateBinding FontSize}" MinWidth="34" VerticalAlignment="Stretch"/>
Delete button
It is also important not to forget to delete all other places in the markup that refer in one way or another to this element. So the following are deleted:
<Style x: Name = "DeleteButtonStyle" /> and
<VisualState x: Name = "ButtonVisible" /> . Removing the latter in general allows us to delete the entire
<VisualStateGroup x: Name = "ButtonStates" /> .
Define the resulting style
x: Key - <Style x: Key = "articleTextBox" TargetType = "TextBox"> and apply to the required text input field
<TextBox Style = "{StaticResource articleTextBox}" />
TextBox without a clear button
It should be noted that this method of modifying the template does not always work. In the next article, we will examine the insides of controls at the
Control.cs level and we will see that sometimes dependencies on the elements that make up the template are defined not only in the layout, but also in the code. There are cases when modifying a template by deleting leads to incorrect operation of the control or even exceptions.
Modification of the template through changes to its constituent elementsIn our practice, there was a situation where we needed to make the following changes to the
CalendarDatePicker control:
• Highlight weekend headers in red
• Increase the font size of weekend headers
• Change the vertical navigation arrows to horizontal
• Place the left arrow in the left side of the panel, the right arrow in the right side, and place the heading “year \ month / decade” in the middle between these arrows

Default
CalendarDatePicker Calendar Appearance

New calendar view
CalendarDatePicker• Get the
CalendarDatePicker control pattern.
In the process of analyzing the template, we find that it includes another control that contains what we are looking for -
CalendarView .
CalendarView included in the
CalendarDatePicker template
• Get the
CalendarView control pattern. We make the following changes in it:
• For
<Button x: Name = "PreviousButton" /> and
<Button x: Name = "NextButton" /> buttons, set the values of the
Content property to
"& # xE0e2;" and
"& # xE0e3;" respectively
• For the
<TextBlock x: Name = "WeekDay6" /> and
<TextBlock x: Name = "WeekDay7" /> fields, set the value of the
Foreground property to
Red• Add a setter to the
<Style x: Key = "WeekDayNameStyle" /> style
• In the
Grid container containing
<Button x: Name = "PreviousButton" /> and
<Button x: Name = "NextButton" /> we make obvious changes in the layout for the task.
Is done. Thus, we took a ready-made template and brought its appearance in accordance with the requirements.
Modifying a template by adding new elements to itObviously, this method without access to Control.cs is very limited. The maximum that can be obtained from it is the addition of some kind of visual component, which can be diversified through the states of the
VisualStateManager . This refers to the third way to extend existing controls.
To the above three methods one could add one more, the most interesting - the creation of a new control inheriting from the existing one using its template. But this way more to the next part of our story, which will be devoted to the topic of creating new controls.
Yang Moroz, Senior .NET Developer