How can I force databinding on all tabs in a Form?

A

aualias

Hi All,

I have several tabs with controls on a Form that is bound to a DataSet. If
I load a DataSet and go from one tab to the next all the data appears
correctly in the controls. However, if I do certain operations before
changing tabs, like entering an incorrect value into a control and the
validation handler fires, the values on the tabs are all empty.

I am assuming the the databinding occurs the first time the tab is shown.
( I don't know if this is true )

Is there a way to cause all the controls to bind on the tabs that are not
visible, without having to explicitly assign a value to each control
whenever a new DataSet is loaded?

Thanks.

Alfredo
 
Y

Ying-Shen Yu[MSFT]

Hi Alfredo,

Winform uses delay initialization to reduce the memory and resource
requirements.
However I'm not sure if this issue is caused by the delay initialization.
Could you post your code snippet of the validating handler?
Also I'm suspecting there might be an internal exception happened during tab
switch, could you try enable catching "first-chance exception" in VS.NET
IDE?
You can enable this option using the following steps:
1. In the menu "Debug", select "Exceptions" to open the Exceptions dialog.
2. Select "Common Language Runtime Exceptions"
3. In the groupbox "When the exception is thrown", set radio selection to
"Break into the debugger"
4. click ok.
Then run your program with debugger (F5), and repeat the steps to see if the
debugger will break in.

If you have any update to this issue, please feel free to reply this thread.
Thanks!
Best regards,

Ying-Shen Yu [MSFT]
Microsoft Community Support
Get Secure! - www.microsoft.com/security

This posting is provided "AS IS" with no warranties and confers no rights.
This mail should not be replied directly, please remove the word "online"
before sending mail.
 
A

aualias

Hi Ying-Shen,

I apologize. The problem is a bit different than I explained. It occurs
when I create a new DataSet and databind it to the controls - not loading an
existing dataset. So, the DataSet initially does not have any values.

I just tried this... If I load a new DataSet, save it, and bring it up in
the UI it will not contain any of the default values. Most likely it is the
delayed initialization that is causing the problem. At what point does the
data get into the DataSet? When the window is shown?

It sounds like I will have to explicitely initialize all the controls. Is
this true?

To follow up on your questions:

There are no exceptions being thrown. I turned on breaking when an
exception is thrown as you suggested. Here is the code for the validation
handler. (NotifyParent() is kind of a kludge to prevent the tab switch -
just sends a custom message to the main window)

private void OnValidateDouble(object sender,
System.ComponentModel.CancelEventArgs e)
{
if ( sender.GetType() != typeof(DoubleTextBox) )
return;

DoubleTextBox tb = (DoubleTextBox)sender;
if ( tb.Text.Trim() == String.Empty )
{
double temp = Math.Round(tb.DefaultValue, ROUND_LEN);
tb.Text = temp.ToString();
if ( !_allowBlank )
{
tb.SelectAll();
e.Cancel = true;
NotifyParent(false);
}

NotifyParent(true);
return;
}

double dVal;
try
{
dVal = Convert.ToDouble(tb.Text);
}
catch ( Exception ex )
{
MessageBox.Show(this, ex.Message, "You must enter a number");
double temp = Math.Round(tb.DefaultValue, ROUND_LEN);
tb.Text = temp.ToString();
e.Cancel = true;
NotifyParent(false);
return;
}

tb.MinimumValue = Math.Round(tb.MinimumValue, ROUND_LEN);
tb.MaximumValue = Math.Round(tb.MaximumValue, ROUND_LEN);

if ( dVal < tb.MinimumValue || dVal > tb.MaximumValue )
{
StringBuilder builder = new StringBuilder();
builder.Append("Maximum value: ");
builder.Append(this.MaximumValue);
builder.Append("\nMinimum value: ");
builder.Append(this.MinimumValue);
MessageBox.Show(this, builder.ToString(), "Value out of range");
double temp = Math.Round(tb.DefaultValue, ROUND_LEN);
tb.Text = temp.ToString();
tb.SelectAll();
NotifyParent(false);
e.Cancel = true;
}

NotifyParent(true);
}

private void NotifyParent(bool status)
{
if ( _parentForm != null )
{
// if the validation fails, the focus will return to the control
// validation will occur a second time before a tab change event is
fired
// cancel the second validation notification message so that the tab
will not change
if ( status == true && _previousValidationFailed == true )
{
_previousValidationFailed = false;
return;
}

_previousValidationFailed = true;

// This is just a wrapper around the SendMessage() API function
ValidationHelper.SendMessage(((Form)_parentForm).Handle,
(int)ValidationHelper.VC_ONVALIDATION,
0,
(status == false) ? 0 : 1);
}
}

Thanks for your help.

Alfredo



Ying-Shen Yu said:
Hi Alfredo,

Winform uses delay initialization to reduce the memory and resource
requirements.
However I'm not sure if this issue is caused by the delay initialization.
Could you post your code snippet of the validating handler?
Also I'm suspecting there might be an internal exception happened during tab
switch, could you try enable catching "first-chance exception" in VS.NET
IDE?
You can enable this option using the following steps:
1. In the menu "Debug", select "Exceptions" to open the Exceptions dialog.
2. Select "Common Language Runtime Exceptions"
3. In the groupbox "When the exception is thrown", set radio selection to
"Break into the debugger"
4. click ok.
Then run your program with debugger (F5), and repeat the steps to see if the
debugger will break in.

If you have any update to this issue, please feel free to reply this thread.
Thanks!
Best regards,

Ying-Shen Yu [MSFT]
Microsoft Community Support
Get Secure! - www.microsoft.com/security

This posting is provided "AS IS" with no warranties and confers no rights.
This mail should not be replied directly, please remove the word "online"
before sending mail.
 
A

aualias

Ying-Shen,

I don't know why it did not show up the first time I tried it, but I am now
getting a "first chance exception". It says...

A first chance exception of type "System.ArgumentException" occurred in
System.Windows.Forms.dll.
Additional information: 0 is not a valid value for 'Value'. 'Value' should
be between 'Minimum' and 'Maximum'.

This exception is occurring in the Leave handler, before the validation code
that I sent to you is called. Here is the code where the exception occurrs:

double temp = Convert.ToDouble(((TextBox)sender).Text);
this.oDataSet.Tables[tblName].Rows[pos][FieldName] = temp; // this is
the assignment that throws

temp is a valid double and is not equal to 0 (which would be ok anyway)
this.oDataSet.Tables[tblName].Rows[pos][FieldName] is of type System.Double
and contains a valid value.

Your instincts were correct about the exception. Do you have any idea what
is throwing this exception? All the values seem fine.

Thanks.

David








aualias said:
Hi Ying-Shen,

I apologize. The problem is a bit different than I explained. It occurs
when I create a new DataSet and databind it to the controls - not loading an
existing dataset. So, the DataSet initially does not have any values.

I just tried this... If I load a new DataSet, save it, and bring it up in
the UI it will not contain any of the default values. Most likely it is the
delayed initialization that is causing the problem. At what point does the
data get into the DataSet? When the window is shown?

It sounds like I will have to explicitely initialize all the controls. Is
this true?

To follow up on your questions:

There are no exceptions being thrown. I turned on breaking when an
exception is thrown as you suggested. Here is the code for the validation
handler. (NotifyParent() is kind of a kludge to prevent the tab switch -
just sends a custom message to the main window)

private void OnValidateDouble(object sender,
System.ComponentModel.CancelEventArgs e)
{
if ( sender.GetType() != typeof(DoubleTextBox) )
return;

DoubleTextBox tb = (DoubleTextBox)sender;
if ( tb.Text.Trim() == String.Empty )
{
double temp = Math.Round(tb.DefaultValue, ROUND_LEN);
tb.Text = temp.ToString();
if ( !_allowBlank )
{
tb.SelectAll();
e.Cancel = true;
NotifyParent(false);
}

NotifyParent(true);
return;
}

double dVal;
try
{
dVal = Convert.ToDouble(tb.Text);
}
catch ( Exception ex )
{
MessageBox.Show(this, ex.Message, "You must enter a number");
double temp = Math.Round(tb.DefaultValue, ROUND_LEN);
tb.Text = temp.ToString();
e.Cancel = true;
NotifyParent(false);
return;
}

tb.MinimumValue = Math.Round(tb.MinimumValue, ROUND_LEN);
tb.MaximumValue = Math.Round(tb.MaximumValue, ROUND_LEN);

if ( dVal < tb.MinimumValue || dVal > tb.MaximumValue )
{
StringBuilder builder = new StringBuilder();
builder.Append("Maximum value: ");
builder.Append(this.MaximumValue);
builder.Append("\nMinimum value: ");
builder.Append(this.MinimumValue);
MessageBox.Show(this, builder.ToString(), "Value out of range");
double temp = Math.Round(tb.DefaultValue, ROUND_LEN);
tb.Text = temp.ToString();
tb.SelectAll();
NotifyParent(false);
e.Cancel = true;
}

NotifyParent(true);
}

private void NotifyParent(bool status)
{
if ( _parentForm != null )
{
// if the validation fails, the focus will return to the control
// validation will occur a second time before a tab change event is
fired
// cancel the second validation notification message so that the tab
will not change
if ( status == true && _previousValidationFailed == true )
{
_previousValidationFailed = false;
return;
}

_previousValidationFailed = true;

// This is just a wrapper around the SendMessage() API function
ValidationHelper.SendMessage(((Form)_parentForm).Handle,
(int)ValidationHelper.VC_ONVALIDATION,
0,
(status == false) ? 0 : 1);
}
}

Thanks for your help.

Alfredo



Ying-Shen Yu said:
Hi Alfredo,

Winform uses delay initialization to reduce the memory and resource
requirements.
However I'm not sure if this issue is caused by the delay initialization.
Could you post your code snippet of the validating handler?
Also I'm suspecting there might be an internal exception happened during tab
switch, could you try enable catching "first-chance exception" in VS.NET
IDE?
You can enable this option using the following steps:
1. In the menu "Debug", select "Exceptions" to open the Exceptions dialog.
2. Select "Common Language Runtime Exceptions"
3. In the groupbox "When the exception is thrown", set radio selection to
"Break into the debugger"
4. click ok.
Then run your program with debugger (F5), and repeat the steps to see if the
debugger will break in.

If you have any update to this issue, please feel free to reply this thread.
Thanks!
Best regards,

Ying-Shen Yu [MSFT]
Microsoft Community Support
Get Secure! - www.microsoft.com/security

This posting is provided "AS IS" with no warranties and confers no rights.
This mail should not be replied directly, please remove the word "online"
before sending mail.
 
Y

Ying-Shen Yu[MSFT]

Hi,

I also tested bounding the TextBox control to an empty dataset,
the data didn't fill into the TextBox so the Textbox displayed it's initial
value, this behavior is expected since there is no row in the underlying
datatable.
To workaround this issue you may set the default value for the column in
the dataset schema editor, then use
BindingManagerBase.AddNew() to create a new item in the underlying
datatable after binding it with the textboxes, this method will create a
temporary datarow with default value.
Does it resolve the first chance exception?

If you still have problem on this issue, maybe there are still something
I'm not aware of , could you seperate this issue into a small repro sample?
so that I can get full understanding on this issue and debug it on my
machine.

By the way, in your description you update the underlying datasource
directly in the OnLeave event handler, as you had seen this event handler
was executed before validation, how about moving it to the Validated event?

Thanks!
Best regards,

Ying-Shen Yu [MSFT]
Microsoft Community Support
Get Secure! - www.microsoft.com/security

This posting is provided "AS IS" with no warranties and confers no rights.
This mail should not be replied directly, please remove the word "online"
before sending mail.
 
A

aualias

"Ying-Shen Yu[MSFT]" said:
Hi,

I also tested bounding the TextBox control to an empty dataset,
the data didn't fill into the TextBox so the Textbox displayed it's initial
value, this behavior is expected since there is no row in the underlying
datatable.
To workaround this issue you may set the default value for the column in
the dataset schema editor, then use
BindingManagerBase.AddNew() to create a new item in the underlying
datatable after binding it with the textboxes, this method will create a
temporary datarow with default value.
Does it resolve the first chance exception?

If you still have problem on this issue, maybe there are still something
I'm not aware of , could you seperate this issue into a small repro sample?
so that I can get full understanding on this issue and debug it on my
machine.

By the way, in your description you update the underlying datasource
directly in the OnLeave event handler, as you had seen this event handler
was executed before validation, how about moving it to the Validated event?

Thanks!
Best regards,

Ying-Shen Yu [MSFT]
Microsoft Community Support
Get Secure! - www.microsoft.com/security

This posting is provided "AS IS" with no warranties and confers no rights.
This mail should not be replied directly, please remove the word "online"
before sending mail.
 
A

aualias

I think that there might be something basic that I am doing wrong here...

When I used CurrencyManager.AddNew() the whole application hung, but I am
not using the dataset schema editor, I am creating the DataSet manually.
Obviously, I used AddNew() incorrectly - I am not clear on how it applies
here.

I moved the code that was in the Leave handler to the Validated handler and
that got rid of the problem of the exception (I would love to know why). It
should be in the Validated handler, but I am not even sure the code is
necessary at this point (I'll look into it later). Anyway, it did help, but
I am having a problem with that exception occurring elsewhere (the
System.ArgumentException).

Do you have any idea of what object within the Framework could be throwing
that exception? At the point where it is thrown, everything looks correct.
My guess is that the problem is with the initialization of the DataSet.
That the assignment of a value or calling
BindingManagerBase.EndCurrentEdit() is triggering the exception because the
dataset is not in the correct state.

I shall try to get a simple working (or not working...) example to show you.
It may be difficult, but it is a good exercise to go through to get a handle
on what is happening.

At this point in the application, I basically want to
1) create a DataSet - I am creating the DataSet in a method - new DataSet,
new columns, adding columns...
2) bind the data
3) initialize the DataSet and UI with default values

