Click Ok
Click Ok

Reputation: 8852

How to bind UIElements in XAML?

I have a class:

class LinkedTextBox: TextBox
{
    public TextBox TextBoxA { get; set; }
    public TextBox TextBoxB { get; set; }
}

Say I have two Textboxes:

    <TextBox x:Name="txt1" />
    <TextBox x:Name="txt2" />

How do I to specify that TextBoxes on my Xaml?

My tests:

(1) "The TypeConverter for "TextBox" does not support converting from a string."

    <local:LinkedTextBox TextBoxA="txt1" TextBoxB="txt2" />

(2) "A 'Binding' cannot be set on the 'TextBoxA' property of type 'LinkedTextBox'. A 'Binding' can only be set on a DependencyProperty of a DependencyObject."

    <local:LinkedTextBox 
        TextBoxA="{Binding ElementName=txt1}"  
        TextBoxB="{Binding ElementName=txt2}"  
        />

I think that there is an obvious way to do, but I don't know how to...

Upvotes: 1

Views: 1291

Answers (1)

Right. Your second example is correct XAML, but it fails because TextBoxA and TextBoxB are the wrong kind of property. The target of a Binding must be a DependencyProperty of a DependencyObject, like it says on the tin. TextBox is already a DependencyObject and you're subclassing it, so that part's taken care of. And defining a DependencyProperty is trivial.

You would define TextBoxA like this, and TextBoxB likewise:

public class LinkedTextBox : TextBox
{
    #region TextBoxA Property
    public TextBox TextBoxA
    {
        get { return (TextBox)GetValue(TextBoxAProperty); }
        set { SetValue(TextBoxAProperty, value); }
    }

    //  Careful with the parameters you pass to Register() here.
    public static readonly DependencyProperty TextBoxAProperty =
        DependencyProperty.Register("TextBoxA", typeof(TextBox), typeof(LinkedTextBox),
            new PropertyMetadata(null));
    #endregion TextBoxA Property
}

But what is your intent here? What are you trying to accomplish? It's very likely that you can do it by binding existing properties to each other in a normal way, without any of these subclass monkeyshines. Possibly you'd want an attached property, which is a specialized type of dependency property.

UPDATE

OP wants to add visual elements illustrating relationships among the text boxes. If you want to add a visual overlay, the WPF Way to Do That is to write an Adorner. So you'd write some kind of TextBoxLinkingAdorner with TextBoxA and TextBoxB dependency properties, and apply that to the main text box, which depending on your requirements might not even have to be a subclass.

Your dependency properties might need to do some work when their values change; if so, they'd look more like this, assuming an Adorner subclass named TextBoxLinkerAdorner:

    #region TextBoxA Property
    public TextBox TextBoxA
    {
        get { return (TextBox)GetValue(TextBoxAProperty); }
        set { SetValue(TextBoxAProperty, value); }
    }


    public static readonly DependencyProperty TextBoxAProperty =
        DependencyProperty.Register("TextBoxA", typeof(TextBox), 
            typeof(TextBoxLinkerAdorner),
            new FrameworkPropertyMetadata(null,
                    FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
                    TextBoxA_PropertyChanged)
                        { DefaultUpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged });

    protected static void TextBoxA_PropertyChanged(DependencyObject d, 
        DependencyPropertyChangedEventArgs e)
    {
        var obj = d as TextBoxLinkerAdorner;
    }
    #endregion TextBoxA Property

If all you're looking at on the text boxes is their size and location, you might write an adorner that links arbitrary UIElements, not just text boxes. The sky's the limit! If you can dream it, you can adorn it!

Upvotes: 3

Related Questions