Tag Archives: Windows Forms

Exploring formatting…

In the documentation you can read the following for CultureInfo:

The CultureInfo class holds culture-specific information, such as the associated language, sublanguage, country/region, calendar, and cultural conventions. This class also provides access to culture-specific instances of DateTimeFormatInfo, NumberFormatInfo, CompareInfo, and TextInfo. These objects contain the information required for culture-specific operations, such as casing, formatting dates and numbers, and comparing strings.

First i’ll initialize an instance of a customized CultureInfo and install it in the current thread:

CultureInfo appCultureInfo = new CultureInfo("en-US");
appCultureInfo.NumberFormat.NumberDecimalSeparator = ".";
appCultureInfo.NumberFormat.NumberGroupSeparator = " ";
appCultureInfo.NumberFormat.NumberDecimalDigits = 2;
appCultureInfo.NumberFormat.CurrencySymbol = "€";
Thread.CurrentThread.CurrentCulture = appCultureInfo;

Note: The culture in Thread.CurrentThread.CurrentUICulture is only used by the Resource Manager to lookup culture-specific resources at run-time. Since we’re not playing with resources, we don’t have to care about this one.

If you don’t provide the desired format specifier, you will get the generic format specifier “G” ( Standard Numeric, DateTime, Enumeration Format Strings) And now it’s time for a little demo:

public double SomeValue
{
 get { return 12345.6789; }
}

private void Form1_Load(object sender, EventArgs e)
{
 label1.Text = "default to generic format: " + SomeValue.ToString();
 label2.Text = "numeric format: " + SomeValue.ToString("N");
 label3.Text = String.Format("currency format: {0:C}", SomeValue);
 label4.DataBindings.Add("Text", this, "SomeValue", true, DataSourceUpdateMode.Never, string.Empty, "P");

 this.Column1.DefaultCellStyle.Format = "E1";
 this.Column1.DataPropertyName = "SomeValue";
 this.dataGridView1.AutoGenerateColumns = false;
 this.dataGridView1.DataSource = new Form1[] { this };
}



Another important interface for formatting is IFormattable which provides functionality to format the value of an object into a string representation. Put simply, it allows you to define your own format specifiers. Here is an example that allows the user to build his own representation of a Person:

class Person : IFormattable
{
 // omitted the code for 4 properties: Id, Name, Title and Birthday

 public override string ToString()
 {
  return ToString("{Id}, {Name}", null);
 }

 public string ToString(string format, IFormatProvider formatProvider)
 {
  string actualFormat = format;

  string[] replacements = new string[] { "Id", "Name", "Title", "Birthday" };
  for (int i = 0; i < replacements.Length; ++i)
  {
   actualFormat = actualFormat.Replace(replacements[i], i.ToString());
  }

  return string.Format(actualFormat, this.id, this.name, this.title, this.birthday);
 }
}

private void Form1_Load(object sender, EventArgs e)
{
 List<person> persons = new List<person>();
 persons.Add(new Person(1, new DateTime(1980, 4, 30), "Tim", "Sir"));
 persons.Add(new Person(2, new DateTime(1974, 4, 9), "Jenna", "Miss"));

 this.comboBox1.FormatString = "{Name} born on {Birthday}";
 this.comboBox1.FormattingEnabled = true;
 this.comboBox1.DataSource = persons;
}



Using interfaces with Drag and Drop

Earlier today i was refactoring some graphical components. I wanted to use an interface instead of concrete implementations for my drag and drop code… Although i was using an instance of Foo, and thus IFoo, the following code never allowed me to drop:

interface IFoo { }
class Foo : IFoo { }

private void label1_MouseDown(object sender, MouseEventArgs e)
{
 this.DoDragDrop(new Foo(), DragDropEffects.All);
}

private void Form1_DragEnter(object sender, DragEventArgs e)
{
 // for an instance of Foo it returns false,
 // if you use typeof(Foo) it returns true though...
 if (e.Data.GetDataPresent(typeof(IFoo)))
 {
  e.Effect = DragDropEffects.All;
 }
}

Simply wrapping the concrete instance in a DataObject results in the desired behaviour:

private void label1_MouseDown(object sender, MouseEventArgs e)
{
 this.DoDragDrop(new DataObject(typeof(IFoo).FullName,new Foo()), DragDropEffects.All);
}