Is there a preferred method for doing this? You mentioned using the schema
editor.

Thanks again - you have been very helpful.

Alfredo


"Ying-Shen Yu[MSFT]" said:
Hi,

I also tested bounding the TextBox control to an empty dataset,
the data didn't fill into the TextBox so the Textbox displayed it's initial
value, this behavior is expected since there is no row in the underlying
datatable.
To workaround this issue you may set the default value for the column in
the dataset schema editor, then use
BindingManagerBase.AddNew() to create a new item in the underlying
datatable after binding it with the textboxes, this method will create a
temporary datarow with default value.
Does it resolve the first chance exception?

If you still have problem on this issue, maybe there are still something
I'm not aware of , could you seperate this issue into a small repro sample?
so that I can get full understanding on this issue and debug it on my
machine.

By the way, in your description you update the underlying datasource
directly in the OnLeave event handler, as you had seen this event handler
was executed before validation, how about moving it to the Validated event?

Thanks!
Best regards,

Ying-Shen Yu [MSFT]
Microsoft Community Support
Get Secure! - www.microsoft.com/security

This posting is provided "AS IS" with no warranties and confers no rights.
This mail should not be replied directly, please remove the word "online"
before sending mail.
 
Y

Ying-Shen Yu[MSFT]

Hi Alfredo,

