Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
  1. Home
  2. General Programming
  3. WPF
  4. Custom Control Styling

Custom Control Styling

Scheduled Pinned Locked Moved WPF
wpfcsharpasp-netdatabasedotnet
6 Posts 2 Posters 11 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • K Offline
    K Offline
    Kevin Marois
    wrote on last edited by
    #1

    I have created a Hyperlink control. What I want is to have a default style in my control itself, but allow consumers to restyle it later, like when It's dropped into a window. So here's my control's XAML:

    <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:Marois.Framework.Core.WPF.Controls"
    xmlns:i="http://schemas.microsoft.com/xaml/behaviors">

    <SolidColorBrush x:Key="hyperlinkMouseOverBrush" Color="Green"/>
    
    <Style TargetType="{x:Type local:MaroisHyperlink}">
    
        <Setter Property="FontSize" Value="60" />
        <Setter Property="Hyperlink.TextDecorations" Value="None" />
    
        <Setter Property="Template">
    
            <Setter.Value>
    
                <ControlTemplate>
                    
                    <TextBlock>
    
                            <Hyperlink>
    
                                <TextBlock Text="{Binding LinkText, RelativeSource={RelativeSource TemplatedParent}}"
                                           FontSize="{TemplateBinding FontSize}"/>
                                
                                
                                
                            </Hyperlink>
    
                        </TextBlock>
    
                </ControlTemplate>
    
            </Setter.Value>
    
        </Setter>
    
        <Style.Triggers>
    
            <Trigger Property="IsMouseOver" Value="true">
                <Setter Property="Hyperlink.Foreground" Value="{StaticResource hyperlinkMouseOverBrush}" />
                <Setter Property="Hyperlink.TextDecorations" Value="Underline" />
            </Trigger>
    
            <Trigger Property="IsEnabled" Value="false">
                <Setter Property="Hyperlink.Foreground" Value="Gray" />
                <Setter Property="Hyperlink.TextDecorations" Value="None" />
            </Trigger>
    
        </Style.Triggers>
    
    </Style>
    

    </ResourceDictionary>

    Code behind:

    using System.Windows;
    using System.Windows.Media;

    namespace Marois.Framework.Core.WPF.Controls
    {
    public class MaroisHyperlink : ControlBase
    {
    #region DP's
    #region DP HoverBrush
    public static readonly DependencyProperty HoverBrushP

    Richard DeemingR 1 Reply Last reply
    0
    • K Kevin Marois

      I have created a Hyperlink control. What I want is to have a default style in my control itself, but allow consumers to restyle it later, like when It's dropped into a window. So here's my control's XAML:

      <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      xmlns:local="clr-namespace:Marois.Framework.Core.WPF.Controls"
      xmlns:i="http://schemas.microsoft.com/xaml/behaviors">

      <SolidColorBrush x:Key="hyperlinkMouseOverBrush" Color="Green"/>
      
      <Style TargetType="{x:Type local:MaroisHyperlink}">
      
          <Setter Property="FontSize" Value="60" />
          <Setter Property="Hyperlink.TextDecorations" Value="None" />
      
          <Setter Property="Template">
      
              <Setter.Value>
      
                  <ControlTemplate>
                      
                      <TextBlock>
      
                              <Hyperlink>
      
                                  <TextBlock Text="{Binding LinkText, RelativeSource={RelativeSource TemplatedParent}}"
                                             FontSize="{TemplateBinding FontSize}"/>
                                  
                                  
                                  
                              </Hyperlink>
      
                          </TextBlock>
      
                  </ControlTemplate>
      
              </Setter.Value>
      
          </Setter>
      
          <Style.Triggers>
      
              <Trigger Property="IsMouseOver" Value="true">
                  <Setter Property="Hyperlink.Foreground" Value="{StaticResource hyperlinkMouseOverBrush}" />
                  <Setter Property="Hyperlink.TextDecorations" Value="Underline" />
              </Trigger>
      
              <Trigger Property="IsEnabled" Value="false">
                  <Setter Property="Hyperlink.Foreground" Value="Gray" />
                  <Setter Property="Hyperlink.TextDecorations" Value="None" />
              </Trigger>
      
          </Style.Triggers>
      
      </Style>
      

      </ResourceDictionary>

      Code behind:

      using System.Windows;
      using System.Windows.Media;

      namespace Marois.Framework.Core.WPF.Controls
      {
      public class MaroisHyperlink : ControlBase
      {
      #region DP's
      #region DP HoverBrush
      public static readonly DependencyProperty HoverBrushP

      Richard DeemingR Offline
      Richard DeemingR Offline
      Richard Deeming
      wrote on last edited by
      #2

      Kevin Marois wrote:

      The Hyperlink.TextDecorations does not.

      Firstly, it's Inline.TextDecorations, not Hyperlink.TextDecorations. Inline.TextDecorations Property (System.Windows.Documents) | Microsoft Learn[^] Setting that property on a parent element doesn't affect the Hyperlink, since it overrides the property in its default template. You either need to set the property explicitly on the Hyperlink:

      or via a style:

          <Setter Property="TextDecorations" Value="None" />
      

      If you want to be able to override it when you use your control, you'll need a property to control it:

      public class MaroisHyperlink : ControlBase
      {
      public static readonly DependencyProperty TextDecorationsProperty = Inline.TextDecorationsProperty.AddOwner(typeof(MaroisHyperlink));

      public TextDecorationCollection TextDecorations
      {
          get { return (TextDecorationCollection)GetValue(TextDecorationsProperty); }
          set { SetValue(TextDecorationsProperty, value); }
      }
      

      and then bind the property in your template:

      Kevin Marois wrote:

      None of the triggers at the bottom work.

      A similar problem. The triggers should set the properties of your control, and the relevant properties of the Hyperlink should be bound to the properties on your control.

      "These people looked deep within my soul and assigned me a number based on the order in which I joined" - Homer

      K 3 Replies Last reply
      0
      • Richard DeemingR Richard Deeming

        Kevin Marois wrote:

        The Hyperlink.TextDecorations does not.

        Firstly, it's Inline.TextDecorations, not Hyperlink.TextDecorations. Inline.TextDecorations Property (System.Windows.Documents) | Microsoft Learn[^] Setting that property on a parent element doesn't affect the Hyperlink, since it overrides the property in its default template. You either need to set the property explicitly on the Hyperlink:

        or via a style:

            <Setter Property="TextDecorations" Value="None" />
        

        If you want to be able to override it when you use your control, you'll need a property to control it:

        public class MaroisHyperlink : ControlBase
        {
        public static readonly DependencyProperty TextDecorationsProperty = Inline.TextDecorationsProperty.AddOwner(typeof(MaroisHyperlink));

        public TextDecorationCollection TextDecorations
        {
            get { return (TextDecorationCollection)GetValue(TextDecorationsProperty); }
            set { SetValue(TextDecorationsProperty, value); }
        }
        

        and then bind the property in your template:

        Kevin Marois wrote:

        None of the triggers at the bottom work.

        A similar problem. The triggers should set the properties of your control, and the relevant properties of the Hyperlink should be bound to the properties on your control.

        K Offline
        K Offline
        Kevin Marois
        wrote on last edited by
        #3

        Thanks. I learned some new things here. One question - That DP syntax you used is unfamiliar to me. How do you set the default value for the TextDecoration's DP? I've always used this syntax for a DP, but for some reason it won't compile here:

        public static readonly DependencyProperty TextDecorationsProperty =
        DependencyProperty.Register("TextDecorations",
        typeof(TextDecorations),
        typeof(MaroisHyperlink),
        new PropertyMetadata(TextDecorations.Underline));

        public TextDecorations TextDecorations
        {
        get { return (TextDecorations)GetValue(TextDecorationsProperty);}
        set { SetValue(TextDecorationsProperty, value); }
        }

        I get 3 compilation errors:

        Cannot convert to static type 'TextDecorations'
        'TextDecorations': static types cannot be used as return types
        'TextDecorations': static types cannot be used as paramters

        If it's not broken, fix it until it is. Everything makes sense in someone's mind. Ya can't fix stupid.

        Richard DeemingR 1 Reply Last reply
        0
        • Richard DeemingR Richard Deeming

          Kevin Marois wrote:

          The Hyperlink.TextDecorations does not.

          Firstly, it's Inline.TextDecorations, not Hyperlink.TextDecorations. Inline.TextDecorations Property (System.Windows.Documents) | Microsoft Learn[^] Setting that property on a parent element doesn't affect the Hyperlink, since it overrides the property in its default template. You either need to set the property explicitly on the Hyperlink:

          or via a style:

              <Setter Property="TextDecorations" Value="None" />
          

          If you want to be able to override it when you use your control, you'll need a property to control it:

          public class MaroisHyperlink : ControlBase
          {
          public static readonly DependencyProperty TextDecorationsProperty = Inline.TextDecorationsProperty.AddOwner(typeof(MaroisHyperlink));

          public TextDecorationCollection TextDecorations
          {
              get { return (TextDecorationCollection)GetValue(TextDecorationsProperty); }
              set { SetValue(TextDecorationsProperty, value); }
          }
          

          and then bind the property in your template:

          Kevin Marois wrote:

          None of the triggers at the bottom work.

          A similar problem. The triggers should set the properties of your control, and the relevant properties of the Hyperlink should be bound to the properties on your control.

          K Offline
          K Offline
          Kevin Marois
          wrote on last edited by
          #4

          I stumbled across this also. I needed put the triggers INSIDE the template:

          <ControlTemplate.Triggers>

          <Trigger Property="IsMouseOver" Value="true">
              <Setter TargetName="hyperLink" Property="TextDecorations" Value="{Binding TextDecorations, RelativeSource={RelativeSource TemplatedParent}}"/>
              <Setter TargetName="hyperLink" Property="Foreground" Value="{Binding HoverBrush, RelativeSource={RelativeSource TemplatedParent}}"/>
          </Trigger>
          

          </ControlTemplate.Triggers>

          If it's not broken, fix it until it is. Everything makes sense in someone's mind. Ya can't fix stupid.

          1 Reply Last reply
          0
          • Richard DeemingR Richard Deeming

            Kevin Marois wrote:

            The Hyperlink.TextDecorations does not.

            Firstly, it's Inline.TextDecorations, not Hyperlink.TextDecorations. Inline.TextDecorations Property (System.Windows.Documents) | Microsoft Learn[^] Setting that property on a parent element doesn't affect the Hyperlink, since it overrides the property in its default template. You either need to set the property explicitly on the Hyperlink:

            or via a style:

                <Setter Property="TextDecorations" Value="None" />
            

            If you want to be able to override it when you use your control, you'll need a property to control it:

            public class MaroisHyperlink : ControlBase
            {
            public static readonly DependencyProperty TextDecorationsProperty = Inline.TextDecorationsProperty.AddOwner(typeof(MaroisHyperlink));

            public TextDecorationCollection TextDecorations
            {
                get { return (TextDecorationCollection)GetValue(TextDecorationsProperty); }
                set { SetValue(TextDecorationsProperty, value); }
            }
            

            and then bind the property in your template:

            Kevin Marois wrote:

            None of the triggers at the bottom work.

            A similar problem. The triggers should set the properties of your control, and the relevant properties of the Hyperlink should be bound to the properties on your control.

            K Offline
            K Offline
            Kevin Marois
            wrote on last edited by
            #5

            I beleive I finally have it working! This was mainly about me learning how to create Custome Controls. I appreciate all your help. I learned a lot. Here's the finiished product! Generic.xaml

            <Style TargetType="{x:Type local:MaroisHyperlink}">

            <Setter Property="Template">
            
                <Setter.Value>
            
                    <ControlTemplate>
                            
                        <TextBlock>
            
                            <Hyperlink x:Name="hyperLink" 
                                        Foreground="{Binding Foreground, RelativeSource={RelativeSource TemplatedParent}}"
                                        TextDecorations="{Binding TextDecorations, RelativeSource={RelativeSource TemplatedParent}}">
            
                                <TextBlock Text="{Binding LinkText, 
                                            RelativeSource={RelativeSource TemplatedParent}}"/>
                                        
                                <i:Interaction.Triggers>
                                    <i:EventTrigger EventName="Click">
                                        <i:InvokeCommandAction Command="{Binding RelativeSource={RelativeSource FindAncestor, 
                                                                            AncestorType=Control}, Path=LinkClickedCommand}"/>
                                    </i:EventTrigger>
                                </i:Interaction.Triggers>
                                        
                            </Hyperlink>
            
                        </TextBlock>
            
                    <ControlTemplate.Triggers>
            
                        <Trigger Property="IsMouseOver" Value="true">
                            <Setter TargetName="hyperLink" Property="TextDecorations" Value="{Binding TextDecorations, RelativeSource={RelativeSource TemplatedParent}}"/>
                            <Setter TargetName="hyperLink" Property="Foreground" Value="{Binding HoverBrush, RelativeSource={RelativeSource TemplatedParent}}"/>
                        </Trigger>
            
                    </ControlTemplate.Triggers>
                            
                    </ControlTemplate>
            
                </Setter.Value>
            
            </Setter>
            

            </Style>

            Code Behind

            public class MaroisHyperlink : ControlBase
            {
                #region Routed Events
                #region LinkClickedEvent
                public static readonly RoutedEvent LinkClickedEvent =
                            EventManager.RegisterRoutedEvent("LinkClicked",
                            RoutingStrategy.Bubble,
                            typ
            
            1 Reply Last reply
            0
            • K Kevin Marois

              Thanks. I learned some new things here. One question - That DP syntax you used is unfamiliar to me. How do you set the default value for the TextDecoration's DP? I've always used this syntax for a DP, but for some reason it won't compile here:

              public static readonly DependencyProperty TextDecorationsProperty =
              DependencyProperty.Register("TextDecorations",
              typeof(TextDecorations),
              typeof(MaroisHyperlink),
              new PropertyMetadata(TextDecorations.Underline));

              public TextDecorations TextDecorations
              {
              get { return (TextDecorations)GetValue(TextDecorationsProperty);}
              set { SetValue(TextDecorationsProperty, value); }
              }

              I get 3 compilation errors:

              Cannot convert to static type 'TextDecorations'
              'TextDecorations': static types cannot be used as return types
              'TextDecorations': static types cannot be used as paramters

              If it's not broken, fix it until it is. Everything makes sense in someone's mind. Ya can't fix stupid.

              Richard DeemingR Offline
              Richard DeemingR Offline
              Richard Deeming
              wrote on last edited by
              #6

              The AddOwner syntax lets you register another type for use with a DependencyProperty which has already been registered: How to: Add an Owner Type for a Dependency Property - WPF .NET Framework | Microsoft Learn[^] DependencyProperty.AddOwner Method (System.Windows) | Microsoft Learn[^] You can't use the TextDecorations class[^] as the property type; that's a static class used to provide access to the standard text decorations. Instead, you need to use the TextDecorationCollection class[^] as the property type, which is what the Inlines.TextDecorations property[^] does:

              Reference Source[^]:

              /// /// DependencyProperty for

              "These people looked deep within my soul and assigned me a number based on the order in which I joined" - Homer

              1 Reply Last reply
              0
              Reply
              • Reply as topic
              Log in to reply
              • Oldest to Newest
              • Newest to Oldest
              • Most Votes


              • Login

              • Don't have an account? Register

              • Login or register to search.
              • First post
                Last post
              0
              • Categories
              • Recent
              • Tags
              • Popular
              • World
              • Users
              • Groups