9

I have a custom control called EnhancedTextBox which is a UserControl that has a TextBox and a Button. To the consumer I want it to mostly look like a TextBox, so I did the following:

<UserControl.Template>
    <ControlTemplate TargetType="textBoxes:EnhancedTextBox">
    ...
    <TextBox Text="{TemplateBinding Text}"...

And in EnhancedTextBox I have

public static readonly DependencyProperty TextProperty =
  DependencyProperty.Register("Text", typeof (String), typeof (EnhancedTextBox));

public String Text
{
  get { return (String) GetValue(TextProperty); }
  set { SetValue(TextProperty, value); }
}

Yet, when I use it as the following:

<EnhancedTextBox Text="{Binding MyText, Mode=TwoWay, NotifyOnSourceUpdated=True, UpdateSourceTrigger=PropertyChanged}}" />

Then, MyText is never updated, as well as I inspect EnhancedTextBox.Text and it is null. What am I missing? I have been staring at this for a bit and can't figure out what is wrong. I even thought it might be the fact that I was using the same name, so create a property called Text1 which did not work....

Also of note, if I use a regular TextBox, then this all works. So, I am fairly certain the problem is with the EnhancedTextBox itself

Justin Pihony
  • 66,056
  • 18
  • 147
  • 180

2 Answers2

26

I figured it out after reading this MSDN about TemplateBinding. Specifically,

A TemplateBinding is an optimized form of a Binding for template scenarios, analogous to a Binding constructed with {Binding RelativeSource={RelativeSource TemplatedParent}}.

So, I decided to do this explicitly...which would allow me to set the UpdateSourceTrigger (still not sure why it doesn't default to PropertyChanged)

<TextBox Text="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Text, UpdateSourceTrigger=PropertyChanged}"....

And, now it is working. TemplateBinding does not even expose these properties....again, not sure why

Justin Pihony
  • 66,056
  • 18
  • 147
  • 180
  • Hey, today I too experienced the same issue and its working now with your solution but if both `TemplateBinding Value` the `{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Value}` are analogous then why is it accepting! If till now you've figured out and answer it would be kind of you to share here and update your answer. Thank You! – Himanshu Sep 18 '16 at 05:33
  • There's no UpdateSourceTrigger on TemplateBinding because TemplateBinding is a one-way binding to the view. The MSDN link you posted states: _A TemplateBinding is always a one-way binding, even if properties involved default to two-way binding._ Not sure why they didn't allow two-way binding though. – mikelt21 Oct 26 '17 at 16:35
  • Old, but I struggled with this. Note that you can set the default bindings for your own dependency properties: https://stackoverflow.com/questions/2663965/is-there-a-way-to-specify-a-custom-dependency-propertys-default-binding-mode-an . In my case I had to use the binding above, with Mode=TwoWay and I'd also set the dependency property default binding to two way. Now binding to a textbox worked without also having to specify there that it had to be two way. – Roy T. Dec 12 '17 at 13:41
-1

You are missing the CallBack when you register the property.

Here's a sample code.

    public bool IsSelected
    {
        get { return (bool)GetValue(IsSelectedProperty); }
        set { SetValue(IsSelectedProperty, value); }
    }

    public void IsSelectedChangedCallback()
    {

        //actions when property changed

    }

    private static void OnSelectedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        userControl.IsSelectedChangedCallback();
    }

    public static readonly DependencyProperty IsSelectedProperty = DependencyProperty.Register("IsSelected", typeof(bool), typeof(MyUserControl), new PropertyMetadata(new PropertyChangedCallback(OnSelectedChanged)));
user2880486
  • 1,068
  • 7
  • 16
  • 1
    This is not it. The callback would get called, but the bound `MyText` property would still not get updated. – ANeves Jan 07 '16 at 11:08