Binding BOs to custom controls

Binding BOs to custom controls

Old forum URL: forums.lhotka.net/forums/t/7499.aspx


OpticTygre posted on Monday, August 24, 2009

Hey all. I have a winform app that contains a bindingsource hooked up to one of my BOs. I also have a custom user control that contains a label and a textbox (for simplicity's sake). What I'd like to be able to do is bind a custom property of my user control to a property on my BO (done), so I can display the property name on the label (done), and allow the textbox to act as if were bound directly to the bindingsource (not done) as well as have errorprovider capability (not done).

I have the label text of my user control hooked up properly so that when the binding on my control changes, the text of the label is updated.

I seem to be having issue with setting the databinding on my text property of my textbox control, as well as hooking up an errorprovider to display any validation issues.

I hope this isn't too confusing to understand what I'm trying to do. Can anyone give any pointers as to how to implement this?

Thanks!

RockfordLhotka replied on Monday, August 24, 2009

It has been many years since I did anything like this, but I seem to recall that there was some obscure attribute you had to put on the Text property of a control to make it bindable. Normally this attribute isn't required, but the Text property is defined by the base class and is missing the attribute or something like that.

Of course I could be entirely off base, my memory of this is foggy...

jemmer replied on Monday, August 24, 2009

BindableAttribute ??

OpticTygre replied on Tuesday, August 25, 2009

Right. In my user control, I have declared a public property: MyProperty.

I have placed 3 attributes on that property:
System.ComponentModel.Browsable(True)
System.ComponentModel.Description("Some description.")
System.ComponentModel.Bindable(True)

In the designer, I set the "MyProperty" binding equal to a Property of my BO through my BindingSource on the main form.

I am also capturing the DataBindings_CollectionChanged event in my User Control. Inside of that method, I set my label's text to the BindingField of the Me.DataBindings("MyProperty").BindingMemberInfo object.

My issue is that everything I do from this point to get the textbox's "Text" property databound to the same binding as the exposed "MyProperty" is throwing me design-time errors.

Am I being difficult? Is there an easier way to bind the internal label and text?

tetranz replied on Tuesday, August 25, 2009

I saw your post yesterday and almost replied. I don't quite follow what you're trying to do which is unusual. I've used plenty of custom user controls on forms with databinding and never had a problem.

Putting that aside for a moment, have you implemented INotifyPropertyChanged in your user control?  You need that for changes to flow from the control to the BO.

It's very simple. This sort of thing (C# sorry)

        public event PropertyChangedEventHandler PropertyChanged;

        private void OnPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName);
            }
        }

Code in MyProperty's setter would set the textbox.Text.
Code in MyProperty's getter would get the textbox.Text.

In the textbox's TextChanged event you would call OnPropertyChanged("TextboxName") so that databinding knows that MyProperty has changed.

In some more complex controls where one inner control affects another, I have had to use flags to make things work smoothly and avoid getting into infinite loops.

The one thing that this won't do for you is make the error icons appear within the control beside the appropriate inner control. Your BO will have a rule on MyProperty so if that is broken then the error appears beside the user control. I have once or twice done something klugy to give the illusion of what you're trying to do by having an zero size checkbox positioned on top of the user control and bind that to a BO property with a rule.

OpticTygre replied on Tuesday, August 25, 2009

Actually, I finally got it, and took a little bit of a different route.

In my user control, "MyProperty" contains the NotifyParent and Bindable attributes. The getter exposes textbox.text and the setter sets textbox.text.

The user control class itself contains the DefaultBindingProperty("MyProperty") attribute.

With those things in place, as well as detecting when my databindings change via the Me.Databindings.CollectionChanged event so I can update the label, everything automatically bubbles up to the parent without having to deal with the PropertyChanged event.

Now, if there were only an easy way to databind to the actual PropertyInfo object to get the FriendlyName out for my label usage, we'd be all set. ;)

OpticTygre replied on Tuesday, August 25, 2009

Oh, and FYI, you can also place an ErrorProvider on your form, and in the DataBindings.CollectionChanged event, set the datasource of the ErrorProvider = Me.Bindings("MyProperty").DataSource, and viola, you have an error provider displaying CSLA validation errors for each control in your user control.

Copyright (c) Marimer LLC