Using WPF for Business Applications

Tuesday, March 11, 2008 9:14:38 PM (Central Standard Time, UTC-06:00)

Here is the presentation that I did today at the Microsoft office in Minneapolis today.  It was a segment on real world WPF.  It discusses how WPF isn't just about the cool North Face demo or the New York Times Reader, but there is advantages for using it in every day enterprise applications.  The presentation and source can be found below.  The demo's include sample WPF implementations for Authorization, Application Activity Monitoring and Highlighted Search similar to what you experience when you search in Outlook.  None of the examples are currently at production quality, but with a little polish they could get there.

Authorization UI

Demonstrates how to use attached properties on different UI elements to change whether they are hidden or disabled based on the users authorization for a specific UI Element.  The authorization UI is mocked up, but should give you an idea of how you can extend any UI Element with property metadata to help in the UI authorization scenario.

image

Application Activity Monitoring

Demonstrates how you can implement monitoring of the mouse and keyboard to determine if you should disable the UI of the application... in this implementation it will blur after 5 seconds of no activity.  This implementation still needs some work... you can still edit data after the screen has blurred and there is no login dialog which would pop up after the blur has taken place so you can resume work.

image

Highlighted Search

Similar to how Microsoft Outlook highlights the search term as you type, this implementation demonstrates a simplified version using a listbox.  There is a bunch of sample data... you can test it out with up to 10,000 records.  If you want to generate more seed data, you can use the seed data api that I put together.

image

Enumerating Exceptions using ForEach

Tuesday, September 04, 2007 9:51:50 PM (Central Standard Time, UTC-06:00)

Thought I would share this class I wrote the other day... it is a helper class that flattens the the Exception hierarchy and allows you to enumerate through the exceptions using ForEach. The following shows how the class is used.

 

EnumerableException items = new EnumerableException(ex);

 

foreach (EnumerableException item in items)

    System.Diagnostics.Debug.WriteLine(item.Exception.Message);

 

The following is the source: EnumerableException.zip

 

 

 

Example of deriving from a WPF User Control

Friday, June 22, 2007 8:24:31 AM (Central Standard Time, UTC-06:00)

I put together an example of how to derive from a base class for a WPF user control when the base class is found in the local assembly or a reference one.  If you want more detail on how to do the derivation you can read my previous post.

UserControlDerivationExample.zip (77.79 KB)

Using Word Automation to Update Word's Table of Contents

Tuesday, January 23, 2007 11:11:23 PM (Central Standard Time, UTC-06:00)

This one took a while to figure out... so I thought I would post it for others.  So the problem was I am building a document using the Word Automation model within C#.  When I inserted text that had styles defined for the TOC (Header 1 for example) I couldn't get the new header text to appear in the TOC contents in my final document output.

My usual approach of recording a macro in Word and then reviewing the VBA code resulted in the followin:

Sub Macro2()
'
' Macro2 Macro
'
'

WordBasic.UpdateTableOfContents
End Sub

But there was no indication of how to "Update entire table", like the option shown in the UI.  No matter what I indicated it was always the same code as shown above.

I saw other approaches online that cycled through the Fields collection and called update, but again there was not option for "Update Entire Table".  When I tried it, it didn't update the TOC with the header 1 text I had just added to the document.

After digging a around a bit more I finally figured it out:

Word.Application _wordApp;

internal void UpdateTOC()
{
//cycle through all of the TOC's and Update them
foreach (Word.TableOfContents contents in _wordApp.Application.ActiveDocument.TablesOfContents)
{
contents.Update();
}
}

Bitwise operations on Enum Flags

Thursday, October 26, 2006 9:13:37 PM (Central Standard Time, UTC-06:00)

A number of times I find my self looking up how to assign multiple enum values to a property to support options semantics on a control.  So to make it easier to find I am TidByteing it here. An example of this is the classic Border property that allows you to identify where you want lines drawn.  For example, lets say we have an enum that looks like this (note that I am using powers of two so they can easily be combined):

public enum Border

       {

           Top = 1,

           Bottom = 2,

           Left = 4,

           Right = 8

       }

And you want to indicate to draw only on the left and right borders would look something like this:

ctl.Border = Border.Left | Border.Right

To make this work you need to add the FlagsAttribute to the enum:

[Flags()]
public enum Border

 

Then to check to see if a flag is set you would do the following:

if ((propertyName & Border.Left) == Border.Left)

        //border left border needs to be drawn;

 

 

Problems with the Draw() on the IHMTLPainter interface

Friday, October 06, 2006 1:24:29 PM (Central Standard Time, UTC-06:00)

The project that I am working on right now we are making some customizations to the MSHTML editor that is hosted by Internet Explorer.  With that we have some custom tags that we need rendered in a specific way (for example wavy lines under misspelled words). 

This can be accomplished by a Binary Behavior that implements the IHTMLPainter interface.  When the behavior is loaded, MSHTML checks to see if the IHTMLPainter interface is supported, if it is supported it will call the appropriate methods on the interface to render the tag. 

The problem I was having was the Draw method was never called.  I could attach the behavior to the body tag and it would render the graphics I wanted, but as soon as a moved it to a span it wouldn't call the draw.  After a couple of hours playing around with it I finally stumbled on to the fact that if the span has a height and width set (even to 0) the Draw() method will be called.  I didn't find this documented anywhere so I thought I would post it for others.

Learn more about binary behaviors here.

Stop Watch Wrapper

Monday, September 18, 2006 9:45:06 PM (Central Standard Time, UTC-06:00)

