Category Archives: WPF

WPF

When creating a WPF application, the first thing you will meet is the Window class. It serves as the root of a window and provides you with the standard border, title bar and maximize, minimize and close buttons. A WPF window is a combination of a XAML (.xaml) file, where the element is the root, and a CodeBehind (.cs) file. A default structure od a XAMP (eXtended Application Markup Language) file will be like the following:

<Window x:Class="WpfApplication1.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="300" Width="300">
    <Grid>
         ...
        </Grid>
</Window>

The x:class attribute tells the XAML file which class to use.
There is a Grid control inside the Window element. The Grid is one of the WPF panels, and while it could be any panel or control, the Window can only have only ONE child control, so a Panel, which in turn can contain multiple child controls, is usually a good choice.

App.xaml, including a Code-behind file called App.xaml.cs, is the declarative starting point of the application.  App.xaml.cs extends the Application class, which is a central class in a WPF Windows application. .NET will go to this class for starting instructions and then start the desired Window or Page from there. This is also the place to subscribe to important application events, like application start, unhandled exceptions and so on. One of the most commonly used features of the App.xaml file is to define global resources that may be used and accessed from all over an application, for instance global styles.

 

App.xaml structure

When creating a new application, the automatically generated App.xaml will look something like this:

<Application x:Class="WpfTutorialSamples.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             StartupUri="MainWindow.xaml">
    <Application.Resources>

    </Application.Resources>
</Application>

The main thing to notice here is the StartupUri property. This is actually the part that instructs which Window or Page to start up when the application is launched. In this case, MainWindow.xaml will be started, but if you would like to use another window as the starting point, you can simply change this.

In some situations, you want more control over how and when the first window is displayed. In that case, you can remove the StartupUri property and value and then do it all from Code-Behind instead. This will be demonstrated below.

App.xaml.cs structure

The matching App.xaml.cs will usually look like this for a new project:

using System;
using System.Collections.Generic;
using System.Windows;

namespace WpfTutorialSamples
{
        public partial class App : Application
        {

        }
}

You will see how this class extends the Application class, allowing us to do stuff on the application level. For instance, you can subscribe to the Startup event, where you can manually create your starting window.

 

Here’s an example:

<Application x:Class="WpfTutorialSamples.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                         Startup="Application_Startup">
    <Application.Resources></Application.Resources>
</Application>

Notice how the StartupUri has been replaced with a subscription to the Startup event (subscribing to events through XAML is explained in another chapter). In Code-Behind, you can use the event like this:

using System;
using System.Collections.Generic;
using System.Windows;

namespace WpfTutorialSamples
{
        public partial class App : Application
        {

                private void Application_Startup(object sender, StartupEventArgs e)
                {
                        // Create the startup window
                        MainWindow wnd = new MainWindow();
                        // Do stuff here, e.g. to the window
                        wnd.Title = "Something else";
                        // Show the window
                        wnd.Show();
                }
        }
}

The cool thing in this example, compared to just using the StartupUri property, is that we get to manipulate the startup window before showing it. In this, we change the title of it, which is not terribly useful, but you could also subscribe to events or perhaps show a splash screen. When you have all the control, there are many possibilities. We will look deeper into several of them in the next articles of this tutorial.

 

WPF Resources

 

WPF introduces a very handy concept: The ability to store data as a resource, either locally for a control, locally for the entire window or globally for the entire application. The data can be pretty much whatever you want, from actual information to a hierarchy of WPF controls. This allows you to place data in one place and then use it from or several other places, which is very useful.

 

<Window x:Class="WpfTutorialSamples.WPF_Application.ResourceSample"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:sys="clr-namespace:System;assembly=mscorlib"
        Title="ResourceSample" Height="150" Width="350">
    <Window.Resources>
        <sys:String x:Key="strHelloWorld">Hello, world!</sys:String>
    </Window.Resources>
    <StackPanel Margin="10">
        <TextBlock Text="{StaticResource strHelloWorld}" FontSize="56" />
        <TextBlock>Just another "<TextBlock Text="{StaticResource strHelloWorld}" />" example, but with resources!</TextBlock>
    </StackPanel>
</Window>



Resources are given a key, using the x:Key attribute, which allows you to reference it from other parts of the application by using this key, in combination with the StaticResource markup extension. In this example, I just store a simple string, which I then use from two different TextBlock controls.

StaticResource vs. DynamicResource

In the examples so far, I have used the StaticResource markup extension to reference a resource. However, an alternative exists, in form of the DynamicResource.

The main difference is that a static resource is resolved only once, which is at the point where the XAML is loaded. If the resource is then changed later on, this change will not be reflected where you have used the StaticResource.

 

A DynamicResource on the other hand, is resolved once it’s actually needed, and then again if the resource changes. Think of it as binding to a static value vs. binding to a function that monitors this value and sends it to you each time it’s changed – it’s not exactly how it works, but it should give you a better idea of when to use what. Dynamic resources also allows you to use resources which are not even there during design time, e.g. if you add them from Code-behind during the startup of the application.

More resource types

Sharing a simple string was easy, but you can do much more. In the next example, I’ll also store a complete array of strings, along with a gradient brush to be used for the background. This should give you a pretty good idea of just how much you can do with resources:

 

<Window x:Class="WpfTutorialSamples.WPF_Application.ExtendedResourceSample"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:sys="clr-namespace:System;assembly=mscorlib"
        Title="ExtendedResourceSample" Height="160" Width="300"
        Background="{DynamicResource WindowBackgroundBrush}">
    <Window.Resources>
        <sys:String x:Key="ComboBoxTitle">Items:</sys:String>

        <x:Array x:Key="ComboBoxItems" Type="sys:String">
            <sys:String>Item #1</sys:String>
            <sys:String>Item #2</sys:String>
            <sys:String>Item #3</sys:String>
        </x:Array>

        <LinearGradientBrush x:Key="WindowBackgroundBrush">
            <GradientStop Offset="0" Color="Silver"/>
            <GradientStop Offset="1" Color="Gray"/>
        </LinearGradientBrush>
    </Window.Resources>
    <StackPanel Margin="10">
        <Label Content="{StaticResource ComboBoxTitle}" />
        <ComboBox ItemsSource="{StaticResource ComboBoxItems}" />
    </StackPanel>
</Window>



Advertisements