Solved

Why does a databound check box generate a null value and how can I stop it?

Posted on 2009-05-06
24
603 Views
Last Modified: 2012-05-06
I have a databound check box which works perfectly unless you uncheck the box at runtime.  If you do that, the value in the underlying table is set to null even though the check box checked value can only be true or false?

The checkbox is bound like this:

            addressControl.statementCheckBox.DataBindings.Add("Checked", addressesBindingSource, "Statement", true, DataSourceUpdateMode.OnPropertyChanged, false);

"Statement" is a boolean column in the table connected via the addresses bindingsource.

Chris Bray
0
Comment
Question by:chrisbray
  • 12
  • 7
  • 4
  • +1
24 Comments
 
LVL 7

Expert Comment

by:60MXG
ID: 24318704
Can you disable the checkbox while it run?  Or Set check box value = 1 instead of "checked" and set uncheck box value = 0.  I think that will fix your problem.
0
 
LVL 8

Expert Comment

by:RyanAndres
ID: 24318815
Looks right to me.

Are you sure you're not reassigning the addressesBindingSource variable before/after the bindings occurr? This may cause a similar error.

Otherwise, please provide the exception detail.
0
 
LVL 3

Author Comment

by:chrisbray
ID: 24318984
Hi Guys,

Thanks for your input:

60MXG: The checkbox is databound to a boolean field... consequently I don't believe your suggestion is practical.

RyanAndres: Quite certain,  and just to double check I ran a full search of the code and it is created and assigned only once.  There is no exception detail to report, it is simply that the underlying value in the table becomes NULL instead of false even though the checked value cannot be anything other then true or false and as you can see a default value of false has also been provided just in case...

Chris Bray
0
 
LVL 8

Expert Comment

by:mac-will
ID: 24319020
You could make quick format/parse methods to see what is happening?
But as RyanAndres said it looks right.
0
 
LVL 8

Expert Comment

by:mac-will
ID: 24319035
Stupid question I know, but is it maybe because you are never changing the property?
Since it is on the porpertychange event that it is binding?
0
 
LVL 8

Expert Comment

by:RyanAndres
ID: 24319110
What property are you getting the value from? It should be Checkbox.Checked, unless you are manipulating the value or reading the wrong peroperty.
0
 
LVL 3

Author Comment

by:chrisbray
ID: 24319121
Hi mac-will:

I am not sure I understand what  you are asking.  The value of the column is true, and a check is displayed indicating that the binding works when the value is read.  If you uncheck the bound box the property should change automatically because it is bound, and because the only possible values of checked are true or false it should never be null.

Interestingly, if I modify a value of false (again shown correctly by the check box) to true by putting a check in the box the table is updated correctly.  It is ONLY unchecking the value and leaving it unchecked that causes the problem.

Chris Bray
0
 
LVL 3

Author Comment

by:chrisbray
ID: 24319390
Hi RyanAndres:

Again, I am not sure I understand your question.  You can see from the code provided that the Checked property is hooked to the Statement boolean column...  There is no other code, and I am not doing anything else.  The problem is that the binding appears to fail ONLY when I go from checked (true) to unchecked (should be false, but goes to null in the table).  In all other scenarios (i.e. read, go from unchecked to checked) it works perfectly and the binding functions as anticipated.

Chris Bray
0
 
LVL 8

Expert Comment

by:RyanAndres
ID: 24319539
Raise the Format and Parse events and watch the values and expected datatype. This might bring more information to the table.

addressControl.statementCheckBox.DataBindings["Checked"].Format
addressControl.statementCheckBox.DataBindings["Checked"].Parse
0
 
LVL 8

Expert Comment

by:RyanAndres
ID: 24319557
Chris, thanks for clearing that up... I assumed you were reading the value in code.
0
 
LVL 8

Expert Comment

by:mac-will
ID: 24319591
I thought maybe the field was NULL to begin with and the property was never changed - just an off chance thought.