With limited information , I'm not clear about the reason why causes the
application hang when using AddNew method, Will it work if you comment out
the validation code on the bound controls?
If it still hang, how about the CPU utilization when the program hang?

Also you also mentioned you got some exceptions elsewhere and the value
looks correct, I'd like to know if it is the exception you caught is also a
"first-chance exception", if yes, maybe the actual execution pointer is not
in your own code at that time, you may take a look at the call stack
window, to see what function was being executed. if you see [Non-User code]
in call stack, you need to configure VisualStudio debugger to load
apporiate symbols for .NET Framework assemblies to display the complete
call stack information. This KB article will show you how to do
configuration.

<HOW TO: Use a Symbol Server with the Visual Studio .NET Debugger>
http://support.microsoft.com/?id=319037

Please paste the call stack information as well as the code to generate
that data table in your reply to let me know more about your program.

Thanks!

Best regards,

Ying-Shen Yu [MSFT]
Microsoft Community Support
Get Secure! - www.microsoft.com/security

This posting is provided "AS IS" with no warranties and confers no rights.
This mail should not be replied directly, please remove the word "online"
before sending mail.
 
A

aualias

Ying-Shen,

I believe that I have discovered the problem. Basically, I did not pay
proper attention to the call stack because it indicated that the error was
in the .NET Framework. I finally noticed that a NumericUpDown control was
causing he exception because I was binding to the Value property, not the
Text property which it seems must be used for the databinding. (it is not
very clear from the documentation that you should bind to the Text
property - but now the error message makes sense)

