Friday, June 1, 2007

How to get from a DataGridViewCheckBoxCell the CheckBoxValue?

Often you only need to bind a list and the user need to check what it desire. To do it, simply bind your list to a grid and add an unbound colum with the type of DataGridViewCheckBoxColumn.

The example below contain grid of CheckBoxColumn and an TextBoxColumn that contain an ID.

List lstIdModuleToAdd = new List();
DataGridViewRow row;
DataGridViewCheckBoxCell cell;
for (int i = 0; i < this.chkModuleList.Rows.Count;i++ )//Loop all grid rows
{
row = this.chkModuleList.Rows[i];
cell = row.Cells["chkAddThisModule"] as DataGridViewCheckBoxCell;
if ((null != cell && null != cell.Value && true == (bool)cell.Value))//If checkbox == true
{
lstIdModuleToAdd.Add(Convert.ToInt32(row.Cells["Id"].Value));
}
}

Monday, May 7, 2007

Datagridview resize column

A new thing with the DataGridView of the Framework 2.0 is the way to automaticly size the width of the column. Most of the common way to size the grid are already done for you.

All the magic with the DataGridView column resize is in the DataGridView property called AutoSizeMode. By default, the value is NotSet, thence you do not see any thing resized. If you want to manually set the width, use None. One of the coolest resize is ColumnHeader that let you resize the column depending of the length of the text in the column header. Have fun with all others values possibles.

Sunday, May 6, 2007

Binding Parse event

The binding object has a Parse event that is raised when a new value is added to the component to go to the object. It's a middle-tier between the component and the class object.

One useful thing is it can parse an ID and save it's Name.

To test, create textbox and add a binding object to this textbox. Add a parse event to the binding object and in the event add the code below.


void b_Parse(object sender, ConvertEventArgs e)
{
int i = -1;
int.TryParse(e.Value.ToString(), out i);
int id;
string name="";
if(i>=0)
{
foreach(object o in bs.List)
{
id = (o as Product).Id;
if(i==id)
{
name = (o as Product).Name;
e.Value = name;
break;
}
}
}
}

The important part is the LOOP that through all bindingsource and if find the ID in the list will change the display data to an other data.

3 layers with Databinding

Normally, at the first look data binding is 2 layers process. First is the source and second is the display. In real, it's more like 3 layers.

The first one is the source of the data. It can be a DataSet or a custom object. The second one is the data binding display and third one is the component display.

Let me explain. If you want to display only the first 4 characters of a string to the screen but let the user write all what he wants (and of course only append data if necessery). You need to use what we have seen before : Format. The Format method of the Binding object let change the display information to the screen without changing the real data of the object. The code below is an exemple that truncate the string if it's more than 4 characters.

void b_Format(object sender, ConvertEventArgs e)
{
if (e.Value.ToString().Length > 5)
{
e.Value = e.Value.ToString().Substring(0, 4) + "...";
}
}

You can see that the value from the ConvertEventArgs contain the value from the object. If the length of the string is over 5 than we substring and all three dots. If you try, you will see that everything is fine until you set the focus on the control because when the get the focus, you still only have the 4 first characters and the three dots. In fact, we want to full string that contain the object below the data source object. To get that work, it needs some transformation. The transformation is needed when the focus is on the control. If you have for example a Text Box than you need to add an event on the Enter event. The code below show a brief example.

void textBox1_Enter(object sender, EventArgs e)
{
(sender as TextBox).Text = ((Product)bs.Current).Name;
}

As you can see, we convert the first parameter to get the Text property. We could have simply use the name of the control but it's much more elegant and ensure that future name change won't interfere with this event. This event set the name of the product but which one is the current one? The answer is with the BindingSource.Current. The binding source for this example was a list of Product. To know the current product, the binding source has a Current method. Once casted, you can have all public method of the object and than have the original full name.

The code below is a complet example. You need to add 1 textbox and 2 buttons.


BindingSource bs = new BindingSource();
public Form2()
{
InitializeComponent();
}
private void Form2_Load(object sender, EventArgs e)
{
List listProduct1 = new List();
listProduct1.Add(new Product(100, "Pantalon"));
listProduct1.Add(new Product(101, "Chemise"));
listProduct1.Add(new Product(102, "Casquette"));
bs.DataSource = listProduct1;
Binding b = new Binding("Text",bs,"Name");
b.Parse += new ConvertEventHandler(b_Parse);
b.Format += new ConvertEventHandler(b_Format);
textBox1.DataBindings.Add(b);
textBox1.Enter += new EventHandler(textBox1_Enter);
}
void textBox1_Enter(object sender, EventArgs e)
{
(sender as TextBox).Text = ((Product)bs.Current).Name;
}
void b_Format(object sender, ConvertEventArgs e)
{
if (e.Value.ToString().Length > 5)
{
e.Value = e.Value.ToString().Substring(0, 4) + "...";
}
}
private void button2_Click(object sender, EventArgs e)
{
if (bs.Position < (bs.Count-1))
bs.MoveNext();
else
{
bs.MoveFirst();
}
}

BindingContext

The BindingContext has the role to synchronize between component and data source for a context. Since the framework 2.0, the BindingContext do a lots of job and require less to play with it. An important thing is to always remember that every container has its binding context. Remember that point if you do dialog form modal.

The BindingContext contain the CurrencyManager and the PropertyManager.

Saturday, May 5, 2007

Binding object event

When you bind a property to a field, they are two actions. First, object to gui (graphical user interface). Second, gui to object.



If you want to have control on both you need to subscribe to events.



The first event called Format do the first one, take the object information and format it to the gui. So let stay you have a property that has a ASCII character as INT. With the parser you can show to the screen the ASCII character as Char.



On the other side, the event called Parse take what the user input to the gui. When the gui send back the information to the object property's, it pass to the Parse event. You just need to convert back to INT in the Parse event and you are fine. The Parse event is raised after the control has changed focus, therefore after the Validating event and Validated event of the control.



Here is few important about the properties of the ConverEventArgs parameter of theses two events (Format and Parse both have Object sender and ConvertEventArgs as arguments) . The ConvertEventArgs has Value. This is the object value of what to display (or what to get back to the object depending your side of view). You have DesiredType that is the type of the Object, in our example above, it would be typeof(int).



The screenshot below is from Microsoft help about Parse and Value. It shows a simple example.

(Click to enlarge)

What if an error occur from a bad input of a user? Well, of course this should be threat and of course the value need not to crash the application. Hence, the framework is clever for this type of circumstance. If an exception is thrown from a binding event handler, the binding terminates the binding process for that control and force the control to refresh by refreshing the Format event (if the exception is from the Parse event). I say the framework is clever because you can raise yourself an error if you know that the value isn't in a good format or if the type is not good and cannot be converted than it will do it automatically without any help from you.

Thursday, April 26, 2007

Tutorial about Binding with ComboBox



Let say that you have a list of Person that you would like to display into a combobox. To fill a combo box with C#2.0 is pretty simple. First of all, you required a List of strong typed object, for our example a list of Person. Second, you need to bind the list to the component. Finally, you require to tell what's to display and what to hold for value.




Code:
List lstPerson = new List();
lstPerson.Add(new Person("Mary"));
lstPerson.Add(new Person("Sam"));
lstPerson.Add(new Person("Joe"));
this.cboPersons.DataSource = lstPerson;
this.cboPersons.DisplayMember = "Name";
this.cboPersons.ValueMember = "Name";




The final result is simply a combobox with all the three names.