What about my first suggestion, ie, making the parse/format methods?
This would at least tell you what is happening?

Here is the code to get you started:
Binding mBind = new Binding("Checked", addressesBindingSource, "Statement", true, DataSourceUpdateMode.OnPropertyChanged, false);
 

mBind.Format += new ConvertEventHandler(mBind_Format);

mBind.Parse += new ConvertEventHandler(mBind_Parse);
 

addressControl.statementCheckBox.DataBindings.Add(mBind);

Open in new window

0
 
LVL 3

Author Comment

by:chrisbray
ID: 24320053
Hi Guys,

Here is the output from the new binding events routed to Console:

Format: Desired Type: System.Boolean Value: True
Parse: Desired Type: System.Boolean Value: False

This indicates that the value from the check box is correct,  so what next?

Chris Bray
0
IT, Stop Being Called Into Every Meeting

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

 
LVL 8

Expert Comment

by:mac-will
ID: 24327658
in the parse method what is the value of e.Value when you uncheck the box?

BTW. can you give the database details and table def
private void mBind_Parse(object sender, ConvertEventArgs e)

        {

            try

            {                

                //e.Value = ???           

            }

            catch (Exception ex)

            {

            }

        }

Open in new window

0
 
LVL 3

Author Comment

by:chrisbray
ID: 24328180
Hi mac-will:

Umm... again I don't understand your question - you already have the answer!  The values reported in my last response were e.DesiredType and e.Value respectively, output to Console as I described.

The database in this case is a simple VistaDB file.  The structure is as follows:

                TABLE [Addresses]
               
                [AddressId] BIGINT NOT NULL IDENTITY (1, 1),
                [LinkId] BIGINT,
                [LinkTypeId] BIGINT,
                [AddressName] VARCHAR (50) CODE PAGE 1252 NOT NULL DEFAULT '''''',
                [Addressee] VARCHAR (50) CODE PAGE 1252 NOT NULL,
                [Address1] VARCHAR (50) CODE PAGE 1252 NOT NULL,
                [Address2] VARCHAR (50) CODE PAGE 1252 NOT NULL,
                [Address3] VARCHAR (50) CODE PAGE 1252 NOT NULL,
                [Address4] VARCHAR (50) CODE PAGE 1252 NOT NULL,
                [Postcode] VARCHAR (10) CODE PAGE 1252 NOT NULL,
                [CountryID] BIGINT,
                [Telephone] VARCHAR (20) CODE PAGE 1252,
                [Fax] VARCHAR (20) CODE PAGE 1252,
                [Email] VARCHAR (100) CODE PAGE 1252,
                [Billing] BIT NOT NULL DEFAULT 'true',
                [Delivery] BIT NOT NULL DEFAULT 'false',
                [Statement] BIT NOT NULL DEFAULT 'false',
                [Inactive] BIT NOT NULL DEFAULT 'false',
                [EnteredBy] VARCHAR (50) CODE PAGE 1252,
                [EnteredOn] DATETIME NOT NULL DEFAULT 'GetDate()',
                [LastModifiedBy] VARCHAR (50) CODE PAGE 1252,
                [LastModifiedOn] DATETIME

Chris Bray

0
 
LVL 8

Expert Comment

by:mac-will
ID: 24338809
Sorry I read that quickly. You did give what I was asking for.

Do you know if you can bind a boolean directly to a BIT field in this type of file?

What if in the Parse/Format you set e.Value to 0 or 1 (as maybe bytes)?

Something like:
private void mBind_Parse(object sender, ConvertEventArgs e)

        {
 

            try

            {                

               Boolean locVal = e.Value as Boolean;
 

                if (locVal == null)

                {

                    e.Value = null;

                    throw new Exception("Not a valid ...");

                }

else

{

   e.Value = locVal ? ((object)(byte)1):((object)(byte)0);

}

  

            }

            catch (Exception ex)

            {

            }

        }

Open in new window

0
 
LVL 3

Author Comment

