Pass through bound properties in a custom control

697 views
Skip to first unread message

Brian Noyes

unread,
Aug 18, 2011, 5:44:14 PM8/18/11
to wpf-di...@googlegroups.com

Any of you have any experience and resources for addressing a situation similar to this:

 

Define a DoubleTextBox:

-        User control that wraps a normal TextBox

-        Exposes a double Value Dependency property that the user can bind to a source object

-        Real target of the Value binding is the Text property of the encapsulated TextBox, but need some custom logic in the loop when values are set to convert to special text representations for some values

-        Source object can validate Values set with IDataErrorInfo or exceptions, need to pass those through and indicate invalid inputs on the TextBox

-        Need to convert the input string to double and set the Value property’s source object property

 

I can easily handle such a control where a user binding for the exposed custom propery is not involved, but not sure how to push a value through a binding programmatically to the source object for the binding. And of course the real requirement I am trying to address is not a single encapsulated control, it is a little grouping of several controls that will be shown in several screens and I don’t want to have to repeat the MVVM hook up I know very well how to do to address it in a single screen.

 

Thanks

Brian

 

-----------------------------------------
Brian Noyes
Chief Architect, IDesign Inc
Microsoft Regional Director / MVP
http://www.idesign.net
+1 703-447-3712
-----------------------------------------

 

Sacha Barber

unread,
Aug 19, 2011, 3:27:31 AM8/19/11
to wpf-di...@googlegroups.com
I have to say I don't get this, why can't you just set the wrapped TextBox.Text property when your new property changes after your rules are happy, and change the new properties GetValue(..) to just return the wrapped TextBox.Text property.

Or am I missing something?



--
Sacha Barber
sacha....@gmail.com

Peter O'Hanlon

unread,
Aug 19, 2011, 3:33:03 AM8/19/11
to wpf-di...@googlegroups.com
I wondered that, and came to the conclusion that I must be missing something.

From: Sacha Barber
Sent: 19 August 2011 08:27
To: wpf-di...@googlegroups.com
Subject: Re: [WPF Disciples] Pass through bound properties in a custom control

Sacha Barber

unread,
Aug 19, 2011, 3:38:04 AM8/19/11
to wpf-di...@googlegroups.com
Ok so missing something it is.
--
Sacha Barber
sacha....@gmail.com

Brian Noyes

unread,
Aug 19, 2011, 8:30:58 AM8/19/11
to wpf-di...@googlegroups.com

Because if the user of my control has set the exposed Value property with a {Binding} to some other object’s property, setting the dependency property in my control’s code behind replaces their binding with the new value. It also doesn’t address how to reflect validation errors.

Colin E.

unread,
Aug 19, 2011, 9:04:42 AM8/19/11
to wpf-di...@googlegroups.com
Hi Brian,

I still cannot quite visualise the issue here. When the consumer of
the control binds to the Value of your UserControl, the DoubleTextBox
is the target of the binding. However, if you use binding to wire-up
the UI of your DoubleTextBox internally, for example binding the
DoubleTextBox.Value property to a TextBlox, in this case
DoubleTextBox.Value is the source and your TextBox within your
control's UI is the target

The two should not cancel each other out, they are different targets.

The only thing you have to do is ensure that you do not change the
DataContext of DoubleTextBox in order to wire-up your UI. I typically
set the 'LayoutRoot' of my UserControl to this, allowing the
DataContext of the UserControl to inherit properly.

Perhaps I have misunderstood (as well!), but this sounds relatively
simple to me!

Colin E.

On Fri, Aug 19, 2011 at 1:30 PM, Brian Noyes

--
Regards,
Colin E.

Brian Noyes

unread,
Aug 19, 2011, 11:00:38 AM8/19/11
to wpf-di...@googlegroups.com
OK, so if I have someone binding my Value property like so:
<Window x:Class="EncapsulatedBindableControls.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:EncapsulatedBindableControls"
        Title="MainWindow"
        Height="350"
        Width="525"
        xmlns:my="clr-namespace:EncapsulatedBindableControls">
    <Window.Resources>
        <local:SomeDataObject x:Key="SomeObj"
                              InterestRate="23.1" />
    </Window.Resources>
    <Grid>
        <my:DoubleTextBox HorizontalAlignment="Left"
                          Width="100"
                          Value="{Binding Source={StaticResource SomeObj}, Path=InterestRate, UpdateSourceTrigger=PropertyChanged}"
                          Margin="10,10,0,0"
                          x:Name="doubleTextBox1"
                          VerticalAlignment="Top" />
        <TextBox Margin="10,50,0,0" />
    </Grid>
</Window>
The code behind tries to set the ValueProperty dependency property through its wrapper property when the Text of the encapsulated TextBox changes (so that it can intercept and handle special values). But setting Value kills the binding:
private void TrySetValue()
{
    if (string.IsNullOrWhiteSpace(myTextBox.Text)) return;
 
    double convertedValue = double.Parse(myTextBox.Text);
    var binding = GetBindingExpression(ValueProperty);
    Debug.Assert(binding != null);
    Value = convertedValue;
    binding = GetBindingExpression(ValueProperty);
    Debug.Assert(binding == null);
}
--

