Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Chaining DependencyProperties

Let's say I have a custom control which wraps another control (for example MyCustomButton). I expose a property Content, which wraps the inner control:

    public object Content
    {
        get { return innerControl.Content; }
        set { innerControl.Content = value; }
    }

In order for a consumer to bind to this property, I need to define a DependencyProperty for it:

 public static DependencyProperty ContentProperty = DependencyProperty.Register("Content", typeof (object), typeof (MyCustomButton));

but now I need my property definition to use GetValue/SetValue:

    public object Content
    {
        get { return GetValue(ContentProperty); }
        set { SetValue(ContentProperty, value); }
    }

so I'm not wrapping the value of the inner control anymore.

I can define PropertyMetadata to handle the PropertyChanged event of the DependencyProperty, but then I need a bunch of plumbing code to keep the values in sync and prevent infinite loopbacks on changed.

UPDATE: I can't just derive from Button because my UserControl has various other concerns.

Is there a better way to do this?

like image 818
Jeff Avatar asked Dec 14 '11 16:12

Jeff


People also ask

What is dependency property?

A dependency property can reference a value through data binding. Data binding works through a specific markup extension syntax in XAML, or the Binding object in code. With data binding, determination of the final property value is deferred until run time, at which time the value is obtained from a data source.

What is difference between dependency property and attached property?

Attached properties are a type of dependency property. The difference is in how they're used. With an attached property, the property is defined on a class that isn't the same class for which it's being used. This is usually used for layout.

What is the biggest feature of dependency property?

Arguably the biggest feature of a dependency property is its built-in ability to provide change notification. The motivation for adding such intelligence to properties is to enable rich functionality directly from declarative markup.


1 Answers

Well, depending on the particulars of why you're wrapping a button with a user control, you could define a custom control that inherits from button. Then, instead of wrapping the button and exposing the wrapped methods and properties that you want, you can simply override methods and properties whose behavior you want to define the custom control. This way, you'll get all of the functionality of button without the need to reinvent the wheel.

Here's a google link that walks you through it (one of the first that I found - there are plenty): http://knol.google.com/k/creating-custom-controls-with-c-net#

If the user control has other concerns, this may not be an option for you, but I'm offering this answer because the only purpose that you've mentioned for it is wrapping the button. I'd personally favor creating a custom control and inheriting rather than a user control and wrapping if the control in question is simply meant to be a more specific kind of wrapped/inherited control (i.e. button in your case).

Edit: In light of updated question...

You could do something along these lines. Here is the XAML of the client of your user control:

<Grid>
    <local:MyControl ButtonContent="Click Me!"/>
</Grid>
</Window>

Here is the XAML for the user control itself:

 <UserControl x:Class="GuiScratch.MyControl"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:GuiScratch"
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">
    <Grid>

        <StackPanel>
            <ContentControl Content="Asdf"/>
            <Button Content="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:MyControl}},Path=ButtonContent}"/>
        </StackPanel>

    </Grid>
</UserControl>

And, here is the code behind:

public partial class MyControl : UserControl
{

    public static readonly DependencyProperty ButtonContentProperty = 
    DependencyProperty.Register("ButtonContent", typeof(object), typeof(MyControl), 
    new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.AffectsRender));

    public object ButtonContent
    {
        get { return (object)GetValue(ButtonContentProperty); }
        set { SetValue(ButtonContentProperty, value); }
    }

    public MyControl()
    {
        InitializeComponent();
    }
}

So, you don't need to handle the binding at all through code. Your client XAML binds to your dependency property, as does the XAML of the user control itself. In this fashion, they share the dependency property setting. I ran this in my little scratchpad, and the result is (at least my understanding of) what you're looking for. The main window displays the user control as a stack panel with the text "Asdf" and then a button with the text "Click Me!"

like image 172
Erik Dietrich Avatar answered Oct 11 '22 14:10

Erik Dietrich