Improvements for the SortableBindingList (and TypedList)

I found out that the sorting didn’t work for ‘Expression’ properties. My first thought was to add another switch to the logic of the already existing code:

object value1 = t1;
object value2 = t2;

if (prop.Name.StartsWith("||"))
{
 // do something to find the 'ExpressionProperty' values
}
else
{
 foreach (string property in prop.Name.Split('.'))
 {
  // navigate through the relations
  PropertyInfo propertyInfo = value1.GetType().GetProperty(property);
  value1 = propertyInfo.GetValue(value1, null);
  value2 = propertyInfo.GetValue(value2, null);
 }
}

Since i already have a PropertyDescriptor it seems a lot smarter to use it’s GetValue instead:

object value1 = prop.GetValue(t1);
object value2 = prop.GetValue(t2);

At Matthieu MEZIL‘s blog i found a suggestion to use Comparer<T>. This allowed me to reduce:

IComparable comparable = value1 as IComparable;
if (comparable != null)
{
 return reverse * comparable.CompareTo(value2);
}
else
{
 comparable = value2 as IComparable;
 if (comparable != null)
 {
  return -1 * reverse * comparable.CompareTo(value1);
 }
 else
 {
  return 0;
 }
}

with:

// Notice that this requires that atleast value1 or value2 are an instance of a type that implements IComparable
return reverse * Comparer.Default.Compare(value1, value2);

Feel free to get yet another version of TypedList.zip.

Presenting the ExpressionDescriptor

A couple of days ago i presented you the TypedList which supports navigation through subproperties. Another common feature request is the possibility to add a column that has a value based on other values in the row (like a DataColumn with it’s Expression property set). With the plumbing code i’ve written it’s as simple as implementing the following interface:

public interface IExpressionProvider<componentType, PropertyType>
{
 /// <summary>
 /// Gets the name of the property
 /// </summary>
 string Name { get; }

 /// <summary>
 /// Returns the value of the expression for the given component
 /// </summary>
 /// <param name="component"></param>
 /// <returns></returns>
 PropertyType GetValue(ComponentType component);
}

An example implementation could be an expression that represents the duration of an Appointment:

public class DurationExpressionProvider : IExpressionProvider<appointment, TimeSpan>
{
 #region IExpressionProvider<appointment,TimeSpan> Members

 public string Name { get { return "||Duration"; } }

 public TimeSpan GetValue(Appointment component)
 {
  return component.DateTimeRange.End - component.DateTimeRange.Start;
 }

 #endregion
}

I’ve changed the constructor of TypedList a bit so that it accepts an enumeration of PropertyDescriptors. In my example you can initialise the list as following:

List<propertyDescriptor> propertyDescriptors = new List<propertyDescriptor>();

// create the subpropertydescriptors
string[] propertyNames = new string[] { "Patient.Name", "Patient.Address.Municipality", "DateTimeRange.Start", "DateTimeRange.End" };
propertyDescriptors.AddRange(Array.ConvertAll<string, SubPropertyDescriptor<appointment>>(propertyNames, delegate(string propertyName) { return new SubPropertyDescriptor<appointment>(propertyName); }));

// add an expressiondescriptor
IExpressionProvider<appointment, TimeSpan> expressionProvider = new DurationExpressionProvider();
ExpressionDescriptor<appointment, TimeSpan> durationDescriptor = new ExpressionDescriptor<appointment, TimeSpan>(expressionProvider);
propertyDescriptors.Add(durationDescriptor);

TypedBindingList<appointment> appointments = new TypedBindingList<appointment>(propertyDescriptors);

And this is how it looks like at runtime:

image of the typedlist

As always, feel free to download the code: TypedList.zip.

Presenting the TypedList<T>

A while ago i presented the SortableBindingList. One of the nice features you get with DataSets is that you can use relations to navigate through the data. Business Objects don’t give you this functionality by default. Today i implemented a BindingList that supports navigation through relations. First i’ll present you the Business Objects:

screenshot of business objects

We would like to create an overview of the appointments using a datagridview:

screenshot of wanted ui

I drag a datagridview on the designer form, add columns, and then i set the datapropertynames as following: (Notice how i use a . to navigate the relations)

