• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 617
  • Last Modified:

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

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
chrisbray
Asked:
chrisbray
  • 12
  • 7
  • 4
  • +1
1 Solution
 
60MXGCommented:
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
 
RyanAndresCommented:
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
 
chrisbrayAuthor Commented:
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
Concerto's Cloud Advisory Services

Want to avoid the missteps to gaining all the benefits of the cloud? Learn more about the different assessment options from our Cloud Advisory team.

 
mac-willCommented:
You could make quick format/parse methods to see what is happening?
But as RyanAndres said it looks right.
0
 
mac-willCommented:
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
 
RyanAndresCommented:
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
 
chrisbrayAuthor Commented:
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
 
chrisbrayAuthor Commented:
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
 
RyanAndresCommented:
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
 
RyanAndresCommented:
Chris, thanks for clearing that up... I assumed you were reading the value in code.
0
 
mac-willCommented:
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
 
chrisbrayAuthor Commented:
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
 
mac-willCommented:
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
 
chrisbrayAuthor Commented:
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
 
mac-willCommented:
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
 
chrisbrayAuthor Commented:
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
 
mac-willCommented:
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
 
mac-willCommented:
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
 
chrisbrayAuthor Commented:
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
 
chrisbrayAuthor Commented:
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
 
chrisbrayAuthor Commented:
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
 
chrisbrayAuthor Commented:
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
 
chrisbrayAuthor Commented:
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
 
chrisbrayAuthor Commented:
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

Free Tool: Site Down Detector

Helpful to verify reports of your own downtime, or to double check a downed website you are trying to access.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

  • 12
  • 7
  • 4
  • +1
Tackle projects and never again get stuck behind a technical roadblock.
Join Now