MULTIMEDIA

Building a WPF Application without XAML (part 1)

10/18/2011 9:06:14 AM
Given all of the functionality provided by the parent classes of the Window type, it is possible to represent a window in your application by either directly creating a Window object or using this class as the parent to a strongly typed descendent. Let's examine both approaches in the following code example. Although most WPF applications will make use of XAML, doing so is entirely optional. Anything that can be expressed in XAML can be expressed in code and (for the most part) vice versa. If you wish, it is possible to build a complete WPF project using the underlying object model and procedural code.

To illustrate, let's create a minimal but complete application without the use of XAML using the Application and Window classes directly. Begin by creating a new Console Application named WpfAppAllCode. Next, access the Project | Add Reference dialog box and add a reference to WindowsBase.dll, PresentationCore.dll, System.Xaml.dll and PresentationFramework.dll.

Now, update your initial C# file with the following code, which creates a window of modest functionality:

// A simple WPF application, written without XAML.
using System;


using System.Windows;
using System.Windows.Controls;

namespace WpfAppAllCode
{
// In this first example, you are defining a single class type to
// represent the application itself and the main window.
class Program : Application
{
[STAThread]
static void Main(string[] args)
{
// Handle the Startup and Exit events, and then run the application.
Program app = new Program();
app.Startup += AppStartUp;
app.Exit += AppExit;
app.Run(); // Fires the Startup event.
}

static void AppExit(object sender, ExitEventArgs e)
{
MessageBox.Show("App has exited");
}

static void AppStartUp(object sender, StartupEventArgs e)
{
// Create a Window object and set some basic properties.
Window mainWindow = new Window();
mainWindow.Title = "My First WPF App!";
mainWindow.Height = 200;
mainWindow.Width = 300;
mainWindow.WindowStartupLocation = WindowStartupLocation.CenterScreen;
mainWindow.Show();
}
}
}


NOTE

The Main() method of a WPF application must be attributed with the [STAThread] attribute, which ensures any legacy COM objects used by your application are thread-safe. If you do not annotate Main() in this way, you will encounter a runtime exception.

Note that the Program class extends the System.Windows.Application class. Within the Main() method, you create an instance of the application object and handle the Startup and Exit events using method group conversion syntax.

Of course, if you wish, you can specify the underlying delegates directly by name. In the following modified Main() method, notice that the Startup event works in conjunction with the StartupEventHandler delegate, which can only point to methods taking an Object as the first parameter and a StartupEventArgs as the second. The Exit event, on the other hand, works with theExitEventHandler delegate, which demands that the method pointed to take an ExitEventArgs type as the second parameter:

[STAThread]
static void Main(string[] args)
{
// This time, specify the underlying delegates.
MyWPFApp app = new MyWPFApp();
app.Startup += new StartupEventHandler(AppStartUp);
app.Exit += new ExitEventHandler(AppExit);
app.Run(); // Fires the Startup event.
}

In any case, the AppStartUp() method has been configured to create a Window object, establish some very basic property settings, and call Show() to display the window on the screen in a modeless fashion (the ShowDialog() method can be used to launch a modal dialog). The AppExit() method simply makes use of the WPF MessageBox class to display a diagnostic message when the application is being terminated.

Once you compile and run the project, you will find a very simple main window that can be minimized, maximized, and closed. To spice things up a bit, you need to add some user interface elements. Before you do, however, you should refactor your code base to account for a strongly typed and well-encapsulated Window-derived class.

1. Creating a Strongly Typed Window

