Windows Forms Tricks You May Have Missed

This article dives into Windows Forms. Rather than focusing on a specific feature, it covers a variety of topics that will assist you in building fully functional and well performing Windows Forms applications. You'll need to have some level of familiarity with topics such as data binding and validation to follow along.

Data Binding Optimization

Data binding allows data to be processed automatically and displayed in controls such as ComboBox on the user interface (UI). When you change the ValueMember property on controls programmatically, it causes most controls to repopulate the data from the configured DataSource. This means your controls may inadvertently populate multiple times. To prevent your control from being populated multiple times, a good practice is to always set the DataSource property last on controls such as ComboBox and ListBox, as follows:

comboBox1.ValueMember   = "Name";
comboBox1.DisplayMember = "Name";
comboBox1.DataSource    = test;

Control Data Population

Loading items into controls such as ListView and TreeView causes a repainting after each change. The BeginUpdate and EndUpdate methods allow bulk operations to occur without causing excessive repainting. Here's an example:

listView1.BeginUpdate();
for(int i = 0; i < 10000; i++)
{
   ListViewItem listItem = new ListViewItem("Item"+i.ToString() );
   listView1.Items.Add(listItem);
}
listView1.EndUpdate();

You also can use the AddRange method to efficiently add an array of pre-created items. It automatically calls BeginUpdate and EndUpdate. Additionally, it performs other optimizations to the methods internally to ensure efficiency in the loading, as follows:

ListViewItem[] list = new ListViewItem[10000];
for (int i = 0; i < 10000; i++)
{
   list[i] = new ListViewItem("Item" + i.ToString());
}
listView1.Items.AddRange(list);

You also should avoid the use of Items.Clear() with non-databound lists. It will cause excessive screen painting if you use it. Rather, encapsulate a block of code with calls to BeginUpdate and EndUpdate. Traverse the non-databound list and add, edit, or remove items. This will avoid unnecessary painting and UI delay.

PropertyGrid Control

The PropertyGrid control is a native control available within .NET. It is a simple model for displaying property settings. It can use a serializable object with properties to display, save, and load state. Below is sample code to create and display a simple property grid.

PropertyGrid optionsPropertyGrid = new PropertyGrid();
optionsPropertyGrid.Size         = new Size(300, 250);

this.Controls.Add(optionsPropertyGrid);
this.Text = "Options Dialog";

// Create the class and display in PropertyGrid.
AppSettings appset = new AppSettings();
optionsPropertyGrid.SelectedObject = appset;

Threaded UI

A prior set of articles (Part 1, Part 2, and Part 3) contains much more detail about threading, but it is worth mentioning here. You can use threads to perform processing in the background and increase the perceived responsiveness and performance of a WinForm app. It is especially useful for long-running operations such as accessing resources across a network. The following sample code demonstrates the ability to call a method and have it process on a new thread, which would allow the UI to remain responsive:

System.Threading.Thread thread = new System.Threading.Thread(
   new System.Threading.ThreadStart(this.GoToSleep));
thread.Start();

ClickOnce Deployment

As covered in a previous article, ClickOnce is a mechanism for combining the reach of Web applications with the rich UI of a Windows Forms-based application through auto updateable Windows Forms. It relies on an application manifest, which describes the assemblies, dependencies, files, permissions, and update location, and the deployment manifest, which specifies the version number and location of the application manifest.

You can use ClickOnce in launched or installed mode. In launched mode, nothing is actually installed to the client computer. The application can be deployed to a web site, UNC folder, or CD/DVD. The application can look for updates on startup or at some point afterwards. Updates to the application can be forced as mandatory.

It has a publishing wizard that allows you to publish your projects easily and quickly. It auto generates the application and deployment manifests. The Mage and MageUI tools allow you to edit the manifest files after the fact. You should avoid changing the deployment type (debug or release) because it breaks compatibility with the manifest files. Also, assemblies used in the solution that are part of the GAC are not automatically included in the deployment.

User Input Validation

User input validation is the process of ensuring data is accurate before processing or storage. Typically, it is included in the UI layer to improve performance by reducing network round trips. Validation is enforced at the control level within Windows Forms. The controls have a CausesValidation property that dictates whether or not the control fires validation events when losing focus. The _Validating event is fired as the control is losing focus. You use the ErrorProvider control to control error messages and display. Here is some example code for validating a name field on a form:

void txtName_Validating(object sender, CancelEventArgs e)
{
   // Name is required
   if( txtName.Text.Trim().Length == 0 )
   {
      errorProvider.SetError(txtName "Name is required");
      e.Cancel = true;
      return;
   }
   else
   {
      // Name is valid
      errorProvider.SetError(txtName "");
   }
}

One or more forms may not have had focus. This forces you to enumerate all form controls and fire the _Validating event for each control. The following sample code depicts this behavior based on the click of an OK button:

