Replace part of default template in WPF

后端 未结 4 1961
不思量自难忘°
不思量自难忘° 2020-12-04 22:14

is there any \"best practice\" way to replace a part of the default template. The current use case is a treeview. As default, the treeview has this small triangle shapes to

相关标签:
4条回答
  • 2020-12-04 22:25

    Actually there is a way (sort of). You can create your own custom control and override the OnApplyTemplate function to change the style dynamically.

    For example, create a custom control like so (I am doing this in silverlight but it's all the same I presume):

    namespace SilverlightClassLibrary1
    {
        public class MyButton: Button
        {
            public string BackgroundColor { get; set; }
    
            public override void OnApplyTemplate()
            {
                base.OnApplyTemplate();
    
                if (BackgroundColor != null)
                {
                    Rectangle r = this.GetTemplateChild("BackgroundGradient") as Rectangle;
    
                    if (r != null)
                    {
                        r.Fill = new SolidColorBrush(Color.FromArgb(255, 
                            Convert.ToByte(BackgroundColor.Substring(1,2),16),
                            Convert.ToByte(BackgroundColor.Substring(3,2),16),
                            Convert.ToByte(BackgroundColor.Substring(5,2),16)));
                    }
                }
            }
        }
    }
    

    The interesting part is the GetTemplateChild method, that's looking for a Rectangle control named "BackgroundGradient". (BTW, it's easier if you define custom controls in a separate project, so create a new "Silverlight class library" project if you haven't already done so and put it into that project.)

    Then add a new resource dictionary file and override the control template and make sure you have a rectangle named "BackgroundGradient". In this case we're using the standard button control template that I've cut down a bit:

    <ResourceDictionary
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:custom="clr-namespace:SilverlightClassLibrary1;assembly=SilverlightClassLibrary1">
    
        <Style TargetType="custom:MyButton">
            <Setter Property="Background" Value="#FF1F3B53"/>
            <Setter Property="Foreground" Value="#FF000000"/>
            <Setter Property="Padding" Value="3"/>
            <Setter Property="BorderThickness" Value="1"/>
            <Setter Property="BorderBrush">
                <Setter.Value>
                    <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                        <GradientStop Color="#FFA3AEB9" Offset="0"/>
                        <GradientStop Color="#FF8399A9" Offset="0.375"/>
                        <GradientStop Color="#FF718597" Offset="0.375"/>
                        <GradientStop Color="#FF617584" Offset="1"/>
                    </LinearGradientBrush>
                </Setter.Value>
            </Setter>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="Button">
                        <Grid>
                            <Border x:Name="Background" CornerRadius="3" Background="White" BorderThickness="{TemplateBinding BorderThickness}" BorderBrush="{TemplateBinding BorderBrush}">
                                <Grid Background="{TemplateBinding Background}"  Margin="1">
                                    <Border Opacity="0"  x:Name="BackgroundAnimation" Background="#FF448DCA" />
                                    <Rectangle x:Name="BackgroundGradient" Fill="White" >
                                    </Rectangle>
                                </Grid>
                            </Border>
                            <ContentPresenter
                                  x:Name="contentPresenter"
                                  Content="{TemplateBinding Content}"
                                  ContentTemplate="{TemplateBinding ContentTemplate}"
                                  VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
                                  HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                                  Margin="{TemplateBinding Padding}"/>
                            <Rectangle x:Name="DisabledVisualElement" RadiusX="3" RadiusY="3" Fill="#FFFFFFFF" Opacity="0" IsHitTestVisible="false" />
                            <Rectangle x:Name="FocusVisualElement" RadiusX="2" RadiusY="2" Margin="1" Stroke="#FF6DBDD1" StrokeThickness="1" Opacity="0" IsHitTestVisible="false" />
                        </Grid>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </ResourceDictionary>
    

    So you can now declare a button control and override a style if you'd like:

    <UserControl x:Class="SilverlightApplication1.MainPage"
                ...
                xmlns:custom="clr-namespace:SilverlightClassLibrary1;assembly=SilverlightClassLibrary1">
    
            <custom:MyButton>Normal Button 1</custom:MyButton>
            <custom:MyButton>Normal Button 2</custom:MyButton>
    
            <custom:MyButton BackgroundColor="#8888cc">Customized Background</custom:MyButton>
    

    I presume you could get get even more clever and pass through a resource name or a style name and load it dynamically.

    You then need to include your resource file as part of your application:

    <Application xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
                 x:Class="SilverlightApplication1.App"
                 >
        <Application.Resources>
            <ResourceDictionary >
                <ResourceDictionary.MergedDictionaries>
                    <ResourceDictionary Source="Dictionary1.xaml" />
                </ResourceDictionary.MergedDictionaries>
            </ResourceDictionary>
        </Application.Resources>
    </Application>
    

    and you'll see your custom property changes in your XAML designer.

    0 讨论(0)
  • 2020-12-04 22:35

    Unfortunately, I think you have to replace the entire template:

    From MSDN: http://msdn.microsoft.com/en-us/library/aa970773.aspx

    Controls in Windows Presentation Foundation (WPF) have a ControlTemplate that contains the visual tree of that control. You can change the structure and appearance of a control by modifying the ControlTemplate of that control. There is no way to replace only part of the visual tree of a control; to change the visual tree of a control you must set the Template property of the control to its new and complete ControlTemplate.

    0 讨论(0)
  • 2020-12-04 22:48

    I would redesign your template to be a Custom Control, using ContentPresenters as placeholders for the elements that will change.

    To use these placeholders you must link them to dependency properties.

    Check this post to see how this is done

    http://www.codeproject.com/Articles/82464/How-to-Embed-Arbitrary-Content-in-a-WPF-Control

    "Using Custom Control" explains my approach

    0 讨论(0)
  • 2020-12-04 22:48

    2020 Update

    I came across this question on my search for an answer and this is how I did it:

    To override the default control templates: use Microsoft Blend > Via the Designer right click on the control you wish to override > Edit Template > Edit Current or Edit a Copy (If you're using the same control multiple times like in my case a Menu Item) save the template in a Resource Dictionary and use it as a Dynamic Resource on the controls you wish to override. and of course, edit the template the way you want.

    0 讨论(0)
提交回复
热议问题