Question about Databinding - binding controls to members of my business object.

M

Michael.Suarez

Let's suppose I have an instance of MyClass, which has the properties
MyText1 and MyText2, and sets the values of MyText1 and MyText2 to 'A'
and 'B' in it's constructor.

Let's also suppose I have a Form with textBox1, textBox2, btnShowValue,
and btnNew.

Let's also suppose I have this code.

//member of Form
MyClass MyObject;

//in Form Load Method:
{
MyObject = new MyClass();

textBox1.DataBindings.Add("Text", MyObject, "MyText1");
textBox2.DataBindings.Add("Text", MyObject, "MyText2");
}

//in btnShowValue Click Method
{
MessageBox.Show(MyObject.MyText1);
MessageBox.Show(MyObject.MyText2);
}

//in btnNew Click Method
{
MyObject = new MyClass();
}


If I were to run this program, I could start typing into Textbox1 and
Textbox2. Then if I were to click btnShowValue, I would see
MessageBoxes with the values of what I just typed, being as the
textboxes are bound to the properties of the object.

BUT, If I were to click btnNew, I would expect Textbox1 and Textbox2 to
revert to the default values 'A' and 'B'.

They do not. They stay the same. And clicking btnShowValues gives you
'A' and 'B' from now on, no matter what you type in the textboxes.

My question is WHY? What am I missing here?
and How do i alter this code so that it works the way I want it to?
 
N

