Sometimes you need to add custom behaviour to existing UI components so in this post we’ll see some examples on how to achieve that.

MainWindow.xaml

In MainWindow.xaml we’re going to use our attached properties for Rectangle and for TextBlock:

local:RectangleBehaviours.BackgroundOnMouseOver="Yellow"
local:TextBlockBehaviours.TransformToUppercase="True"

Here’s the full source code sample:

<Window x:Class="AttachedProperties.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:AttachedProperties"
        mc:Ignorable="d"
        Title="Attached Properties"
        Width="400"
        Height="400">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition/>
            <RowDefinition Height="50"/>
        </Grid.RowDefinitions>
        <Rectangle Grid.Row="0"
                   Fill="Red"
                   local:RectangleBehaviours.BackgroundOnMouseOver="Yellow"/>
        <Rectangle Grid.Row="1"
                   Fill="Blue"
                   local:RectangleBehaviours.BackgroundOnMouseOver="Green"/>
        <TextBlock Grid.Row="2"
                   Text="lower case text"
                   local:TextBlockBehaviours.TransformToUppercase="True"
                   HorizontalAlignment="Center"
                   VerticalAlignment="Center"
                   FontWeight="Bold"
                   FontSize="20"/>
    </Grid>
</Window>

RectangleBehaviours.cs

For the Rectangle we are going to set the Fill property to the value provided in the attached property, but only when the user moves the mouse on top of the rectangle.

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

namespace AttachedProperties {
    public class RectangleBehaviours {
        public static Brush GetBackgroundOnMouseOver(DependencyObject obj) {
            return (Brush)obj.GetValue(BackgroundOnMouseOverProperty);
        }

        public static void SetBackgroundOnMouseOver(DependencyObject obj, Brush value) {
            obj.SetValue(BackgroundOnMouseOverProperty, value);
        }

        public static readonly DependencyProperty BackgroundOnMouseOverProperty =
            DependencyProperty.RegisterAttached("BackgroundOnMouseOver",
                typeof(Brush),
                typeof(Rectangle),
                new PropertyMetadata(
                    new PropertyChangedCallback(OnBackgroundOnMouseOverChanged)));

        private static void OnBackgroundOnMouseOverChanged(
                DependencyObject d, DependencyPropertyChangedEventArgs e) {
            if (!(d is Rectangle rectangle)) return;

            var originalFill = rectangle.Fill;
            rectangle.IsMouseDirectlyOverChanged += (sender, args) => {
                var r = sender as Rectangle;

                var newFill = e.NewValue as Brush;
                if (newFill == originalFill) return;
                r.Fill = r.IsMouseDirectlyOver ? newFill : originalFill;
            };
        }
    }
}

TextBlockBehaviours.cs

For the TextBlock we are going to set the text in upper case. Please keep in mind that this is just an example on how to use attached properties and that it might not be the best option to achieve this specific task (you may use a Converter for example).

using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;

namespace AttachedProperties {
    public class TextBlockBehaviours {
        public static bool GetTransformToUppercase(DependencyObject obj) {
            return (bool)obj.GetValue(TransformToUppercaseProperty);
        }

        public static void SetTransformToUppercase(DependencyObject obj, bool value) {
            obj.SetValue(TransformToUppercaseProperty, value);
        }

        public static readonly DependencyProperty TransformToUppercaseProperty =
            DependencyProperty.RegisterAttached("TransformToUppercase",
                typeof(bool),
                typeof(TextBlock),
                new PropertyMetadata(
                    new PropertyChangedCallback(OnTransformToUppercaseChanged)));

        private static void OnTransformToUppercaseChanged(
                DependencyObject d, DependencyPropertyChangedEventArgs e) {
            if (!(d is TextBlock textBlock)) return;

            var dp = DependencyPropertyDescriptor.FromProperty(
                        TextBlock.TextProperty,
                        typeof(TextBlock));
            dp.AddValueChanged(textBlock, (sender, args) => {
                var tb = sender as TextBlock;

                if (GetTransformToUppercase(tb))
                    tb.Text = tb.Text.ToUpper();
            });
        }
    }
}

In this sample you can also see how to use a DependencyPropertyDescriptor to listen to value changes using AddValueChanged.