by:chrisbray
ID: 24339384
Hi mac-will:

Thank you for your continued efforts to help.

In all my experiments trying to resolve this e.value is consistently correct.  I suspect this whole thing is yet another piece of MS crap coding, and that it relates to one of their controls - but I cannot be certain so I am seeking guidance.

The exact same binding works in other scenarios, i.e. on a straight form it works perfectly.  I am thinking that the problem may be down to the fact that there is a) a user control involved or b) that there is a tab control involved.  In order to attempt to eliminate the user control a added a check box outside the user control but it showed the same problems.  On the other hand, check boxes bound to a different table work perfectly even despite the tab control so I am hugely confused!

I have another issue with a DatePicker control that works perfectly in other scenarios but not on this same form with the tab control.  In that case writing to the table works perfectly but the sync with the control fails constantly displaying the current date and failing to change when the underlying record changes...

Chris Bray
0
 
LVL 8

Expert Comment

by:mac-will
ID: 24339632
Yes, it may be some nested control problem or perhaps a problem with the database.

As a test I tried binding a checkbox with a boolean field on an SQLEXPRESS database with no problems.

(I also think I have done it in the past with DB2)
0
 
LVL 8

Expert Comment

by:mac-will
ID: 24339669
As a test in the parse event try:

e.Value = e.Value;

I seem to remember doing this when I had a databinding issue with a custom control.
0
 
LVL 3

Author Comment

by:chrisbray
ID: 24342754
Hi mac-will:

It is definitely not database related, as I have exactly the same code working perfectly for fields in the same table elsewhere even in the same form... and I can create a simple form to access the same data and that works correctly.

That   brings it down to a stupidity in my code or a problem with the controls.  Since I have written no code whatsoever other than that presented I agree it is probably a nested control problem.  

I will try your suggestion, although I am not sure how that could make a difference -0 I wil report back.

Thanks again for sticking with this and trying to help, it is much appreciated.

Chris Bray

0
 
LVL 3

Author Comment

by:chrisbray
ID: 24397693
Hi mac-will:

Just to confirm that assigning the variable to itself makes no difference whatsoever.  Don't know if you have any other ideas?

Chris Bray
0
 
LVL 3

Accepted Solution

by:
chrisbray earned 0 total points
ID: 24401466
Hi Everyone,

After many days of writing test code and digging deep into the internals of .Net I have found the answer - MicroShaft's crap coding!  The answer to the problem is that in .Net 2 at least that particular overload of DataBindings.Add is terminally broken and just does not work, at least in conjunction with adapters.  I have not tested every type of data connection because I just cannot afford the time given the weeks it has taken to get to the bottom of this problem and the many issues it has given our software and its users, but having found the problem I have now been able to find other postings on the web where programmers have experienced the same issue.

We have proven at least to our own satisfaction that the problem is at .Net level by using the same overload on types of control other than CheckBox and in other forms and applications, and the problem can be reliably reproduced.

The workaround is not to use that particular overload,  and based on the original example piece of code change:

 addressControl.statementCheckBox.DataBindings.Add("Checked", addressesBindingSource, "Statement", true, DataSourceUpdateMode.OnPropertyChanged, false);

to

 addressControl.statementCheckBox.DataBindings.Add("Checked", addressesBindingSource, "Statement");

After that the control, database, and application work in harmony with each other.

Chris Bray

0
 
LVL 3

Author Comment

by:chrisbray
ID: 24402880
Hi Everyone,

One other bit of information that may prove useful has arisen out of this exercise... it is not all types of binding that are broken, just most of them.  The following calls appear to work as advertised:

Image fields

            // Image can be null, as we replace the null with a new bitmap 1 pixel in size
            idImagePhotoBox.DataBindings.Add("Image", adapter.Table, "IdImage", true, DataSourceUpdateMode.OnPropertyChanged, new Bitmap(1,1));

