One-way and Two-way DataBindings

In .Net, there are two types of data bindings, one is called one-way data binding and the other is called two-way data binding. One-way data binding means that after you bind a data source to a control, any change made on the control will be reflected to the underlying data source. But if you change the underlying data source (via other means than through the control), the control will not capture the change and reflect it in UI. Two-way data binding complements this limit. In a two-way binding, any change on the control is automatically reflected on the underlying data source and any change on the underlying data source is automatically reflected on the control.

To impliment a one-way binding is very easy:

List<DemoClass> instances_ = new List<DemoClass>();
BindingSource bs_ = new BindingSource();
bs_.DataSource = instances_;
dgv.DataSource = bs_;

Above four lines create a one-way data binding. dgv is the DataGridView. Here we rely on its own mechanism to populate columns and fill the grid with the underly data source instances_.

The problem is, when you try to add a new instance of DemoClass to instances_, the change is not reflected on the grid. If you change a property value of an existing instance, the change is not reflected on the grid as well. Two works need to be done for these.

Firstly, DemoClass has to impliment INotifyPropertyChanged interface. Implimenting this interface will add a public delegate to the DemoClass. Don’t worry about the delegate, data binding ensures the delegate will be assigned by other classes necessary. The key is to call this delegate on every setter method of every published property:

public event PropertyChangedEventHandler PropertyChanged;

private void NotifyPropertyChanged(string propertyName){
if(PropertyChanged != null) {
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}

Here, I create a private method calling the delegate so we save some redundant code. What I now need to do is to ensure every setting calls the private method, passing the property’s name to it:

private string property_;

public string Property{
set{
property_ = value;
NotifyPropertyChanged(“Property”);
}
}

OK. Now, if we programatically change the Property value of an instance in instances_ list, the change will be immediately reflected to the grid.

How about adding and removing items from instances_? Unfortunately, we cannot let our List<DemoClass> to impliment INotifyPropertyChanged interface. A good news is, there is another class for this purpos, that is, BindingList<T>. BindingList<T> can be used exactly the same as List<T>. The difference is that BindingList<T> supports two-way binding. If we simply change the type of instances_ from List<DemoClass> to BindingList<DemoClass>, the adding and removing DemoClass changes will immediately reflect to the UI. And until now, we implement a two-way binding.

Until next time, happy coding!

How to avoid multiple clicks on a DataGridViewComboBoxCell?

If you have used DataGridViewComboBoxColumn on a DataGridView, you must have the experience of clicking a DataGridViewComboBoxCell multiple times before the dropdown list shows itself. This can be annoying. One quick fix is to set the EditStyle of the DataGridView to EditOnEnter. This has a small bug which only happens when the row selection mode is allowed. Be specific, when you set the EditStyle to EditOnEnter and you select a whole row by selecting the row header, the row is selected and one cell will be in edit mode, which is not the desired behavior. There is a workaround: http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=98504.

Until next time, happen coding!

How to enable column sorting on DataGridView?

In many cases, you will want to enable column sorting on your DataGridView. The most straightforward way of doing this is to allow users to click on the column headers of the DataGridView to sort the data source according to ascending or descending order of the specific columns. There will be a glyph indicating the sorting order on the columns of the DataGridView. In another case, you may want to sort the data source with two buttons, or other controls. One example for this case, is that the column header click event is already used by other purposes, such as whole column selection. The first case can be treated as the “standard” sorting manner of DataGridView and the second case can be treated as the “customized” or “programmatic” manner. In this article, I will show you how to enable these sorting manners on your DataGridView, with your business objects.

The first work has to be done on DataGridView itself. For each column in the DataGridView, there is a property called SortMode. It accepts an enumerable value, DataGridViewColumnSortMode. This enum has three values, Automatic, Unsortable, and Programmatic. If a column’s SortMode is set to Automatic, its behavior is similar to the first case, i.e. clicking the column headers triggers the sorting of the data source according to the column values. If a column’s SortMode is set to Unsortable, the only way to trigger sorting is programmatically. But this value indicates that the DataGridView is not supposed to be sorted, so there will be no spare space for the sorting glyph on the column headers. If a column’s SortMode is set to Programmatic, it means that sorting will only be triggered via code. Clicking column headers (if not handled by code) will nto trigger the sorting.

In most of the cases that desire column sorting, you should either use Automatic or Programmatic. Since the SortMode is for columns, you have to set the property for each column in your DataGridView. Make sure this property setting code is in the right place. For example, if columns are automatically generated according to the underlying bound data, the setting code should be put after the data binding of the DataGridView, otherwise, you will find that your setting doesn’t work at all.

It is not the end of the story after the columns’ SortMode has been set. You will find that sometimes, even if you set the SortMode of the columns, you still cannot sort the data bound to the DataGridView. This is because the underlying binding source may not support sorting. If your underlying binding source is a DataTable or a DataSet, it is fine. Most of the database related containers, provided in ADO.net support sorting. But this is not the case for the most frequently used binding source that holds customized objects, BindingList
. BindingList itself always doesn’t know how to sort the items it contains. It is also the case of List, the commonly used container.

If you want to allow BindingList to support sorting, you have to inherit from it to create your own sortable BindingList. Fortunately, it is not very difficult. The above is a standard sortable BindingList.