The control is on a tab that is not visible when the UI first appears. Now
I get a first-chance exception if I click on a check box before I switch to
the tab with the UpDown control (Decimal.Parse() is called on an empty
string), but this time the exception does not seem to do any harm. After I
switch tabs there is no exception.

It seems that the above is caused by the delayed initialization, but it not
appear to be a problem. If I start up the application and immediately call
DataSet.WriteXml() to save the data, all the data on the tab pages that have
not been displayed seems to be there. WriteXml() must cause the
initialization to take place. Is this true?

Thanks again.

Alfredo
 
Y

Ying-Shen Yu[MSFT]

Hi Alfredo,

In my opinion, the binding to NumericUpDown.Value property is correct, the
exception is also an expected behavior, when the Value property is set, the
new value is validated to be between the Minimum and Maximum values.

The problem is why the NumericUpDown.Value property was initialized to a
value not in the range.

This issue may occur if you didn't set default value to data column when
defining the dataset, and you need use AddNew method to add a row to update
the bounded controls default values, the bounded controls will not be
updated if the bounded data source is emptry.

Since you said in previous reply, the program hung if you called AddNew on
corresponding BindingContext( It might be caused by some other issues, we
can discuss it later). You may try adding a button and try the test code
below:
<code>
private void button1_Click(object sender, System.EventArgs e)
{
//define data table
DataTable table1= new DataTable("Table1");
DataColumn column1 = new DataColumn("ID",typeof(int));

//Set Default Value for this Column
column1.DefaultValue = 10;//change it to 3 will throw ArgumentException
table1.Columns.Add ( column1 );

//create a NumericUpDown control
NumericUpDown numUpDn = new NumericUpDown();
numUpDn.Location = new Point(30,10);
numUpDn.Minimum = 5;
this.Controls.Add(numUpDn);

//Set DataBinding
numUpDn.DataBindings.Add("Value",table1, "ID");

//Call BindingManagerBase.AddNew
BindingContext[ table1 ].AddNew();
}
</code>
This code snippet shows how to define a DataColumn with default value and
add a new row with the presetted default value, the AddNew method also
moves the Current position to the new row.

