Search code examples
wpfdependency-propertiesdependencyobject

Can we implement dependency property in a class that does not inherit from DependencyObject? If yes, what is the difference?


Can we implement dependency property in a class that does not inherit from DependencyObject? If yes what is the difference?


Solution

  • Yes you can. This is a variant of an Attached Property. From How to Create an Attached Property:

    If your class is defining the attached property strictly for use on other types, then the class does not have to derive from DependencyObject. But you do need to derive from DependencyObject if you follow the overall WPF model of having your attached property also be a dependency property.

    The difference begins in how you define an attached property. Instead of Register, you have to use the RegisterAttached method and you have to define the get and set accessors as static methods with the following naming convention, where PropertyName is the name of the attached property.

    • public static object GetPropertyName(object target)
    • public static void SetPropertyName(object target, object value)

    Let's look at a simple example. Suppose you want create a button that shows an image and a text side-by side. Unfortunately, a Button only has a single Content. As you do not want to create a custom control right now, you try to solve the issue by creating a content template and an attached property for the path of an image to display.

    public static class IconButtonProperties
    {
       public static readonly DependencyProperty SourceProperty = DependencyProperty.RegisterAttached(
          "Source", typeof(string), typeof(IconButtonProperties));
    
       public static void SetSource(UIElement element, string value)
       {
          element.SetValue(SourceProperty, value);
       }
    
       public static string GetSource(UIElement element)
       {
          return (string) element.GetValue(SourceProperty);
       }
    }
    

    Now you can attach this property to a button in your view to define an image path. Here the attached property differs in that you define it on a different type (Button) using its owner type IconButtonProperties.

    <Button ContentTemplate="{StaticResource ImageTextContentTemplate}"
            local:IconButtonProperties.Source="Resources/MyImage.png"
            Content="Click me!"/>
    

    The last big difference is shown in the data template that uses the attached property with a Binding. When binding to an attached property, you have to put the property in parentheses.

    <DataTemplate x:Key="ImageTextContentTemplate">
       <Grid>
          <Grid.ColumnDefinitions>
             <ColumnDefinition Width="Auto"/>
             <ColumnDefinition/>
          </Grid.ColumnDefinitions>
          <Image Grid.Column="0"
                 Source="{Binding (local:IconButtonProperties.Source), RelativeSource={RelativeSource AncestorType={x:Type Button}}}"/>
          <TextBlock Grid.Column="1"
                     VerticalAlignment="Center"
                     Margin="5, 0, 0, 0"
                     Text="{Binding}"/>
       </Grid>
    </DataTemplate>
    

    As you can see, attached properties are invaluable for extensibility and binding in WPF. For more information on attached properties in general, you can refer to the documentation: