Datepicker and DbNull.Value

Posts   
 
    
Sokon1
User
Posts: 97
Joined: 17-Jul-2006
# Posted on: 29-Aug-2006 12:57:03   

Hi! I'm using v2 and self servicing scenario.

I want to bind an entity to a Datepicker-Control. Values can be a DateTime or DbNull.Value.

I created a user control with a datepicker on it an added a Property "Value". If the value from the DB is NULL, an empty picker is shown:

        
public Object Value {
get {
  m_Value = DatePicker.Value;
  return m_Value;
}
set {
  DatePicker.Format = DateTimePickerFormat.Custom;
  if (Convert.IsDBNull(value)) {
    m_Value = DBNull.Value;
    DatePicker.CustomFormat = "'";
    Checked = false;
  }
  else {
    m_Value = value;
    DatePicker.CustomFormat = "dd.MM.yyyy";
    DatePicker.Value = Convert.ToDateTime(value);
    Checked = true;
  }
}
}

Fine. Now I wanted to bind an entity field to this control, like this:


public void BindValue(object DataSource, string DataMember) {
  if (this.DataBindings.Count != 0) {
    this.DataBindings.Clear();
  }
  Binding myBind = new Binding("Value", DataSource, DataMember);
  this.DataBindings.Add(myBind);
}

In run time, i can select a new Date, but this is not shown. Why? I found out, that the entity field's getter is called. Since the entity is not updated yet, the selected value is overwritten with NULL.

Any ideas? Thanks in advance!

Jessynoo avatar
Jessynoo
Support Team
Posts: 296
Joined: 19-Aug-2004
# Posted on: 29-Aug-2006 17:46:42   

Hi,

I think it has to do with your GUI logic in the first place. Your Setter probably gets called at the wrong timing, but we would need more code to tell you. When do you place the bindings?

Can you just place break points at the beginning of your getter and setter and other event related methods and give us the timing of the calls?

Sokon1
User
Posts: 97
Joined: 17-Jul-2006
# Posted on: 30-Aug-2006 09:11:01   

Hi, thanks for messing around with this! Ok, my GUI logic is indeed a little bit more complex than usual. But not the bindings. There is no more code, which is called except the entity's code you all know, I think. But let's see: - I set the databinding in the load event of my form. (code in my last post)

RunTime: - When I change the value of the DateTimePicker in run time, datepicker_valueChanged-event is thrown. This was just a test; I don't do anything in this event handler. - After having changed the value, the userControl.Datepicker.Value and the userControl.Value have the correct value. the userControl.Value property is listed in my las post, too. - Now here comes the point: I move the focus away from then control to another. I don't know why but this is what happens:

  • First the userControl.Value.get is called.
  • After that the Entity's get-event is called. Because the entity doesn't know about the changed date, the old value is restored.
  • userControl.Value.set is called.
  • the entity's field 'set' is never called.
  • The control shows the former value.

There are some things i don't understand: - Why is the userControl.Value.get called first when i move the focus? - Why is the the entity's getter never called? The binding should take care of that, doesn't it?

I even tried something like "DataBindings[0].WriteValue();" in the value_changed event of the datepicker, but the entity's field is not set.

Sokon1
User
Posts: 97
Joined: 17-Jul-2006
# Posted on: 30-Aug-2006 14:24:16   

When I bind textboxes with the following code (bsTarif is a BindingSource object), there is the same problem. No value enters the entity Instead, the entity's set property is called and overwrites my entry.


(In form_load)
checkBox1.DataBindings.Add(new Binding("Checked", bsTarif, "Bool1"));
checkBox2.DataBindings.Add(new Binding("Checked", bsTarif, "Bool2"));

Sokon1
User
Posts: 97
Joined: 17-Jul-2006
# Posted on: 31-Aug-2006 16:38:41   

Seems its not the binding, its a inheritance/polymorphism problem.

Following situation: - I've got a Collection , say "GarageList". - In every garage there can be n "Cars" (1:n relationship).
- There are several sub types of "Car", say "BMW", "Toyota" and "Ford". - In every garage there can only be one type of car.

