WPF Using WinForms – Wrong Approach

Background

It has been quite a while since I have been excited about something new is software development that made me want to spend my off hours playing around with it.  When WPF first came out I did not even give it a look.  I figured it was another one of Microsoft’s attempts to reinvent something.

I was mainly a middleware developer and wrote WinForms applications to access the middle tier.  I really hated ASP.Net so when I took a contract which required ASP.Net, I was looking around for alternatives and that is when I found Silverlight.  What I liked about Silverlight is it allowed me to create all of the cool functionality that Flash has without having to learn something complete different.  Silverlight was laid out in the same format as the rest of the Microsoft libraries so it just made sense how to wire things up and get up and running.  During my course of learning and playing with Silverlight I found references to WPF and how basic WPF xaml could be used for Silverlight.  I picked up WPF and haven’t looked back.  It does take some time to get used to, when I first started, if I needed to make a quick test harness I used WinForms but now I use WPF for everything.  It takes some time to hit the epiphany where it just all comes into place and makes sense.  When it does, it is really a pleasure to code.

During the last year, I have been given or should I say have had two projects dropped in my lap that were written in WPF (and I use that phrase liberally).  I think the more accurate description is the application was written in WinForms with a xaml front end.  Both applications had one thing in common, they either could not get into QA or could not get out of QA due to performance issues or random exception faults.  After having to basically re-write both applications I made some notes on some of the mistakes I saw in the code with the hope that it will help others who are new to WPF from making the same mistakes.

User Controls

When using WinForms, the common approach to have controls have the same look and feel or common functionality is to use user controls.  Though you certainly can do this in WPF, user controls mainly used to encapsulate behavior or group controls together for a specific purpose.  You also have custom controls which basically allows you to build a control from the ground up.  For a good article on user controls vs. custom controls read more here: http://wangmo.wordpress.com/2007/09/28/user-controls-vs-custom-controls/

So if you want to customize the OK and Cancel buttons in your application to have an image with text next to it, instead of creating a user control library which defines this functionality, a style can more easily be defined.  (Style abbreviated for size)

    <Style x:Key=”ImageButtonStyle” BasedOn=”{StaticResource {x:Type Button}}” TargetType=”{x:Type Button}”>
        <Setter Property=”HorizontalContentAlignment” Value=”Center”/>
        <Setter Property=”VerticalContentAlignment” Value=”Center”/>
        <Setter Property=”Template”>
            <Setter.Value>
                <ControlTemplate TargetType=”{x:Type Button}”>
                        <StackPanel>
                            <Image Source=”{Binding RelativeSource={RelativeSource Self}, Path=DataContext}” Stretch=”Fill” Width=”45″ Height=”45″ />

                            <ContentPresenter HorizontalAlignment=”{TemplateBinding HorizontalContentAlignment}” Margin=”{TemplateBinding Padding}” VerticalAlignment=”{TemplateBinding VerticalContentAlignment}” SnapsToDevicePixels=”{TemplateBinding SnapsToDevicePixels}” RecognizesAccessKey=”True”/>
                        </StackPanel>
                    <ControlTemplate.Triggers>
                        <Trigger Property=”IsEnabled” Value=”false”>
                            <Setter Property=”Foreground” Value=”{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}”/>
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

This style can then be applied to a button as shown here:

<Button Style=”{StaticResource ImageButtonStyle}”     DataContext=”/WpfApplication1;component/Close.png” Name=”CloseButton”>Close</Button>

The other advantage to using styles is the ability to change all object types to a particular style.  For example if you have a common library that is used in multiple applications, you can define the controls to be generic (no specific colors, size, etc.) and allow each of the applications to change the color and size to it’s own specifications.  To tell WPF to make the style apply to all controls, simply change the style declaration to use the type as the key as shown here:

<Style x:Key=”{x:Type Button}” TargetType=”Button”>

For the control, you do not need to specify any style, it will use the one defined in you dictionary as the default.

Binding

Binding can be one of the more difficult concepts to grasp because of its flexibility.  There are several good posts on binding including http://msdn.microsoft.com/en-us/magazine/cc163299.aspx  Here are a couple of the mistakes that I have seen:

