6

I have my own UserControl, a LabeledTextBox which is the combination of a Label and a..well, TextBox. This Control has two properties: Caption which will be bound to the caption of the Label, and Value which will be bound to the Text of the TextBox.

Code:

public class LabeledTextBox : Control
{
    static LabeledTextBox()
    {
        DefaultStyleKeyProperty.OverrideMetadata(typeof(LabeledTextBox), new FrameworkPropertyMetadata(typeof(LabeledTextBox)));
    }

    public string Caption
    {
        get { return (string)GetValue(CaptionProperty); }
        set { SetValue(CaptionProperty, value); }
    }

    // Using a DependencyProperty as the backing store for Caption.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty CaptionProperty =
        DependencyProperty.Register("Caption", typeof(string), typeof(LabeledTextBox), new UIPropertyMetadata(""));


    public string Value
    {
        get { return (string)GetValue(ValueProperty); }
        set { SetValue(ValueProperty, value); }
    }

    // Using a DependencyProperty as the backing store for Value.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty ValueProperty =
        DependencyProperty.Register("Value", typeof(string), typeof(LabeledTextBox), new UIPropertyMetadata(""));


}

XAML:

<Style TargetType="{x:Type local:LabeledTextBox}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type local:LabeledTextBox}">
                <Grid>
                    <Grid>

                    <Grid.RowDefinitions>
                        <RowDefinition />
                        <RowDefinition />
                    </Grid.RowDefinitions>

                    <Label Grid.Row="0" Content="{TemplateBinding Caption}" />
                    <TextBox  Name="Box" Margin="3,0,3,3" Grid.Row="1" Text="{Binding Value, RelativeSource={RelativeSource TemplatedParent}, Mode=TwoWay}" />

                    </Grid>
                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

Usage:

<uc:LabeledTextBox Caption="Code:" Value="{Binding ExpenseCode}"  />

Initially I thought I had found my answer here: WPF TemplateBinding vs RelativeSource TemplatedParent

That details the difference between TemplateBinding and RelativeSource TemplatedParent. I've changed my code accordingly, but it still feels like I'm missing a step. The OneWay binding does work, my textbox is bound to the Value property, but changes do not register.

How do I get this to work?

Community
  • 1
  • 1
diggingforfire
  • 3,359
  • 1
  • 23
  • 33
  • Have you tried making your Value dependency property TwoWay aswell? Or is the problem that the TextBox does not write into your Value dp? – dowhilefor Apr 20 '12 at 09:29
  • Is it `LabeledTextBox.Value` that isn't changing or is it `ExpenseCode` in the data object? You could add a [PropertyChangedCallback](http://msdn.microsoft.com/en-us/library/system.windows.propertychangedcallback.aspx) to the `Value` dependency property to see if it gets called. – Clemens Apr 20 '12 at 09:31
  • @dowhilefor: is that not what the `Mode=TwoWay` in the XAML is for? @Clemens: I initially did have that callback, and it did get called. In that callback I set the value of the textbox. Do I need to explicitly make the data go back from within the DP? @Ricibob: thanks, but that doesn't seem to be the case. – diggingforfire Apr 20 '12 at 09:46
  • @diggingforfire Looks like everything is ok with the twoway binding inside your control. TwoWay was just missing at the `ExpenseCode` binding, as @akanksha has answered. – Clemens Apr 20 '12 at 10:15
  • 1
    @diggingforfire Your TwoWay Mode is set from TextBox <-> UserControl ... but your user control exposes the value property, which uses a one way binding so your have Usedcontrol -> UserControl <-> TextBox. Remember that 2 bindings are active, the templatebinding and the "user" binding. – dowhilefor Apr 20 '12 at 11:33
  • @dowhilefor: That explains exactly what I was wondering, great. – diggingforfire Apr 20 '12 at 11:35

2 Answers2

7

Change the mode here.

<uc:LabeledTextBox Caption="Code:" Value="{Binding ExpenseCode,Mode=TwoWay}"  /> 

it worked at my end

Akanksha Gaur
  • 2,636
  • 3
  • 26
  • 50
7

Just in case anybody has this problem:

Another approach (maybe more elegant) would be to declare the dependency property of the usercontrol in a way so that it defaults to two way binding (e.g. as the framework TextBox does by default).

This can be achieved as follows (taken from the answer of this Stackoverflow question):

    public DependencyProperty SomeProperty =
        DependencyProperty.Register("Some", typeof(bool), typeof(Window1),
            new FrameworkPropertyMetadata(default(bool),
                FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));

The key here is using FrameworkPropertyMetadata.

Community
  • 1
  • 1
me.
  • 177
  • 2
  • 8