First I want to select a garage out of a list (in this case a datagrid). -> works After having selected a BMW garage, a list of BMWs is loaded. -> works I show the details of the BMW in bound textboxes, checkboxes etc. -> works I want to change the super type's details (Car's details) -> works I want to change the BMW's details -> data is not transferred from control to entity

I can change the entity data of the "Car" super entity, but NOT the entity data special for the BMW. In this case, the control's data jumps back to the former value after leaving it, because the getter of the entity is called.

This is my code (simplyfied):


garageColl= new GarageCollection();
garageColl.GetMulti(null);

BindingSource bsGarages = new BindingSource();
bsGarages.DataSource = garageColl;
gridGarages.DataSource = bsGarages ;

BindingSource bsCars = new BindingSource();
bsCars.DataSource = bsGarages ;
bsCars.DataMember = "BMW"

TextBox1.DataBindings.Add(new Binding("Text", bsCars, "CarProp"));
TextBox2.DataBindings.Add(new Binding("Text", bsCars, "BmwProp"));

Textbox2 is readonly, Textbox1 is read- and writable.

The LLBLGen Designer created a 1:n relationship between garages and cars by its own, but i had to add custom relations (1:n) from garage to BMW to realize this scenario. Perhaps that's the problem?

Or did i miss something in the help document?

Thanks in advance again! smile

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39898
Joined: 17-Aug-2003
# Posted on: 01-Sep-2006 15:48:29   

If you have a collection of 'CarEntity', and you store a BmwEntity in there (which is allowed), databinding will offer you only the properties of CarEntity, not BmwEntity. This is because the collection of CarEntity, can contain also entities which are of type CarEntity, and thus don't have properties which are native to type BmwEntity. As controls grab the properties of what could be inside a collection only ONCE, the fields of the type of the entity the collection is for is returned.

This also means that if you have a collection of BmwEntity entities, it will work, as the type of entity in the collection is BmwEntity.

Does that answer your question, could that be what is the cause here?

Frans Bouma | Lead developer LLBLGen Pro
Sokon1
User
Posts: 97
Joined: 17-Jul-2006
# Posted on: 04-Sep-2006 10:25:09   

This is what I suspected, too. This answers a part the question, yes. I changed the code already, so there are BmwEntities bound to the controls, and some of the controls are showing the right values, but not all. Some are still jumping back to their old values.

I found out, that binding to checkBoxes only works, if you set the "AllowNullable"- attribute in the database to false. Is that true? Even if I set "Generate as Nullable type .NET2.0" in the designer to false, the data seems to be handled differently inside an entity. Using the collection debug visualizer, you can see that fields mapped on non-nullable bit fields are represented by a checkbox, fields not set to "nullable" are represented by text (true/false). Of course, this is because there could be a NULL, too, which can't be shown by a checkbox. But if I set the "Generate as Nullable type .NET2.0" to false, there can't be null, so i expected to be able to bind those values directly without changing the database.

Ok, after having solved the checkbox problem I'm now fighting against comboboxes :-) But I'll try on my own first, before asking stupid questions wink I have only one: Values are jumping back, when the internal validation fails, right? Is this the only possible reason for the jumping back?

Sokon1
User
Posts: 97
Joined: 17-Jul-2006
# Posted on: 04-Sep-2006 16:24:26   

Ha! I found it. sunglasses

I don't know why the getter is called too early in my scenario, but i know how to avoid it. Perhaps the reason for the values jumping back is that my Datepickers, Listboxes etc. are all parts of user controls, but i don't know. If someone else has the similar problem try this:

(For a Datepicker: )


DataBindings.Add(new Binding("Value", DataSource, DataMember, true, DataSourceUpdateMode.OnValidation, "01.01.1900");

"DataSourceUpdateMode.OnValidation" does the trick and works with all my controls.

Sorry for the confusing start of this thread, I hope this helps someone else.