In the first example, the idea is to load an xml file with state codes and descriptions for a combo box.  The user creates a dataset, reads all of the codes and then assigns the result to the combo box.  

DataSet ds = new DataSet();
XElement statesElement = XElement.Load(“/Data/StateCodes.xml”);
ds.ReadXml(statesElement.CreateReader());
cboState.DataContext = ds.Tables[0];
cboState.DisplayMemberPath = Settings.Default.StateMemberPath;

If you use the XmlDataProvider, you can bind the source to the provider as shown here:

<XmlDataProvider x:Key=”StateData” Source=”/Data/StateCodes.xml” XPath=”//State” />

<ComboBox ItemsSource=”{Binding Source={StaticResource StateData}}”
          DisplayMemberPath=”@id” Name=”cboState” />

In the second example, there are two controls that work together.  Some examples would be using a label to display the value of a scrollbar or making two controls have the same width.  Here is an example of how you bind two controls together:

<Slider Name=”sliderScale” Orientation=”Horizontal” Value=”1.0″ />

<Label Content=”{Binding ElementName=sliderScale, Path=Value, Mode=Default}”/>

If you have types that are not compatible (e.g. a string to update a double) you will need to use a Converter.  This goes beyond the scope of this posting.

Resources

Resources can be stored internally or externally to the application.  If have a resource such as an image which will remain static, the resource can be compiled into the application and referenced in that manner.  Here is example of improperly referencing a static image:

imageBackground.Source = LoadBitmap(“/Images/GpsConnected.png”);

BitmapImage LoadBitmap(string path)
{
    byte[] bytes = File.ReadAllBytes(path);
    MemoryStream memoryStream = new MemoryStream(bytes);
    BitmapImage image = new BitmapImage();
    image.CacheOption = BitmapCacheOption.OnLoad;
    image.BeginInit();
    image.StreamSource = memoryStream;
    image.EndInit();
    bytes = null;

    return image;
}

The following code does the same thing:

imageBackground.Source = new BitmapImage(new Uri(GetBitmapFileName(“/eSketch;component/Images/GpsConnected.png”)));

Callbacks

The final piece that I will touch on is callbacks.  Though I have not tracked down the exact instances or cause, I have found that using in the following manner results in unpredictable exceptions.  It will sometimes cause the application to hang for no apparent reason.  The worst part about it is that it is not consistent.

delegate void SetTextCallback(string Text);
private void WriteLongitude(string Text)
{
    if (txtGpsLongitude.Dispatcher.Thread != Thread.CurrentThread)
    {
        SetTextCallback callBack = new SetTextCallback(WriteLongitude);
        Dispatcher.Invoke(DispatcherPriority.Send, callBack, Text);
    }
    else
    {
        txtGpsLongitude.Text = Text;
    }
}

As a result, I recommend using this method:

private void WriteLongitude(string text)
{
    Dispatcher.Invoke(DispatcherPriority.Send,
                        new Action(() =>
                        {
                            txtGpsLongitude.Text = text;
                        }));
}

Summary

With the flexibility that WPF provides, it can be difficult to get started and you can make more work for yourself.  My intent was to provide some pointers to help you from making more work for yourself. 

In the future I will provide some more guidance including how to extent functionality such as comboboxes.  Feedback is always appreciated.

Advertisements

About David Wetzel

A Microsoft Certified senior-level Architect / Developer with 15+ years’ experience specializing in architecting, constructing, and deploying complex, secure, and scalable applications. • Experience in multifaceted business – boxed software, multi-tiered (SOA) systems, multi-threading, network integration utilities, and customized accounting packages. • Proven history using Microsoft’s newest technologies (WCF, WPF, WF, and LINQ). • Solid management skills, demonstrated proficiency in leading and mentoring individuals to maximize levels of productivity. • Strong SQL database background – design, optimization, and administration • Experience mentoring individuals on new technologies and best practices through team presentations, formal lectures, blogs (https://davidwetzel.wordpress.com), and code reviews. Specialties: Currently hold 14 certifications through Microsoft.
This entry was posted in C#, WPF. Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s