void btnOK_Click(object sender, System.EventArgs e)
{
   foreach( Control control in Controls )
   {
      control.Focus();
      // Validate causes the control's Validating event to be
      // fired if .CausesValidation property is true
      if( !this.Validate() )
      {
         DialogResult = DialogResult.None;
         return;
      }
   }
}

This is all works, but it is more difficult than it really needs to be. Windows Forms use a code-intensive approach that is programmatic. ASP.NET uses a control-based approach that is declarative. An MSDN article describes how to create a set of validation controls that match the ASP.NET validation controls. This solution allows you to eliminate or at least significantly reduce the amount of validation code that you end up writing. Full source code is provided so you can customize to your needs. For example, I modified the controls to include an additional IsRequired property so that I could use a single control to make a field required and match other criteria. I highly recommend reading the article.

Report Enable Your Application

SQL Server 2005 Reporting Services reports can be embedded in Windows applications using a report viewer control. You can use a remote or local connection mode. The remote processing mode allows the report to be hosted from the remote server. It is rendered in output format and sent down to the report viewer for display. The local processing mode does not require a report server at all. The data source is identified in advance. Data from an ADO.NET table or enumerable collection can be used as data for the report.

The report viewer control comes with Visual Studio 2005. You also can download it along with the AdventureWorks sample database from the Microsoft SQL Server site.

Windows Forms Tricks You May Have Missed

Print to Excel

The same report viewer control also has a powerful side feature: the ability to generate Excel spreadsheets based on the report. The following sample code shows how to use the report viewer to read data and save it to Excel. It doesn't require that Microsoft Office even be installed:

string mimeType          = null;
string encoding          = null;
string fileNameExtension = null;
string[] streams         = null;
Microsoft.Reporting.WinForms.Warning[] warnings = null;
string deviceInfo =
   "<DeviceInfo>
       <SimplePageHeaders>True</SimplePageHeaders>
    </DeviceInfo>";

Microsoft.Reporting.WinForms.LocalReport localReport
   = new Microsoft.Reporting.WinForms.LocalReport();
localReport.ReportPath =
   @"..\..\Local Report Store Information.rdlc";

this.Adventure.EnforceConstraints = false;
localReport.DataSources.Add(new Microsoft.Reporting.WinForms.
   ReportDataSource("Sales", GetData()));

byte[] bytes = reportViewer1.LocalReport.Render("Excel",
   deviceInfo, out mimeType, out encoding, out fileNameExtension,
   out streams, out warnings);
System.IO.FileStream fileStream =
   new System.IO.FileStream(@"c:\ExcelExportSample.xls",
                            System.IO.FileMode.Create);

fileStream.Write(bytes, 0, bytes.Length);
fileStream.Close();

Knowledge Is Power

Hopefully, these tips for working with Windows Forms-based applications aren't run-of-the-mill for you, and they will help you in your Windows Forms development efforts. Here are a few links to additional resources that may interest you:

Future Columns

The topic of the next column is yet to be determined. If you have something in particular that you would like to see explained here, you could reach me at mstrawmyer@crowechizek.com.

About the Author

Mark Strawmyer (MCSD, MCSE, MCDBA) is a senior architect of .NET applications for large and mid-sized organizations. Mark is a technology leader with Crowe Chizek in Indianapolis, Indiana. He specializes in architecture, design, and development of Microsoft-based solutions. Mark was honored to be named a Microsoft MVP for application development with C# for the second year in a row. You can reach Mark at mstrawmyer@crowechizek.com.



About the Author

Mark Strawmyer

Mark Strawmyer is a Senior Architect of .NET applications for large and mid-size organizations. He specializes in architecture, design and development of Microsoft-based solutions. Mark was honored to be named a Microsoft MVP for application development with C# for the fifth year in a row. You can reach Mark at mark.strawmyer@crowehorwath.com.

Comments

  • There are no comments yet. Be the first to comment!

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Live Event Date: August 14, 2014 @ 2:00 p.m. ET / 11:00 a.m. PT Data protection has long been considered "overhead" by many organizations in the past, many chalking it up to an insurance policy or an extended warranty you may never use. The realities of today make data protection a must-have, as we live in a data driven society. The digital assets we create, share, and collaborate with others on must be managed and protected for many purposes. Check out this upcoming eSeminar and join eVault Chief Technology …

  • Where the business performance of their mobile app portfolios are concerned, most companies are flying blind. While traditional application portfolios are held to all kinds of ROI measure, the investment plan for mobile apps -- increasingly the more crucial bet -- is made by guesswork and dart-throwing. This interactive e-book investigates how mobile is driving the need for app and portfolio measures unlike any we saw in the days of web. Good mobile analytics must deliver leading indicators of user experience …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds