Saturday, December 11, 2004

 

Sorting a data-bound ComboBox

Recently I encountered a challenging situation in Windows Forms where I needed to sort the contents of a ComboBox involved in the middle of multiple levels of Data Binding. The combobox was on a window that provided a list of items on the top of the window, and details beneath. In the details section is a tab that provides an "Audit History" of changes to the items. Rather than displaying the entire audit history on the page, a combobox allows the user to select which change to view the audit for. Of course, it made sense that the combobox should be sorted in reverse chronological order, with the most recent changes at the top of the list, and the most recent change selected.

Sorting the combobox proved a real challenge. All of the information is managed by a dataset with datatables/datarelations joining the data elements together. I couldn't bind it to a DataView, because it had to participate as a child of the list as well as the parent of the audit details. But without a DataView, how could I sort the contents of the combobox?

First of all, I attempted to set the ComboBox.Sorted property, thinking it would handle the sorting automatically. To my chagrin, an error was promptly raised, stating that the property could not be used if the combobox was data bound. Argh! I suppose this wouldn't have done the trick anyways, since I wanted the contents sorted in reverse.

OK, what about the DataTable.DefaultView property? Surely I could set the DefaultView on the audit datatable to sort appropriately, and the sort would apply wherever that table was data bound, right? Not so! Setting properties of the DefaultView didn't help the sort at all.

Upon further research, I found that new DataViews were being created every time the current list row changed, to manage the data bindings of the child tables. In my Audit record situation, this meant that each time the user selected a new value in the list, a DataView was created in the background for the audit records, containing DataViewRows representing the audit records specifically for the selected item in the list.

By programmatically setting the Sort property of the generated DataView, its rows are automatically sorted. This rearranging of the rows plays nice with the data binding and currency management of the all of the child data tables under the Audit table. As well, the first record in the sorted list is automatically the current record for the table. This met my goal of automatically selecting the most recent audit record in the combobox.

The trick to using this, however, was to insert some code that would fire each time the Audit DataView was generated, to set the Sort property on it. Here is the code that I used. Note that Payment is the DataTable for the list, and PaymentAudit is the child table. PaymentAudit records need to be appear reverse sorted in the combobox.

In the form Load event, I bound up the CurrentChanged and PositionChanged events, as follows:

this.BindingContext[this.paymentListData, "Payment"].CurrentChanged +=new EventHandler(PaymentListTabs_PaymentChanged);

this.BindingContext[this.paymentListData, "Payment"].PositionChanged +=new EventHandler(PaymentListTabs_PaymentChanged);

And then, in the event handler for these events, I got a hold of the generated DataView and set the Sort property on it:

// Event handler that will run with the Payment Position or Currentitem changes
private void PaymentListTabs_PaymentChanged(object sender, EventArgs e)
{
// Sort the Payment Audit records if there are any
if (this.BindingContext[this.paymentListData,"Payment.PaymentPaymentAudit"].Count > 0)
((DataRowView)this.BindingContext[this.paymentListData,"Payment.PaymentPaymentAudit"].Current).DataView.Sort = "PaymentAuditId DESC";
}


This way, all of my controls could be bound up using standard .Net data binding, including the ComboBox. The audit list in the ComboBox is sorted in reverse chronilogical order, and properly re-evaluates whenever the list position is changed, data changes, or new data is merged into the dataset.

Happy coding!

Josh

Comments: Post a Comment

<< Home

This page is powered by Blogger. Isn't yours?