Nicholas Paldino [.NET/C# MVP]

Michael,

When you pass the MyObject reference to the Add method, it will remember
the reference, but it knows nothing about the variable or when it changes.

What you would have to do is remove the binding, and then add a new one,
with a reference to the new class instance.

Hope this helps.
 
M

Marc Gravell

An alternative to the above is to bind not the the object, but to a
BindingSource; this acts as a proxy between the UI and one-or-more objects
(potentially allowing cursor navigation, but that's an aside for this
scenario).

All you then do is change the object in the BindingSource, leaving you to do
your bindings in the designer (if you so choose).

I posted a full working example of this to this group previously - 8th Dec
2005, titled "Re: Binding data to form controls".

Marc
 
M

Michael.Suarez

Thanks for the responses.

It appears as though the BindingSource is new to 2005. My project uses
a .Net API that was created in 1.1 and not compatible in a 2.0 project,
therefore restricting me to use VS 2003.

Anything comparable to a BindingSource in 2003?
 
M

Marc Gravell

Not as far as I know. IIRC, you didn't state 1.1 in the original question so
I assumed 2.0; in this case you have to do it the hard way (as per the other
poster).

Personally, my recommendation is that it is better to invest time making an
app 2005 compatible than to invest time working around 2003 limitations that
are addressed (often very gracefully) in 2005 - however, I appreciate that
this is not always achievable, particularly if you only want to make a minor
change.

Marc
 
M

Michael.Suarez

Appreciate the feedback.

According to these responses, these are the changes I've made:

//in Form Load Method:
{
MyObject = new MyClass();

SetDataBindings();
}

//in btnNew Click Method
{
MyObject = new MyClass();

SetDataBindings();
}

//in SetDataBindings Method
{
foreach(Control ctrl in this.Controls)
{
ctrl.DataBindings.Clear();
}
textBox1.DataBindings.Add("Text", MyObject, "MyText1");
textBox2.DataBindings.Add("Text", MyObject, "MyText2");
}

So that works great and eliminates my initial problem. Thanks!
But here is another issue...


lets say I add another button. In it's click event method, I have this
code:
{
MyObject.MyText1 = "C";
MyObject.MyText2 = "D";
}

I would expect the values in the textBoxes to change upon clicking this
button. But they don't!
However, if I start typing into textBox1 then place my cursor in
textBox2, textBox2 all of a sudden displays "D".

So somehow, the application knew to change the value in at least one of
the textBoxes, but only after changing one textbox and putting my
cursor the other.
Why is this? How can I get my application to know to change the values
in both textboxes immediately upon updating MyText1 and MyText2?
 
M

Marc Gravell

This illustrates my previous point about 1.1 vs 2.0.

The "simple" answer (from my external viewpoint) is to move to 2.0 and
implement the INotifyPropertyChanged interface (ammending your setters
accordingly). I don't know of a good way to do this in 1.1, short of cloning
the INotifyPropertyChanged interface and using it to reset your bindings
manually (i.e. catch the event and reset your bindings for the object). This
approach would at least smooth the transition from 1.1 to 2.0, as you would
just discard your local version of INotifyPropertyChanged and your event
handler, and hopefully things would continue to just work.

The INotifyPropertyChanged interface is designed to deal with *exactly* this
scenario in a generic manner, and integrates tightly into bindings.

Marc
 
M

Michael.Suarez

Yeah, unfortunately I can't move to 2.0 as the 3rd party .NET API I am
using isn't compatible. But this is good stuff. I'm sure I will
eventually come across this again in 2005, in which case I will
definately keep INotifyPropertyChanged in mind.

I still feel like there is still something else I can do here.
Something gets triggered when I change one textBox and put the cursor
in the other. If I can only figure out what it is... Then I could
trigger my own PropertyChanged method in all of the "set" portions of
my properties, which could then trigger an event that could tell the
textBoxes that they need to update.
 
B

Bart Mermuys

Hi,

Appreciate the feedback.

According to these responses, these are the changes I've made:

//in Form Load Method:
{
MyObject = new MyClass();

SetDataBindings();
}

//in btnNew Click Method
{
MyObject = new MyClass();

SetDataBindings();
}

//in SetDataBindings Method
{
foreach(Control ctrl in this.Controls)
{
ctrl.DataBindings.Clear();
}
textBox1.DataBindings.Add("Text", MyObject, "MyText1");
textBox2.DataBindings.Add("Text", MyObject, "MyText2");
}

So that works great and eliminates my initial problem. Thanks!
But here is another issue...


lets say I add another button. In it's click event method, I have this
code:
{
MyObject.MyText1 = "C";
MyObject.MyText2 = "D";
}

If you're using NET1.1 you need to have similar named events for each
property (PropertyName+"Changed"), then the UI will refresh when a property
changes, eg.:

public class MyClass
{
private string myText1 = "";

public EventHandler MyText1Changed; //it needs to be EventHandler

public string MyText1
{
get { return myText1; }
set
{
if ( myText1 != value )
{
myText1 = value;
if ( MyText1Changed!=null )
MyText1Changed(this, EventArgs.Empty);
}
}

}



HTH,
Greetings
 
M

Michael.Suarez

Thanks for the info! But this alone didn't solve my problem.

Adding this code gave me a nice MyText1Changed Event. But just having
the event didn't update the UI.
I need the code that will basically tell the textBoxes:
"Hey, the data you are binded to has changed! Update yourselves and
display your new Text values!"

If I had that code, I could certainly put it in the method for my
MyText1Changed event.

I am assuming that there is some way of doing this based on the fact
that if I change textBox1 and put the cursor textBox2, textBox2 all of
a sudden diplays it's new Text value. What is making it display it's
new value? That is what I need. A way of accessing and triggering
whatever it is that makes textBox2 display it's new Text value.

Thanks for the help so far. I feel like the solution is almost there.
 
B

Bart Mermuys

Thanks for the info! But this alone didn't solve my problem.

Adding this code gave me a nice MyText1Changed Event. But just having
the event didn't update the UI.
I need the code that will basically tell the textBoxes:
"Hey, the data you are binded to has changed! Update yourselves and
display your new Text values!"

Yes, but the Changed events will do just that, they will force an UI update,
BUT notice that there is a silly mistake in my code:

public EventHandler MyText1Changed; //it needs to be EventHandler

that's not an event, i forgot the event keyword, it must be:

public event EventHandler MyText1Changed; //it needs to be of type
EventHandler


HTH,
Greetings
 
M

Michael.Suarez

ahh hah.
Thats it!

This works now. Funny how simply adding an event forces a UI update.
And even stranger that the naming of the event is so important. Not
exactly sure why this works. But it does! Thanks again for all the help.
 
B

Bart Mermuys

Hi,

ahh hah.
Thats it!

This works now. Funny how simply adding an event forces a UI update.
And even stranger that the naming of the event is so important. Not
exactly sure why this works.

If you are interested, it goes like this:
custom object <-> PropertyManager 1<--00 Binding <--> Control prop.

So for each custom object you bind there will be a PropertyManager managing
the binding, it will create a PropertyDescriptor (using reflection) for each
property that's on the custom object if it doesn't implement
ICustomTypeDescriptor. The PropertyDescriptor will search for a similar
named event (+"Changed") and expose it. The Binding will then add an
eventhandler to that Changed event and when the event is fired the Binding
will notifiy the PropertyManager that it must refresh all Bindings (and
therefore all properties are requeried).

HTH,
Greetings
 
M

Michael.Suarez

This is great stuff. Really. Thank you very much.
For anyone who happens to stumble upon this thread looking to do the
same thing, here is my final source code:

MyClass.cs:

public class MyClass
{
private string text1;
private string text2;

public event EventHandler MyText1Changed;
public event EventHandler MyText2Changed;

public string MyText1
{
get{return text1;}
set
{
if ( text1 != value )
{
text1 = value;
if ( MyText1Changed!=null )
{
MyText1Changed(this, EventArgs.Empty);
}
}
}
}

public string MyText2
{
get{return text2;}
set
{
if ( text2 != value )
{
text2 = value;
if ( MyText2Changed!=null )
{
MyText2Changed(this, EventArgs.Empty);
}
}
}
}

public MyClass()
{
text1 = "A";
text2 = "B";
}
}

create a form with 2 textboxes and 3 buttons:
Form1.cs (after windows form designer generated code):

MyClass MyObject;


private void Form1_Load(object sender, System.EventArgs e)
{
SetDataBindings();
}

private void SetDataBindings()
{
MyObject = new MyClass();

foreach(Control ctrl in this.Controls)
{
ctrl.DataBindings.Clear();
}
textBox1.DataBindings.Add("Text", MyObject, "MyText1");
textBox2.DataBindings.Add("Text", MyObject, "MyText2");

}

private void btnShowValues_Click(object sender, System.EventArgs e)
{
MessageBox.Show("MyText1: " + MyObject.MyText1 + " MyText2: " +
MyObject.MyText2);
}

private void btnNew_Click(object sender, System.EventArgs e)
{
SetDataBindings();
}

private void btnSetValues_Click(object sender, System.EventArgs e)
{
MyObject.MyText1 = "C";
MyObject.MyText2 = "D";
}
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top