[WPF] learn to understand control template Chapter 59

Original: [WPF] learn to understand control template Chapter 59

  Recent work is a busy, failed to timely updates, please understand! ! !

  For the analysis of the visual tree raises several interesting questions. For example, how to control it represents the logical tree to expand the visual tree representation?

  Each control has a built-in method for determining how to render the control (as a set of more basic element). This method is called a control template (control template), it is defined by marker block XAML.

  Here is a simplified version of the template ordinary Button class. This version omits XML namespace declaration Ming Dynasty, set the properties for the nested elements characteristic, and when the button is disabled, take focus or OK button to trigger action when:

Copy the code
<ControlTemplate ...>
    <mwt:ButtonChrome Name="Chrome" ...>
        <ContentPresenter Content="{TemplateBinding ContentControl.Content}" ... />
    <mwt:ButtonChrome>
    <ControlTemplate.Triggers>
    ...
    </ControlTemplate.Triggers>
</ControlTemplate>
Copy the code

  Although not yet studied ButtonChrome and ContentPresenter class, but it is easy to think: control template provides extended what you see in the visual tree. Standard ButtonChrome class defines the visual appearance of the buttons, and ContentPresenter class stores all content provided. If you want to build a new button, just create a new control template. In addition to ButtonChrome classes, access to other content - may be custom element, an element can be introduced in front of the drawing shapes.

  When the button has the focus, and is disabled is clicked, how to control the trigger button to change. For these triggers, there really is no need to introduce special content. For get the focus and click the Modify button itself does not trigger, just modify the properties ButtonChrome class provides the visual appearance of the button:

Copy the code
<Trigger Property="UIElement.IsKeyboardFocused“>
    <Setter Property="mwt:ButtonChrome.RenderDefaulted TargetName="Chrome">
        <Setter.Value>
            <s:Boolean>True</s:Boolean>
        </Setter.Value>
    </Setter>
    <Trigger.Value>
        <s:Boolean>True</s:Boolean>
    </Trigger.Value>
</Trigger>
<Trigger Property="UIElement.IsChecked“>
    <Setter Property="mwt:ButtonChrome.RenderDefaulted TargetName="Chrome">
        <Setter.Value>
            <s:Boolean>True</s:Boolean>
        </Setter.Value>
    </Setter>
    <Trigger.Value>
        <s:Boolean>True</s:Boolean>
    </Trigger.Value>
</Trigger>
Copy the code

  A first flip-flop to ensure that when the button receives focus, RenderDefaulted property set to true. The second trigger ensures that when the button is clicked, RenderDefaulted property is set to true. In each case, ButtonChrome class will adjust itself accordingly. As the graphic changes are too complex, and therefore not only to represent these changes by several property setter statement.

  Setter two objects are in this embodiment by using the property of acting on the control template TargetName specific portion. Only when using a control template, only grace can use this technique. In other words, you can not write a trigger to use TargetName style property access ButtonChrome object because the name Chrome is beyond the scope of style. This technology is only one of the templates provided more powerful than style feature separate methods.

  Triggers may not need to use TargetName property. For example, the trigger for IsEnabled property adjustment buttons only in the foreground of any text content. The trigger can be operated by setting TextElement.Foreground additional properties, and not necessarily by means ButtonChrome categories:

Copy the code
<Trigger Property="UIElement.IsEnabled">
    <Setter Property="TextElement.Foreground">
        <Setter.Value>
            <SolidColorBrush>#FFADADAD</SolidColorBrush>
        </Setter.Value>
    </Setter>
    <Trigger.Value>
        <s:Boolean>False</s:Boolean>
    </Trigger.Value>
</Trigger>
Copy the code

  When building your own control template will see the same separation of duties. If you are lucky enough to be used as a trigger to complete all the work, you may not need to create your own custom class and add the code. On the other hand, if the need Yikes provide more complex visual design, may need to inherit a custom modified class, ButtonChrome class itself does not provide customization - class dedicated to a specific theme Exterior rendering standard buttons.

 A modified class

  ButtonChrome class is defined in Microsoft.Windows.Themes namespace contains some small class similar to each other in the name space, the basic classes used to render details of Windows. In addition to ButtonChrome, further comprising classes BulletChrome (for check boxes and radio buttons), ScrollChrome (Slider), ListBoxChrome and SystemDropShadowChrome. This is the lowest level of public control API. On the few high-level, you will find System.Windows.Controls.Primitives namespace contains a number of basic elements can be used independently, but they usually are packaged into more useful in the control. These elements include ScrollBar, ResizeGrip (for changing the window size), Thumb (drag button on the scroll bar), TickBar (optional scale provided on the scroll bar) and the like. In essence, System.Windows.Controls.Primitives namespace provides the basic elements used in various controls of little own role, but Microsoft.Windows.Themes namespace contains basic logic for rendering the drawing details .

  Another point difference. Like with most types of WPF, System.Windows.Controls.Primitives namespace types are defined in PresentationFramework.dll assembly. However, Microsoft.Windows.Themes name in the control of three different types are defined within the program: PresentationFramework.Aero.dll, PresentationFramework.Luna.dll and PresentationFramework.Royale.dll. Each assembly contains its own ButtonChrome class (as well as other modifications class) versions that rendering logic is slightly different. WPF uses the assembly depends on the operating system settings and themes.

  Despite the frequent use modified control template drawing classes, but not always. For example, ResizeGrip elements (which elements are used to change the size of the lower right corner of the window to create a grid point) is very simple, its template can be used in drawing classes previously described, such as Path, DrawingBrush and LinearGradientBrush. The following is a mark of its use (somewhat complicated):