Peter O'Hanlon

unread,
Aug 19, 2011, 11:06:56 AM8/19/11
to wpf-di...@googlegroups.com
To be honest mate, I can't see anything there that you couldn't do with an attached behavior on a textbox. That would be my first choice.

From: Brian Noyes
Sent: 19 August 2011 16:02

Brian Noyes

unread,
Aug 19, 2011, 11:14:50 AM8/19/11
to wpf-di...@googlegroups.com

Again I am was simplifying the scenario the try to find an answer to the one part I can’t solve. The real scenario is more complicated with a cluster of several controls with some semi-complex value transformations between what the user inputs and what the value produced is, and this is needed on several screens. It is not a single control single property scenario I am trying to address.

 

Thanks anyway, guess it just doesn’t translate by email.

Peter O'Hanlon

unread,
Aug 19, 2011, 11:19:55 AM8/19/11
to wpf-di...@googlegroups.com
Yeah, sorry mate. If you could send a use case, we might be able to help.

From: Brian Noyes
Sent: 19 August 2011 16:15

Colin E.

unread,
Aug 19, 2011, 11:27:48 AM8/19/11
to wpf-di...@googlegroups.com
Hi Brian,

I tested this out, and it works the way I would have expected, see the
attached project.

In my example I have a user control with a TextBox that is bound to
the property that the user control exposes to the control's clients.
There is also a button that sets the value directly. Clicking this
button sets the exposed value, but binding still works afterwards.

Again, hope I understood correctly!

Regards,
Colin E.

Testing.zip

Bill Kempf

unread,
Aug 19, 2011, 12:33:57 PM8/19/11
to wpf-di...@googlegroups.com
I've read these e-mails quickly, so maybe I'm not understanding you correctly, but it sounds like you're describing the "Control Local Values Bug" (http://blogs.msdn.com/b/vinsibal/archive/2009/03/24/the-control-local-values-bug.aspx). If so, the answer may be SetCurrentValue (http://blogs.msdn.com/b/vinsibal/archive/2009/05/21/the-control-local-values-bug-solution-and-new-wpf-4-0-related-apis.aspx).
--
 Quidquid latine dictum sit, altum sonatur.
- Whatever is said in Latin sounds profound.

War is peace. Freedom is slavery.  Bugs are features.

Brian Noyes

unread,
Aug 19, 2011, 12:39:42 PM8/19/11
to wpf-di...@googlegroups.com

Wow. OK, this is a subtle one that I can get working now, but I can't fully explain why. 

I finally isolated it to this: If the binding on Value in the containing form is TwoWay, life is good. If it is not, setting Value programmatically inside the control kills the binding.

In other words, this works:

<local:DoubleTextBox Value="{Binding Path=MyValue, Mode=TwoWay}"/>

This does not:

<local:DoubleTextBox Value="{Binding Path=MyValue}"/>

I modified your sample slightly to bind the contained TextBox to a string property in the control itself and did the setting of the Value property and binding checking from there:

<TextBox Text="{Binding StringSource}"/>

      private string _StringSource;
      public string StringSource
      {
          get
          {
              return _StringSource;
          }
          set
          {
              _StringSource = value;
              var binding = GetBindingExpression(ValueProperty);
              Debug.Assert(binding != null);
              Value = 77.0;
              binding = GetBindingExpression(ValueProperty);
              Debug.Assert(binding == null);
          }
      }

And sure enough, the binding was intact after setting Value if the Mode=TwoWay in the users binding, but it dies on setting Value if Mode=OneWay (the default).

I understand that if it is OneWay the value would never be pushed to the source object property, but its unclear to me why it would kill the binding by setting the property programmatically.

Guess I better set the default for that property to TwoWay!
Thanks for the help everyone.
Brian

Colin Eberhardt

unread,
Aug 19, 2011, 12:52:14 PM8/19/11
to Brian Noyes, wpf-di...@googlegroups.com
Glad to hear you found the issue. It certainly is counter intuitive. I really like the BindingMode.Default concept, not least because the default binding mode for most properties is TwoWay, which differs from the default behavior for Silverlight.

Colin E.

From: Brian Noyes
Sent: 19 August 2011 17:39

To: wpf-di...@googlegroups.com
Subject: Re: [WPF Disciples] Pass through bound properties in a custom control

Colin Eberhardt

unread,
Aug 19, 2011, 1:03:59 PM8/19/11
to wpf-di...@googlegroups.com
Hmm... Looks like I forgot to insert a 'dis' in there before the 'like' ...

From: Colin Eberhardt
Sent: 19 August 2011 17:52
To: Brian Noyes; wpf-di...@googlegroups.com
Subject: RE: [WPF Disciples] Pass through bound properties in a custom control

Reply all
Reply to author
Forward
0 new messages