Tuesday, December 21, 2004

 

Excellent article explaining C# structs

Just came across a great article by Senthil Kumar on structs. Well worth the read for anyone doing C# development. Several things were new to me:
- an instance of a struct can be created without specifying constructor parameters
- structs support interfaces, but not inheritance
- the CLR boxes structs as objects when accessed through an interface, which is a potential performance hit
- foreach and using statements implicitely set variables declared in them to readonly

Thursday, December 16, 2004

 

Tidbits from Microsoft Performance Guide

I just had a read through parts of the Microsoft "Improving .NET Performance and Scalability" guide (microsoft.com/perf), and learned some interesting new things:



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

 

Welcome!

Welcome to my Blog! In this blog, I will endeavor to document solutions to challenges that I encounter while programming in .Net, primarily C#.

I have found that there are many things that the Framework does a good job of, but lack adequate technical documentation. The blogs of fellow .Net developers have been invaluable in researching solutions to these problems. My goal with this blog is to document what I've learned (so that I don't forget it), and at the same time, hopefully assist other developers in finding answers faster.

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