Copy the code
<ControlTemplate TargetType="{x:Type ResizeGrip}" ...>
    <Grid Background="{TemplateBinding Panel.Background}" SnapsToDevicePixels="True">
        <Path Margin="0,0,2,2" Data="M9,0L11,0 11,11 0,11 0,9 3,9 3,6 6,6 6,3 9,3z" HorizontalAlignment="Right" VerticalAlignment="Bottom">
            <Path.Fill>
                <DrawingBrush ViewboxUnits="Absolute" TileMode="Tile" Viewbox="0,0,3,3" Viewport="0,0,3,3" ViewportUnits="Absolute">
                    <DrawingBrush.Drawing>
                        <DrawingGroup>
                            <DrawingGroup.Children>
                                <GeometryDrawing Geometry="M0,0L2,0 2,2 0,2z">
                                    <GeometryDrawing.Brush>
                                        <LinearGradientBrush EndPoint="1,0.75" StartPoint="0,0.25">
                                            <LinearGradientBrush.GradientStops>
                                                <GradientStop offset="0.3" Color="#FFFFFFFF"/>
                                                <GradientStop offset="0.75" Color="#FFBBC5D7" />
                                                <GradientStop offset="1" Color="#FF6D83A9" />
                                             </LinearGradientBrush.GradientStops>
                                        </LinearGradientBrush>
                                    <GeometryDrawing.Brush>
                                </GeometryDrawing>
                            </DrawingGroup.Children>
                        </DrawingGroup>
                    </DrawingBrush.Drawing>
                </DrawingBrush>
            </Path.Fill>
        </Path>
    </Grid>
</ControlTemplate>
Copy the code

Second, the analysis controls

  When you create a control template, the new template completely replace the original template, so you can get more flexibility, but more complicated. In most cases, before creating the template to meet their own needs, need to look at the standard template used by the control. In some cases, a custom control template mirrors the standard template, and only a few modifications.

  WPF XAML document is not listed in the standard control template. However, the available information needed by the program. The basic idea is that (in the Control class defines the attribute) from the acquired template Tmeplate property control, and then use XamlWriter class, the template serialized into XAML file. The following figure shows a sample program that lists all the WPF controls, and allows you to view the template of each control.

   Construction of the application is to use the trick reflection (reflection), is a reflection type for checking .NET API. When all types of live loaded first application window, the scanning PresentationFramework.dll core assembly (the assembly defines a control class), and then add them to a collection type, sorted according to the type name , after which the collection is bound to a list.

Copy the code
private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            Type controlType = typeof(Control);
            List<Type> derivedTypes = new List<Type>();

            // Search all the types in the assembly where the Control class is defined.
            Assembly assembly = Assembly.GetAssembly(typeof(Control));
            foreach (Type type in assembly.GetTypes())
            {
                // Only add a type of the list if it's a Control, a concrete class, and public.
                if (type.IsSubclassOf(controlType) && !type.IsAbstract && type.IsPublic)
                {
                    derivedTypes.Add(type);
                }
            }

            // Sort the types by type name.
            derivedTypes.Sort(new TypeComparer());

            // Show the list of types.
            lstType.ItemsSource = derivedTypes;
        }
Copy the code

  Whenever you select a control from the list, the corresponding control template will be displayed to the right of the text box. This is done more work needs to be done. The first challenge is, before the actual display in the window control template control is empty. By using reflection, to create a view instance of the control codes, and add it to the current window (but may be set to Collapse Visibility, so that control is not visible). The second challenge is that the existing ControlTemplate object into a familiar XAML markup. XamlWriter.Save () static method is responsible for completing the task, but the code uses XamlWriter and XamlWriterSetting objects to ensure Xaml indent reasonable, easy to read. All of these codes are encapsulated in the exception handling block, the abnormality monitoring processing block can not be created or added to the grid Grid control problem (such as Windows or another Page) are produced:

Copy the code
private void lstTypes_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            try
            {
                // Get the selected type.
                Type type = (Type)lstType.SelectedItem;

                // Instantiate the type.
                ConstructorInfo info = type.GetConstructor(System.Type.EmptyTypes);
                Control control = (Control)info.Invoke(null);

                Window win = control as Window;
                if (win != null)
                {
                    // Create the window (but keep it minimized).
                    win.WindowState = System.Windows.WindowState.Minimized;
                    win.ShowInTaskbar = false;
                    win.Show();
                }
                else
                {
                    // Add it to the grid (but keep it hidden).
                    control.Visibility = Visibility.Collapsed;
                    grid.Children.Add(control);
                }

                // Get the template.
                ControlTemplate template = control.Template;

                // Get the XAML for the template.
                XmlWriterSettings settings = new XmlWriterSettings();
                settings.Indent = true;
                StringBuilder sb = new StringBuilder();
                XmlWriter writer = XmlWriter.Create(sb, settings);
                System.Windows.Markup.XamlWriter.Save(template, writer);

                // Display the template.
                txtTemplate.Text = sb.ToString();

                // Remove the control from the grid.
                if (win != null)
                {
                    win.Close();
                }
                else
                {
                    grid.Children.Remove(control);
                }
            }
            catch (Exception err)
            {
                txtTemplate.Text = "<< Error generating template:" + err.Message + ">>"; ;
            }
        }
Copy the code

  Extend the application to edit the template in the text box, use XamlReader to convert the template back ControlTemplate object, and then assigned to a control and observe the effect, it is not very difficult. However, the actual operation, test and improve them even more easily through the template will be placed into a real window. The next section describes how to create a control template.

  This chapter procedures involved can be downloaded via the link below:

   ControlTemplateBrower.zip

  

Guess you like

Origin www.cnblogs.com/lonelyxmas/p/12514947.html