this.dataGridView1.AutoGenerateColumns = false;
this.ColumnId.DataPropertyName = "Id";
this.ColumnPatient.DataPropertyName = "Patient.Name";
this.ColumnMunicipality.DataPropertyName = "Patient.Address.Municipality";
this.ColumnStart.DataPropertyName = "DateTimeRange.Start";
this.ColumnEnd.DataPropertyName = "DateTimeRange.End";

First we need to implement a method that allows us to find a PropertyInfo for the given property name:

public static PropertyInfo Resolve(string propertyName)
{
 Type t = typeof(T);
 PropertyInfo propertyInfo = null;

 string[] subPropertyNames = propertyName.Split('.');
 if (subPropertyNames.Length == 1)
 {
  // a regular property
  propertyInfo = t.GetProperty(propertyName);
 }
 else
 {
  // navigate through the subproperties
  for (int i = 0; i < subPropertyNames.Length - 1; ++i)
  {
   propertyInfo = t.GetProperty(subPropertyNames[i]);
   t = propertyInfo.PropertyType;
  }
 }

 return propertyInfo;
}

Now we are ready to implement the ITypedList.GetItemProperties method in our TypedList:

public PropertyDescriptorCollection GetItemProperties(PropertyDescriptor[] listAccessors)
{
 PropertyDescriptorCollection propertyDescriptors = new PropertyDescriptorCollection(listAccessors);

 // add the regular property descriptors T has
 foreach (PropertyDescriptor propertyDescriptor in TypeDescriptor.GetProperties(typeof(T)))
 {
  propertyDescriptors.Add(propertyDescriptor);
 }

 // add the subproperties
 foreach (string subPropertyName in this.subPropertyNames)
 {
  propertyDescriptors.Add(new SubPropertyDescriptor<t>(subPropertyName));
 }

 return propertyDescriptors;
}

Using this class is as simple as:

// create a TypedList that holds Appointments
TypedBindingList<appointment> appointments = new TypedBindingList<appointment>(new string[] { "Patient.Name", "Patient.Address.Municipality", "DateTimeRange.Start", "DateTimeRange.End" });

// Initialise two patients
Patient patient = new Patient(1, "Tim", new Address(1, "MyStreet", 1820, "Melsbroek"));
Patient patient2 = new Patient(2, "John", new Address(2, "His Street", 3000, "Leuven"));

// Add appointsments to the list
appointments.Add(new Appointment(1, patient, new DateTimeRange(new DateTime(2007, 5, 3, 15, 0, 0), new DateTime(2007, 5, 3, 16, 0, 0))));
appointments.Add(new Appointment(2, patient2, new DateTimeRange(new DateTime(2007, 5, 4, 15, 0, 0), new DateTime(2007, 5, 4, 16, 0, 0))));
appointments.Add(new Appointment(3, patient, new DateTimeRange(new DateTime(2007, 5, 5, 15, 0, 0), new DateTime(2007, 5, 5, 16, 0, 0))));
appointments.Add(new Appointment(4, patient, new DateTimeRange(new DateTime(2007, 5, 6, 15, 0, 0), new DateTime(2007, 5, 6, 16, 0, 0))));
appointments.Add(new Appointment(5, patient2, new DateTimeRange(new DateTime(2007, 5, 7, 15, 0, 0), new DateTime(2007, 5, 7, 16, 0, 0))));
appointments.Add(new Appointment(6, patient, new DateTimeRange(new DateTime(2007, 5, 7, 17, 0, 0), new DateTime(2007, 5, 7, 17, 15, 0))));

// Assign this list to the datagridview datasource
this.dataGridView1.DataSource = appointments;

Pretty cool, don’t you think? As always, feel free to download the code: TypedList.zip

Edit: Today, May 8th 2007, i discovered a but in SubPropertyDescriptor.SetValue and uploaded a newer version of the code.

Exploring DataGridViewComboBoxColumn databinding (part2)

A while ago i wrote about Exploring DataGridViewComboBoxColumn databinding using Business Objects. Some people asked me to give an example using DataSets…

I’ll start with creating a DataSet, add two DataTables, and create a relation on PersonType.Id (int32). In the designer this looks like:

screenshot of dataset designer displaying person and persontype

Next i create a DataSetDac that will return an instance of a Filled PersonDataSet (In real life you would probably use a TableAdapter and get the data from a database) The code is as simple as:

public static PersonsDataSet Find()
{
 PersonsDataSet personsDataSet = new PersonsDataSet();

 personsDataSet.PersonType.Rows.Add(new object[] { 0, "A geeky person" });
 personsDataSet.PersonType.Rows.Add(new object[] { 1, "A coward" });
 personsDataSet.PersonType.Rows.Add(new object[] { 2, "Feeling hot hot hot" });
 personsDataSet.PersonType.Rows.Add(new object[] { -1, "(None)" });

 personsDataSet.Person.Rows.Add(new object[] { "Timvw", 0 });
 personsDataSet.Person.Rows.Add(new object[] { "John Doe", 1 });
 personsDataSet.Person.Rows.Add(new object[] { "An Onymous", 1 });
 personsDataSet.Person.Rows.Add(new object[] { "Jenna Jameson", 2 });
 personsDataSet.Person.Rows.Add(new object[] { "Null Able", -1 });

 return personsDataSet;
}

And now comes the important stuff: Bind the data to the DataGridView and DataGridViewComboBoxColumn:

public Form1()
{
 InitializeComponent();

 PersonsDataSet personsDataSet = DataSetDac.Find();

 this.dataGridView1.AutoGenerateColumns = false;
 this.ColumnName.DataPropertyName = "Name";
 this.ColumnPersonTypeCode.DataPropertyName = "PersonTypeId";

 this.ColumnPersonTypeCode.DisplayMember = "Label";
 this.ColumnPersonTypeCode.ValueMember = "Id";
 this.ColumnPersonTypeCode.DataSource = personsDataSet.PersonType;

 BindingSource bindingSource = new BindingSource();
 bindingSource.DataSource = personsDataSet.Person;
 this.dataGridView1.DataSource = bindingSource;
}

Geeks are doomed to stay Geeks forever. When you try change a Person that is a Geek, the values in ComboBox should be limited to Geek and (None). The following code takes care of that:

void dataGridView1_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e)
{
 if (this.dataGridView1.CurrentCell.ColumnIndex == this.ColumnPersonTypeCode.Index)
 {
  BindingSource bindingSource = this.dataGridView1.DataSource as BindingSource;
  PersonsDataSet.PersonRow person = (bindingSource.Current as DataRowView).Row as PersonsDataSet.PersonRow;

  // this method returns the allowed persontypes for the given person
  PersonsDataSet.PersonTypeDataTable personTypeDataTable = DataSetDac.FindPersonTypes(person);

  DataGridViewComboBoxEditingControl comboBox = e.Control as DataGridViewComboBoxEditingControl;
  comboBox.DataSource = personTypeDataTable;

  comboBox.SelectionChangeCommitted -= this.comboBox_SelectionChangeCommitted;
  comboBox.SelectionChangeCommitted += this.comboBox_SelectionChangeCommitted;
 }
}

public static PersonsDataSet.PersonTypeDataTable FindPersonTypes(PersonsDataSet.PersonRow person)
{
 // by default, all persons simply have one of the available persontypecodes
 PersonsDataSet personsDataSet = Find();

 if (person.PersonTypeId.Equals(0))
 {
  // geeks are doomed to stay geeks
  personsDataSet.PersonType.Rows.RemoveAt(2);
  personsDataSet.PersonType.Rows.RemoveAt(1);
 }

 return personsDataSet.PersonType;
}

void comboBox_SelectionChangeCommitted(object sender, EventArgs e)
{
 this.dataGridView1.EndEdit();
}

As always, feel free to download DataGridViewComboBoxBinding2.zip.

Presenting the MultiPanel

A while ago i was thinking that i would be nice to have a control that exposes multiple designer panels, but only shows one at a time… Somewhat like a TabControl, but without the header.. Anyway, i found out (here) that a TabControl can be tweaked into that behaviour:

public class MultiPanel : TabControl
{
 protected override void WndProc(ref Message m)
 {
  if (m.Msg == 0x1328 && !DesignMode)
  {
   m.Result = (IntPtr) 1;
  }
  else
  {
   base.WndProc(ref m);
  }
 }
}

In the designer it appears as following:

screenshot of MultiPanel at designtime

screenshot of MultiPanel at designtime

And at runtime it appears as following:

screenshot of MultiPanel at designtime