Currently, the Application-derived class directly creates an instance of the Window type upon application startup. Ideally, you would create a class deriving from Window in order to encapsulate itsappearance and functionality. Assume that you have created the following class definition within your current WpfAppAllCode namespace (if you place this class in a new C# file, be sure to import the System.Windows namespace):

class MainWindow : Window
{
public MainWindow(string windowTitle, int height, int width)
{
this.Title = windowTitle;
this.WindowStartupLocation = WindowStartupLocation.CenterScreen;
this.Height = height;
this.Width = width;
}
}

You can now update your Startup event handler to simply directly create an instance of MainWindow:

static void AppStartUp(object sender, StartupEventArgs e)
{

// Create a MainWindow object.
MainWindow wnd = new MainWindow("My better WPF App!", 200, 300);
wnd.Show();
}

Once the program is recompiled and executed, the output is identical. The obvious benefit is that you now have a strongly typed window class to build upon.

NOTE

When you create a Window (or Window-derived) object, it will automatically be added to the windows collection of the Application class (via some constructor logic found in the Window class itself). You can use the Application.Windows property to iterate over the list of Window objects currently in memory.

2. Creating a Simple User Interface

Adding a UI element to a Window in C# code will involve the following basic steps:

  1. Define a member variable to represent the control.

  2. Configure the control's look and feel upon Window construction.

  3. Assign the control to the inherited Content property, or alternatively, as a parameter to the inherited AddChild() method.

Recall that the WPF control content model demands that the Content property is set only once. Of course, a Window that only contained a single UI control would be quite useless. Therefore, in almost every case, the "single piece of content" that is assigned to the Content property is, in reality, a layout manager, such as DockPanel, Grid, Canvas, or StackPanel. Within the layout manager, you can have any combination of internal controls, including other nested layout managers.

For now, you will add a single Button control to your Window derived class. When you click the button, you will close the current window, which will indirectly terminate the application, as you have no other windows in memory. Ponder the following update to the MainWindow class (be sure you have imported System.Windows.Controls to gain access to the Button class):

class MainWindow : Window
{
// Our UI element.
private Button btnExitApp = new Button();

public MainWindow(string windowTitle, int height, int width)
{
// Configure button and set the child control.
btnExitApp.Click += new RoutedEventHandler(btnExitApp_Clicked);
btnExitApp.Content = "Exit Application";
btnExitApp.Height = 25;
btnExitApp.Width = 100;

// Set the content of this window to a single button.
this.Content = btnExitApp;

// Configure the window.
this.Title = windowTitle;
this.WindowStartupLocation = WindowStartupLocation.CenterScreen;
this.Height = height;
this.Width = width;
this.Show();
}

private void btnExitApp_Clicked(object sender, RoutedEventArgs e)
{
// Close the window.
this.Close();
}
}

In any case, once you recompile and run this application, you will find the customized window shown in Figure 1. Notice that your button is automatically placed in the dead center of the window's client area; this is the default behavior when content is not placed within a WPF panel type.

Figure 1. A Simple WPF application writen in 100% C# code

Other  
  •  iPhone 3D Programming : Drawing an FPS Counter (part 2) - Rendering the FPS Text
  •  iPhone 3D Programming : Drawing an FPS Counter (part 1) - Generating a Glyphs Texture with Python
  •  Programming with DirectX : Game Input - XInput
  •  Programming with DirectX : Game Input - Win32 Input
  •  Introducing Windows Presentation Foundation and XAML : Investigating the WPF Assemblies
  •  Introducing Windows Presentation Foundation and XAML : The Motivation Behind WPF & The Various Flavors of WPF
  •  Microsoft XNA Game Studio 3.0 : Getting the Date and Time
  •  Microsoft XNA Game Studio 3.0 : Text and Computers
  •  Silverlight Recipes : Managing Embedded Resources
  •  Silverlight Recipes : Managing XAML Resources
  •  Silverlight Recipes : Updating the UI from a Background Thread
  •  Programming with DirectX : Sound in DirectX - XAudio2
  •  Programming with DirectX : Sound in DirectX - XACT3 (part 2) - XACT3 Demo
  •  Programming with DirectX : Sound in DirectX - XACT3 (part 1) - XACT3 Tools
  •  iPhone 3D Programming : Image-Processing Example: Bloom
  •  iPhone 3D Programming : Anisotropic Filtering: Textures on Steroids
  •  iPhone 3D Programming : Reflections with Cube Maps
  •  Silverlight Recipes : Networking and Web Service Integration - Accessing Resources over HTTP
  •  Silverlight Recipes : Networking and Web Service Integration - Using JSON Serialization over HTTP
  •  Microsoft XNA Game Studio 3.0 : Displaying Images - Using Resources in a Game (part 4) - Filling the Screen
  •  
    Top 10
    Windows Phone 7 : Packaging, Publishing, and Managing Applications
    Secure Browsing and Local Machine Lockdown in Vista
    Installing Windows Server 2008 R2 and Server Core : Understanding Server Core Installation
    Changes in Windows Vista Affecting SDI
    Using Windows Phone 7 Technologies : Understanding Orientation and Movement
    Server-Side Browser Detection and Content Delivery : Mobile Detection (part 3) - Transcoders
    SQL Server 2008 : Using the CLR - Understanding Permission Sets
    Windows 7 : Windows Driver Foundation Architecture (part 2) - Integrated I/O Queuing and Cancellation
    Mobile Application Security : SMS Security - Protocol Attacks (part 2)
    SQL Server 2008 : Programming Objects - Implementing Functions
    Most View
    Exchange Server 2010 : Deploying a Database Availability Group (part 3)
    iPhone Application Development : Using Advanced Interface Objects and Views - Using Scrolling Views
    Externalizing BLOB Storage in SharePoint 2010 (part 2) - Installing and Configuring RBS & Migrating and Moving BLOBs Between BLOB Stores
    Protecting SQL Server Data : SCHEMA ARCHITECTURE STRATEGIES - Using Views
    Web Security Testing : Manipulating Sessions - Analyzing Session Identifiers with Burp
    iPhone Application Development : Building a Multi-View Tab Bar Application (part 4) - Implementing the Summary View
    Wireless Threats
    Creating Link-Worthy Content and Link Marketing : Types of Link Building (part 1)
    Algorithms for Compiler Design: USING ALGEBRAIC PROPERTIES TO REDUCE THE REGISTER REQUIREMENT
    Manipulate File Paths
    Blind SQL Injection Exploitation : Using Response-Based Techniques
    Hybrid Ciphers
    Servlet Development and Deployment : Configuring the servlet & Packaging the web application
    Designing and Configuring Unified Messaging in Exchange Server 2010 : Unified Messaging Installation (part 1)
    SharePoint 2010 : Business Intelligence - Visio Services
    Advanced ASP.NET : The Entity Framework (part 1) - Creating an Entity Data Model
    Exchange Server 2010 : Perform Essential Database Management (part 1) - Manage the Database Files
    Exploring the T-SQL Enhancements in SQL Server 2005 : TOP Enhancements
    Windows Server 2008 : Understanding Internet Information Services (IIS) 7.5
    Installing SharePoint 2010 Using PowerShell