Comboboxes binding to an ID:

            countryCombo.DataBindings.Add("CountryId", addressesBindingSource, "CountryId", true, DataSourceUpdateMode.OnPropertyChanged, -1);

Having discovered that the faults were demonstrably down to MS, my first instinct was to remove all instances of that overload and replace that with code setting the default values in the adapter if we are dealing with a new record.  However, in the case of the Image column the conversion backwards and forwards between Byte array and image was quite difficult and in the end I put the binding back which does it automatically.

I hope that this helps someone struggling with this issue.

Chris Bray

0
 
LVL 3

Author Comment

by:chrisbray
ID: 24403448
Hi Everyone,

Whilst my solution does resolve the problem described, and produces another one.  When using the shorter overload the binding sometimes fails to update the underlying table in the adapter.

I am going to look at other overloads in case I can do anything different, but it looks increasingly as though I am going to have to trap the save within the adapter, loop through the adapter table, and set default values for any column found to be null!  At the moment I can see no other solution, unless you have any suggestions...

Chris Bray
0
 
LVL 3

Author Comment

by:chrisbray
ID: 24404021
Hi Guys,

Latest update on my progress;  I now appear to have the whole thing working.  The solution seems to be as follows:
  1. Do not use the longer overload unless you need to do so, most commonly this will only be if the underlying field CANNOT have a null value e.g. is set NOT NULL.
  2. If you do need to do so, bear in mind that it may not work as you expect, particularly where you have nested components.
  3. It does not seem to work at all binding to properties e.g. to properties on a user control that reflect component values on the control.
There are some tips that will make some things work that otherwise do not.  The following seem to work:

Image fields

            // Image can be null, as we replace the null with a new bitmap 1 pixel in size
            idImagePhotoBox.DataBindings.Add("Image", adapter.Table, "IdImage", true, DataSourceUpdateMode.OnPropertyChanged, new Bitmap(1,1));

Comboboxes binding to an ID:

            countryCombo.DataBindings.Add("CountryId", addressesBindingSource, "CountryId", true, DataSourceUpdateMode.OnPropertyChanged, -1);

Checkboxes

DO NOT use false as the default value - for some reason this results in NULL in the table when you uncheck the box.  Instead use 0 - yes, I know it makes no sense, but it works!

inactiveCheckBox.DataBindings.Add("Checked", paymentMandatesBindingSource, "Inactive", true, DataSourceUpdateMode.OnPropertyChanged, 0);

Textboxes

DO NOT use string.Empty or "" as the default value - for some reason this results in NULL inthe table when you remove all text from the box.  Instead use a single space " " - not pretty and not necessarily nice to have it in your database, but it works!

mandateNameTextBox.DataBindings.Add("Text", paymentMandatesBindingSource, "MandateName", true, DataSourceUpdateMode.OnPropertyChanged, " ");

I sincerely hope that someone else benefits from this and does not have to go through what I have been through... it has taken weeks of trial and effort and what amounts to wasted coding to get to the bottom of this, and I still have to go through and fix previous changes in the rest of the application.  I hope I will not need to post back on this again, and good luck to anyone trying to do the same thing!

Chris Bray
0

Featured Post

IT, Stop Being Called Into Every Meeting

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

Join & Write a Comment

Article by: Ivo
C# And Nullable Types Since 2.0 C# has Nullable(T) Generic Structure. The idea behind is to allow value type objects to have null values just like reference types have. This concerns scenarios where not all data sources have values (like a databa…
This article describes a simple method to resize a control at runtime.  It includes ready-to-use source code and a complete sample demonstration application.  We'll also talk about C# Extension Methods. Introduction In one of my applications…
Polish reports in Access so they look terrific. Take yourself to another level. Equations, Back Color, Alternate Back Color. Write easy VBA Code. Tighten space to use less pages. Launch report from a menu, considering criteria only when it is filled…
This video explains how to create simple products associated to Magento configurable product and offers fast way of their generation with Store Manager for Magento tool.

746 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

11 Experts available now in Live!

Get 1:1 Help Now