With .NET 2.0 they introduced the StopWatch class which can be used to time the execution of your code to a very high resolution.  Here is a wrapper to help package it up.

public class PerformanceTimer : IDisposable

    {

        Stopwatch _stopwatch = new Stopwatch();

        private static string _elapstedTime;

        public PerformanceTimer()

        {

            PerformanceTimer._elapstedTime = string.Empty;

            _stopwatch.Start();

        }

        public static string ElapstedTime

        {

            get { return _elapstedTime; }

            set { _elapstedTime = value; }

        }

        public void Dispose()

        {

            _stopwatch.Stop();

            TimeSpan ts = _stopwatch.Elapsed;

 

            _elapstedTime =

                    String.Format("{0:00}:{1:00}:{2:00}.{3:00}",

                    ts.Hours, ts.Minutes, ts.Seconds, ts.Milliseconds / 10);

        } 

    }

The class is used in the following manner:

using(new PerformanceTimer())

{

    //Execute code you are timing here.

 

}

 

string result = PerformanceTimer.ElapstedTime;

Creating Seed Data - Updated

Monday, September 18, 2006 9:31:38 PM (Central Standard Time, UTC-06:00)

I did another update to my SeedData class, it now supports the creation of:

  • Job Titles
  • Addresses
  • States
  • Zip Codes
  • County

The city, states and zip codes all match appropriately, in other words if you request a random zip for example, it will return the zip with the related City, State and county.  The data is older (from the 1990 census) but it works great for generating real looking dummy data. 

The following code shows how to use the class

//Load external Seed Data files that aren't automatically loaded (check src to see which are)

SeedData.LoadSeedData("Titles", string.Format(@"{0}\SeedData_JobTitles.txt", Application.StartupPath), 0);

SeedData.LoadSeedData("Address", string.Format(@"{0}\SeedData_Addresses.txt", Application.StartupPath), 0);

 

PersonTableGateway gw = new PersonTableGateway();

 

using(new PerformanceTimer())

{

 

    for (int i = 0; i < 500; i++)

    {

        //create a record using the SeedData class

        Person p = new Person();

        p.FirstName = SeedData.GetFirstName().Trim();

        p.LastName = SeedData.GetLastName().Trim();

        p.NetworkUserID = p.FirstName.Substring(0, 1) + p.LastName;

        p.EMail = p.NetworkUserID.Trim() + "@sysknowlogy.com";

        p.Phone = SeedData.CreatePhone("612");

        p.Title = SeedData.GetRandomSeed("Titles");

        p.TitleDescription = "Description of the title goes here.";

 

        //create a street address

        p.Address1 = SeedData.Number(1000,9999) + " " + SeedData.GetRandomSeed("Address");

 

        ZipCode zip = SeedData.GetZip();

        p.Zip = zip.Zip;

        p.City = zip.City;

        p.State = zip.State;

        p.Branch = zip.City;

 

        gw.CreatePerson(p);

 

    }

}

 

 

 

SeedData1.zip (564.84 KB)

Automating the creation of Seed Data

Wednesday, August 02, 2006 11:00:00 PM (Central Standard Time, UTC-06:00)
Just about every project I have had a need a need to create some seed data.  It’s a pain to come up with good seed data, especially around names of people.
 
The is the main purpose behind the SeedData.cs class that I wrote to create random names of people.  A quick search brought me to data gathered in the 1990 census.  There were over 80,000 last names and 5000 first names.  Pretty good mix for generating seed data.
 
I also added the capability to read in a file delimited by crlf to support creating other seed data based on lists in text files.
 
If you add any other seed data files, send the updates to me and I will post them.
 

SeedData.zip

Using the HtmlAgilityPack

Thursday, February 09, 2006 12:00:00 AM (Central Standard Time, UTC-06:00)
Parsing Html with regular expressions can be an excruciating experience.  The cryptic syntax can take hours to get right.  What if you could treat malformed html like xml and use XPath to select the html tags you were looking for.
 
The HtmlAgility pack allows you to do just that.  It handles parsing the Html document and making navigable via XPath (implements the IXPathNavigable interface).  It also has facilities for downloading the HTML from a Url.  After the document has been parsed you have the capability to update the document.  In addition, there is examples of how to:
 
  • Harvest links from an Html document.
  • Convert the html document to text.
  • Convert the html document to xml.
  • Create an RSS feed from existing html content.
 
I recently used it to create an implementation for the RFC Standard 2557, also known as MIME Encapsulation of Aggregate Documents or Mht Web Archive files.  The same files you create in Internet Explorer by selecting File --> Save As and then modify the file type to be Web Archive. 
 
The implementation I wrote is based on this article Convert any URL to a MHTML archive using native .NET code that I found on CodeProject a while back.  The CodeProject implementation was written in VB.Net and used regular expressions heavily.  In addition, the first version of the implementation was file based and required all of the files to be written to disk before they were embedded into a single mht file.  The later version offers an in memory option so the files no longer need to be persisted to the disk. 
 
The implementation I wrote is based in C# and relies on the HtmlAgility pack to do the heavy lifting of parsing the Html for external resources.  I did have to use one regular expression to find the @import directives with in a style tag. 
 
Here is the code written to create a mht file:
 
string htmlLocation = "http://blogs.technet.com/justinbraun/archive/2005/11/07/413859.aspx";
 
WebResourceDownloader downloader = newWebResourceDownloader();
MhtDocument mht = newMhtDocument(htmlLocation, downloader);
string result = mht.CreateMht();
System.IO.File.WriteAllText("justinbraun.mht", result);
 
Below is an example capture of a web page using the implementation I wrote.  It's a snapshot of my brothers blog.