Detailed explanation of fancy control function expansion of WPF development skills

Time:2021-9-25
catalogue
  • No1. Custom control template
  • NO2. Override control
  • No3. Try attaching attributes
  • summary

The article defaults that you have started WPF

In the daily development of WPF, we often encounter that the default control function does not meet the requirements. What should we do?

No1. Custom control template

In normal development, we often encounter “vulgar” needs and dislike the default appearance of the control. What to do? Ha ha, let’s talk about the whole content!

Remember the button in your heart? Is the first impression a regular rectangle? Well, let’s vulgarize it this time and turn it into a circle!

Upper Code:


<Button Content="Test1" Width="80" Height="80" FocusVisualStyle="{x:Null}" Background="LightSeaGreen" BorderBrush="DarkBlue">
                <Button.Template>
                    <ControlTemplate TargetType="ButtonBase">
                        <Grid>
                            <Ellipse x:Name="ellipseBorder" StrokeThickness="1" Stroke="{TemplateBinding BorderBrush}" Fill="{TemplateBinding Background}"/>
                            <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" Content="{TemplateBinding Content}"/>
                        </Grid>
                        <ControlTemplate.Triggers>
                            <Trigger Property="IsMouseOver" Value="True">
                                <Setter Property="Stroke" Value="Orange" TargetName="ellipseBorder"/>
                            </Trigger>
                            <Trigger Property="IsPressed" Value="True">
                                <Setter Property="Stroke" Value="OrangeRed" TargetName="ellipseBorder"/>
                            </Trigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Button.Template>
            </Button>

Upper appearance:

NO2. Override control

In many cases, we can’t change the appearance of the control. We should not only change the appearance, but also change the function of the control. For example, the normal function of the TextBox control we often use is to input, but it’s more humanized. We want the textbox to tell us whether the current text box should input the user name or address, etc. In fact, this is the watermark function we often see. The watermark text must be set on demand, so we can’t solve it simply by changing the lower control template.

Through the requirements, we know that the new text box with watermark has at least one dependent attribute such as watermark for external setting. Of course, the new watermarked text box looks similar to textbox, but we also need to define the appearance for the new control.

Therefore, the first step is to define the function of the control and add the following code:


public class WaterMarkTextBox : TextBox
    {
        static WaterMarkTextBox()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(WaterMarkTextBox), new FrameworkPropertyMetadata(typeof(WaterMarkTextBox)));
        }


        public string WaterMark
        {
            get { return (string)GetValue(WaterMarkProperty); }
            set { SetValue(WaterMarkProperty, value); }
        }

        // Using a DependencyProperty as the backing store for WaterMark.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty WaterMarkProperty =
            DependencyProperty.Register("WaterMark", typeof(string), typeof(WaterMarkTextBox), new PropertyMetadata(null));


    }

Step 2: redefine the appearance of the control, and add the following code:


<Style TargetType="{x:Type local:WaterMarkTextBox}">
        <Setter Property="BorderBrush" Value="Black"/>
        <Setter Property="BorderThickness" Value="1"/>
        <Setter Property="VerticalContentAlignment" Value="Center"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type local:WaterMarkTextBox}">
                    <Grid>
                        <Border Background="{TemplateBinding Background}"
                                BorderBrush="{TemplateBinding BorderBrush}"
                                BorderThickness="{TemplateBinding BorderThickness}">
                        </Border>
                        <ScrollViewer x:Name="PART_ContentHost"
                                      Grid.Column="0"
                                      Margin="0"
                                      Padding="{TemplateBinding Padding}"
                                      VerticalAlignment="Stretch"
                                      Background="{x:Null}"
                                      BorderThickness="0"
                                      IsTabStop="False"
                                      SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
                        <TextBlock x:Name="PART_Message"
                                   Margin="4 0"
                                   Padding="{TemplateBinding Padding}"
                                   HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                                   VerticalAlignment="Center"
                                   Foreground="Gray"
                                   Text="{TemplateBinding WaterMark}"
                                   Visibility="Collapsed" />
                    </Grid>
                    <ControlTemplate.Triggers>
                        <DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Path=Text}" Value="">
                            <Setter TargetName="PART_Message" Property="Visibility" Value="Visible" />
                        </DataTrigger>
                    </ControlTemplate.Triggers>
                    
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

Please note that the name is part_ The TextBlock of message is used to present the watermark prompt message, and a trigger is added to realize such a function: if no content is entered, the watermark will be displayed, otherwise the watermark will be hidden.

Control, code:


 <local:WaterMarkTextBox Margin="20,0,0,0" Width="200" Height="50" WaterMark="Please Input your name"/>

Upper effect:

No3. Try attaching attributes

Rewriting controls seems perfect. Is that true?

Well, my demand comes again. Now the text box prompt is perfect, but my password box passwordbox also needs a watermark? What should I do? Rewrite another password box with watermark? Do you feel like doing the same thing at this time? As a qualified coder, we should keep in mind the cautionary saying of the coder community: don’t repeat yourself!

At this time, please recall the classic knowledge points of WPF:

Control a should be placed in the grid, a should support setting rows and columns, control B should be placed in the grid, and B should also support setting rows and columns. The tutorial has told us not to be foolhardy. Define row and column attributes in both a and B, otherwise the subsequent C and D… Will be endless.

At this time, it’s time for us to apply additional attributes. Define unified additional attributes of rows and columns in the grid, and then apply them to a and B.

In turn, look at our current needs. Is it the same routine? Can I define a watermark watermark additional attribute in a public place and apply it to the text box and password box respectively? Half right, because there is no watermark on the old appearance of our text box and password box, we have to redefine their new appearance at the same time.

If you don’t have much to say, first add the code of attribute definition:


public class WaterMarkHelper
    {
        public static string GetWaterMark(DependencyObject obj)
        {
            return (string)obj.GetValue(WaterMarkProperty);
        }

        public static void SetWaterMark(DependencyObject obj, string value)
        {
            obj.SetValue(WaterMarkProperty, value);
        }

        public static readonly DependencyProperty WaterMarkProperty =
            DependencyProperty.RegisterAttached("WaterMark", typeof(string), typeof(WaterMarkHelper), new PropertyMetadata(null));


    }

New style of textbox on:


<Style x:Key="TextBoxWithWaterMark" TargetType="{x:Type TextBox}">
        <Setter Property="BorderBrush" Value="Black"/>
        <Setter Property="BorderThickness" Value="1"/>
        <Setter Property="VerticalContentAlignment" Value="Center"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type TextBox}">
                    <Grid>
                        <Border Background="{TemplateBinding Background}"
                                BorderBrush="{TemplateBinding BorderBrush}"
                                BorderThickness="{TemplateBinding BorderThickness}">
                        </Border>
                        <ScrollViewer x:Name="PART_ContentHost"
                                      Grid.Column="0"
                                      Margin="0"
                                      Padding="{TemplateBinding Padding}"
                                      VerticalAlignment="Stretch"
                                      Background="{x:Null}"
                                      BorderThickness="0"
                                      IsTabStop="False"
                                      SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
                        <TextBlock x:Name="PART_Message"
                                   Margin="4 0"
                                   Padding="{TemplateBinding Padding}"
                                   HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                                   VerticalAlignment="Center"
                                   Foreground="Gray"
                                   Text="{TemplateBinding local:WaterMarkHelper.WaterMark}"
                                   Visibility="Collapsed" />
                    </Grid>
                    <ControlTemplate.Triggers>
                        <DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Path=Text}" Value="">
                            <Setter TargetName="PART_Message" Property="Visibility" Value="Visible" />
                        </DataTrigger>
                    </ControlTemplate.Triggers>

                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

Please compare it with the style in the custom control. It is actually part_ The text binding of the control corresponding to message is different. In this way, the additional property watermarkhelper.watermark of textbox is bound

Application code on:


 <TextBox Style="{StaticResource TextBoxWithWaterMark}" Margin="20,0,0,0" Width="200" Height="50" local:WaterMarkHelper.WaterMark="Please Input your name"/>

Please note that in this way, you need to manually and explicitly apply the defined style resources!

Upper effect:

 

After class homework: please follow the gourd and draw a gourd to realize the watermark function of passwordbox

summary

In addition to the three methods listed here, you can also expand the function of a control through the behavior function of behavior, such as the famous drag function! Here, I want to sum up: if a worker wants to do well, he must first sharpen his tools!

When we have a solid foundation, we can really jump out of the fence and apply flexibly!

This is the end of this article about the function expansion of fancy controls in the daily development of WPF. For more information about the function expansion of fancy controls in WPF, please search the previous articles of developeppaer or continue to browse the relevant articles below. I hope you will support developeppaer in the future!

Recommended Today

Supervisor

Supervisor [note] Supervisor – H view supervisor command help Supervisorctl – H view supervisorctl command help Supervisorctl help view the action command of supervisorctl Supervisorctl help any action to view the use of this action 1. Introduction Supervisor is a process control system. Generally speaking, it can monitor your process. If the process exits abnormally, […]