screenshot of MultiPanel at designtime

Performing long running tasks in a Windows Application

A while ago i blogged about Thread Safe UI. Today someone asked the following:

On a form i have a datagridview and two button. One is for insert in a database the values in datagridview, and the other to update data in db.
Now, i would like to have a kind of ‘progress form’ during the insert or the update. At the end, only when the operation is finished, the user can reuse the main form.

The first thing i do is define a delegate (void Performer()) that will do the work of a long running operation. The reason i do this is because the compiler generates a class Performer that inherits from System.MulticastDelegate and exposes Begin- and EndInvoke methods.

screenshot of ildasm displaying generated performer class

Since i want to disable my form before each run of a Performer and enable it after each run i implement a method Perform as following:

private void Perform(Performer performer, string message)
{
 this.PrePerform(message);
 performer.BeginInvoke(this.PostPerform, null);
}

Now it’s simply a matter of implemeting Pre- and PostPerform:

private void PrePerform(string message)
{
 if (this.InvokeRequired)
 {
  this.EndInvoke(this.BeginInvoke(new MethodInvoker(delegate { this.PrePerform(message); })));
 }
 else
 {
  this.Enabled = false;
  this.toolStripStatusLabel1.Text = message;
  this.toolStripStatusLabel1.Visible = true;
  this.toolStripProgressBar1.Visible = true;
 }
}

private void PostPerform(object state)
{
 if (this.InvokeRequired)
 {
  this.EndInvoke(this.BeginInvoke(new MethodInvoker(delegate { this.PostPerform(state); })));
 }
 else
 {
  this.toolStripProgressBar1.Visible = false;
  this.toolStripStatusLabel1.Visible = false;
  this.toolStripStatusLabel1.Text = string.Empty;
  this.Enabled = true;
 }
}

Now that we have all the infrastructure i implement an eventhandler for a button click:

private void button1_Click(object sender, EventArgs e)
{
 // remove previously retrieved results
 this.UpdateResultLabel(string.Empty);

 this.Perform(delegate
 {
  // simulate the effect of a blocking operation that takes a while to complete
  // eg: remoting, webrequests, database queries, ...
  Thread.Sleep(5000);

  // display the result of the long running operation
  this.UpdateResultLabel("Value was retrieved...");
 }, "Retrieving value...");
}

Here are a couple of screenshots of the running program:

screenshot of application not doing anything

screenshot of application performing long running task

screenshot of application after completion of long running task

Feel free to download the AsyncDemo.zip

DataGridView to Excel

The CarlosAg Excel Xml Writer Library does not require Excel in order to generate Excel Workbooks. I already presented a method to print a DataGridView (here) and now i present you a method that allows you to export a DataGridView to an Excel Workbook: DataGridViewToExcel.zip.

screenshot of the source datagridview
screenshot of the generated excel workbook

Little INotifyPropertyChanged helper

Most implementations of INotifyPropertyChanged look as following (notice that you have to make sure that the hardcoded PropertyName is spelled correctly):

class MyClass : INotifyPropertyChanged
{
 public event PropertyChangedEventHandler PropertyChanged;

 private int x;

 public int X
 {
  get { return this.x; }
  set
  {
   if (this.x != value)
   {
    this.x = value;
    this.OnPropertyChanged("X");
   }
  }
 }

 [MethodImpl(MethodImplOptions.NoInlining)]
 private void Fire(Delegate del, params object[] args)
 {
  if (del != null)
  {
   foreach (Delegate sink in del.GetInvocationList())
   {
    try { sink.DynamicInvoke(args); }
    catch { }
   }
  }
 }

 protected virtual void OnPropertyChanged( string propertyName )
 {
  this.Fire( this.PropertyChanged, new PropertyChangedEventArgs( propertyName ) );
 }
}

Everytime you refactor a property you also have to make sure to refactor the string with it’s name in the setter method. Here’s a helper method that makes life a little easier:

protected void OnPropertyChanged()
{
 this.OnPropertyChanged(new StackTrace(false).GetFrame(1).GetMethod().Name.Substring(4));
}

This makes the implementation of a property as simple as (No more hardcoded strings to maintain):

 public int X
{
 get { return this.x; }
 set
 {
  if (this.x != value)
  {
   this.x = value;
   this.OnPropertyChanged();
  }
 }
}