You may try to apply this approach to your data set definition, it seems
besides these text boxes, you have some other controls bound to this data
table. I suggest you removing all databindings to this data table, then add
them one by one, so that we can see which control causes an exception or
program hang. If you meet an exception please paste the call stack in your
reply.

Thanks!

Best regards,

Ying-Shen Yu [MSFT]
Microsoft Community Support
Get Secure! - www.microsoft.com/security

This posting is provided "AS IS" with no warranties and confers no rights.
This mail should not be replied directly, please remove the word "online"
before sending mail.
 
A

aualias

Hi Ying-Shen,

Everything is working well at this point. I actually took out a support
insident because I was not sure that I understood what was going on. By the
time they got to look at the problem things were ok, but I got to ask a few
questions.

The Text property is the correct property to bind to. I don't know why, and
they didn't seem to either, but two support people told me that binding to
Value is not correct.

When I bind to Text, I still can get a first-chance exception, but it does
not affect the other controls. Binding to Value caused the other controls
to go blank after the exception. Of course, it is a different exception
when binding to Text. It occurs when there is a call to Double.Parse() on a
blank string.

I am going to do some testing with AddNew() when I get a chance. I do not
understand the reason for it hanging the application, but at this point it
is for my own knowledge.

So, now things are very solid. I have been trying to break the app, but I
cannot. Your suggestion of moving the code from the Leave event to the
Validated event may have helped (I had incorrectly assumed that Leave was
the last to fire).

Thank you for looking into this. It was a great help.

Alfredo



"Ying-Shen Yu[MSFT]" said:
Hi Alfredo,

In my opinion, the binding to NumericUpDown.Value property is correct, the
exception is also an expected behavior, when the Value property is set, the
new value is validated to be between the Minimum and Maximum values.

The problem is why the NumericUpDown.Value property was initialized to a
value not in the range.

This issue may occur if you didn't set default value to data column when
defining the dataset, and you need use AddNew method to add a row to update
the bounded controls default values, the bounded controls will not be
updated if the bounded data source is emptry.

Since you said in previous reply, the program hung if you called AddNew on
corresponding BindingContext( It might be caused by some other issues, we
can discuss it later). You may try adding a button and try the test code
below:
<code>
private void button1_Click(object sender, System.EventArgs e)
{
//define data table
DataTable table1= new DataTable("Table1");
DataColumn column1 = new DataColumn("ID",typeof(int));

//Set Default Value for this Column
column1.DefaultValue = 10;//change it to 3 will throw ArgumentException
table1.Columns.Add ( column1 );

//create a NumericUpDown control
NumericUpDown numUpDn = new NumericUpDown();
numUpDn.Location = new Point(30,10);
numUpDn.Minimum = 5;
this.Controls.Add(numUpDn);

//Set DataBinding
numUpDn.DataBindings.Add("Value",table1, "ID");

//Call BindingManagerBase.AddNew
BindingContext[ table1 ].AddNew();
}
</code>
This code snippet shows how to define a DataColumn with default value and
add a new row with the presetted default value, the AddNew method also
moves the Current position to the new row.

You may try to apply this approach to your data set definition, it seems
besides these text boxes, you have some other controls bound to this data
table. I suggest you removing all databindings to this data table, then add
them one by one, so that we can see which control causes an exception or
program hang. If you meet an exception please paste the call stack in your
reply.

Thanks!

Best regards,

Ying-Shen Yu [MSFT]
Microsoft Community Support
Get Secure! - www.microsoft.com/security

This posting is provided "AS IS" with no warranties and confers no rights.
This mail should not be replied directly, please remove the word "online"
before sending mail.
 

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