Feeds:
Posts
Comments

Archive for the ‘Attached Properties’ Category

Attached properties are a beautiful thing. For a comprehensive introduction check out the MSDN  here. Anyway, the other day I was tasked with creating a button that has two distinct visual states, a normal state and mouse over state. The layout of the button itself was fairly simple. It was to be a rectangle with a stroke and fill. The rectangle had to contain an image and some text denoting what the purpose of the button was. Normally this would be no problem if I only had one button with one image. However, I needed two images and would prefer to have only one style that I could use for multiple buttons. For this example we are creating a “Save As” button.

When dropping the normal Windows button control on a form, it only exposes a single image property. The main problem was how to go about exposing multiple image properties on that button. One solution to this problem is to utilize attached properties. First I created a new WPF application in Visual Studio and added a class called CustomButton.cs.

Here are the contents of the CustomButton.cs class.

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

namespace AttachedPropertyTesting
{
     public class CustomButton
     {
          static CustomButton()
          {
               ImageProperty = DependencyProperty.RegisterAttached("Image",
                    typeof(ImageSource), typeof(CustomButton), new FrameworkPropertyMetadata((ImageSource)null));

               ImageMouseOverProperty = DependencyProperty.RegisterAttached("ImageMouseOver",
                    typeof(ImageSource), typeof(CustomButton), new FrameworkPropertyMetadata((ImageSource)null));
          }

          public static readonly DependencyProperty ImageProperty;

          public static ImageSource GetImage(DependencyObject obj)
          {
               return (ImageSource)obj.GetValue(ImageProperty);
          }

          public static void SetImage(DependencyObject obj, ImageSource value)
          {
               obj.SetValue(ImageProperty, value);
          }

          public static readonly DependencyProperty ImageMouseOverProperty;

          public static ImageSource GetImageMouseOver(DependencyObject obj)
          {
               return (ImageSource)obj.GetValue(ImageMouseOverProperty);
          }

          public static void SetImageMouseOver(DependencyObject obj, ImageSource value)
          {
               obj.SetValue(ImageMouseOverProperty, value);
          }
     }
}

As you can see, we have declared two Dependency Properties, Image, and ImageMouseOver and registered them as attached properties. We can now access these properties from the button control itself. Then, with a little styling and template binding we have everything we need. I have placed our two images in a folder called Images. Here are the contents of the MainWindow.xaml.

<Window x:Class="AttachedPropertyTesting.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:aps="clr-namespace:AttachedPropertyTesting"
        Title="MainWindow" Height="200" Width="350">

<Window.Resources>
     <Style x:Key="btnSaveOrb" TargetType="{x:Type Button}">
          <Setter Property="Template">
               <Setter.Value>
                    <ControlTemplate TargetType="{x:Type Button}">
                         <Grid Background="LightBlue">
                              <Rectangle x:Name="rectangle" RadiusX="4" RadiusY="4" Stroke="Brown" Fill="Bisque"/>
                              <Label x:Name="label" Content="{TemplateBinding Content}" Margin="60,0,0,0" HorizontalAlignment="Left" VerticalAlignment="Center" Foreground="Brown"/>
                              <Image x:Name="image" Source="{TemplateBinding aps:CustomButton.Image}" HorizontalAlignment="Left" VerticalAlignment="Top"/>
                              <Image x:Name="imageMouseOver" Source="{TemplateBinding aps:CustomButton.ImageMouseOver}" HorizontalAlignment="Left" VerticalAlignment="Top" Visibility="Hidden"/>
                         </Grid>
                         <ControlTemplate.Triggers>
                              <Trigger Property="IsMouseOver" Value="True">
                                   <Setter Property="Stroke" TargetName="rectangle" Value="Green"/>
                                   <Setter Property="Fill" TargetName="rectangle" Value="LightGreen"/>
                                   <Setter Property="Visibility" TargetName="imageMouseOver" Value="Visible"/>
                              </Trigger>
                         </ControlTemplate.Triggers>
                    </ControlTemplate>
               </Setter.Value>
          </Setter>
     </Style>
</Window.Resources>

     <Grid>
          <Button x:Name="buttonTwoImages"
                  aps:CustomButton.Image="Images/largeSaveIcon.png"
                  aps:CustomButton.ImageMouseOver="Images/largeSaveIconMouseOver.png"
                  Style="{StaticResource btnSaveOrb}"
                  Width="151"
                  Height="47"
                  Content="SaveAs">
          </Button>
     </Grid>
</Window>

One thing to note here is the reference to the clr-namespace at the top of the xaml file. Below are two screenshots showing the button in action. The first shows the button in its normal state while the second shows the button in its  mouse over state with the mouse over image. I hope you all realize there are limitless possibilities with attached properties. Enjoy!

Read Full Post »