Posts for Category: Fundamentals
Using attractive typefaces can add individuality to your application, or reinforce your brand. Although we talked about the means to embed WPF fonts in your application a long time ago, the biggest issue with font embedding is the licensing issues associated with fonts, especially if you’re working on a code sample or free utility. Most fonts, even the multitude that you can download for free online, are not licensed to allow redistribution as part of your application.
Fortunately a small group of fonts has started to be released under a much more permissive license – the SIL Open Font License (OFL) - which specifically allows embedding in applications, both commercial, free and open-source (disclaimer: I am not a lawyer, you should read the license yourself and/or seek legal advice before making any decisions regarding font licensing). This is a very generous move on the part of these type designers who spend considerable time and skill on designing beautiful fonts.

Here is a sample application that uses some of my favourite of OFL-licensed fonts from around the web including Titillium, Goudy Bookletter 1911, and Junction. Great resources for finding new fonts with the OFL license is the Open Font Library and the League of Movable Type.
download source [413 KB] (including fonts!)
From a programming point-of-view it pays to remember this trick from the MSDN for finding the names of embedded fonts. Sometimes the name is not apparent from the file name OR from the info you see in the "Install Font" dialog in windows. Instead you can programatically iterate through the installed fonts using this snippet of code.
// iterates over embedded fonts - assumes you have fonts in a sub-directory called "Fonts" in the project in visual studio
foreach (var fontFamily in Fonts.GetFontFamilies(new Uri("pack://application:,,,/"), "./Fonts/"))
{
// do stuff with fonts here
}
.NET Framework 4.0 solves the single biggest problem with WPF development - The size of the .NET framework redistributable. The full redistributable for the x86 version of the .NET framework weighs in at a svelte 37.71 MB, and the cut-down client profile (that should be suitable for many WPF client applications) is just under 31 MB! For 64-bit platforms (x64 and ia64) the full redistributable are about 55 MB each. They both have the x86 bits included also so x86 .NET applications can run in the WoW. You can get all the details here (including what is in and out of the client profile, how to target etc here). Compared to the 230 MB for the full redistributable for .NET Framework 3.5 sp1 this is a welcome relief. Whatever techniques the .NET framework team have learned putting silverlight on an extreme diet have paid off here too. Lets hope this minification of the framework continues into the RTM version.
I thought I would post a short explanation of a small issue I encountered recently with the XAML compiler, in particular with its treatment of linked XAML files. Linked files can be created for all kinds of project files, most commonly code files like .cs or .vb files but it can be anything else. This is almost always done to when you need the same thing in multiple places but don't want to go to the trouble of managing two copies of it. They are added by changing the option in the open file dialog triggered when you choose "add existing item" in your project from 'add' to 'add as link' as shown below.
XAML files linked in this way will compile fine, but the relative path from the root of the project used as the key when retrieving them is lost when they are linked. Assuming we had a project structure like this. A project Foo contains a folder called resources, which in turn contains a XAML resource dictionary called stuff.xaml. Project Bar also has this same structure, but stuff.xaml has been added as a linked file from the Foo project.
If we open up these two using reflector we see that in Foo the path to the resource dictionary has been specified correctly.
In the decompiled output for Bar we can see that they key to stuff.baml is different.
Because resource keys are so...err...key in locating and using them this will substantially affect most usage scenarios for this resource. One way to work around this problem is to factor these resources out into a library DLL that just contains these resources, however this doesn't work with all resource usage scenarios.
If you’ve written your own custom attached property in WPF you may come across the following error when you try to look at a Window, Page or UserControl that attempts to use the attached property in the WPF designer in Visual Studio 2008:
The Property '[your custom attached property name]' is read-only and cannot be changed
The puzzling thing is that you can get this error message even if your attached property is not defined as read-only, and has a setter and isn’t registered as read-only in the Property Meta-data. Even more confusingly the property can seem fine and working correctly at run-time.
So what’s going on? Although the error message is a little cryptic the error is caused by a type mismatch between the property type of the dependency property (when it is registered) and the second parameter accepted by the “Set[YourPropertyName]” method that is defined when creating an attached property. For example if you’ve registered an attached property like this:
public static readonly DependencyProperty MyCustomProperty =
DependencyProperty.RegisterAttached("MyCustom", typeof(MyOtherType), typeof(MyType));
The property meta-data system expects that when you set this attached property the value will be of MyOtherType (the second type parameter is the type that "owns" the dependency property, usually the type you declare the DP in). Type WPF designer is aware of this, for example if you attempt to assign this property in XAML from a string and no appropriate converter from string to MyOtherType is present it shows an error.
However as part of your attached property declaration you are also obliged to create "Get[PropertyName]" and "Set[PropertyName]" wrapper methods for getting and setting the attached properties.
public static void SetMyCustom(DependencyObject depObj, TheWrongType value)
{
depObj.SetValue(MyCustomProperty, value);
}
If we include the wrong type as the second parameter in one of these declarations – in this case a type that is not assignable from MyOtherType - this isn’t a compile time error (because these methods aren’t part of any interface we’re implementing or generic type) and may work fine at run-time if that code path isn’t called (I believe that XAML bypasses the property wrappers). The designer does pick up on the discrepancy, and considers that type dependency property is read-only because it couldn’t find an appropriately typed "Set[YourPropertyName]” method. Of course this error is easy to resolve once you know the cause, by changing the type of the second parameter to be the same as, or assignable from the type that was used when you declared the dependency property.
When you create a WPF application in Visual Studio the 'entry point' for the process, where the application is created and the first form displayed, is not directly apparent. Instead the start-up behaviour is controlled by setting attributes on the App.xaml, such as which form to start. At compile-time WPF generates the real entry point method using the classic static void Main() method signature in C#, or Public Shared Sub Main() in VB.NET. Inside the Main() method WPF creates an instance of one of your classes which derive from System.Windows.Application, and calls the blocking Run() method on this Application-derived class which keeps the process "alive". Generally this is a useful abstraction, hiding away some of the lower-level details of how the WPF application starts up, however sometimes you want to provide your own version of the Main() method. So how do you tell WPF to use your main method and not its own?
The way WPF knows to create the Main() method for a particular xaml file is through the build action property set for App.xaml - it has a build action of ApplicationDefinition. By changing this to Page WPF won't create the Main method and you can provide your own in a regular class file you add to the project.
It is important to note that when you provide your own Main() method that the method should be adorned with the STAThread attribute, which sets the threading model for the process. You can either look at the current generated Main() method for your project as a starting point (it should be in the obj folder) or use the following code:
[System.STAThreadAttribute()]
static void Main()
{
YourApplicationName app = new YourApplicationName();
app.InitializeComponent();
app.Run();
}
One thing people often ask me about WPF is the learning curve - how long will it take for me to be productive, and how long before I know the "whole api". The sad fact is that knowing the "whole" of WPF is a difficult proposition, due to its size. A lot has been written about the learning curve associated with the XAML programming model and the vector-based retained rendering system, but regardless of these factors WPF is going to have a learning curve due just to its size. WPF is big by any standard - with almost 1600 public types in v3.0 and almost 3600 classes it is approximately the same size as Windows Forms and ASP.NET combined. It spans 3 main assemblies PresentationCore.dll, PresentationFramework.dll and WindowsBase.dll (I'm excluding the Aero, Classic, Luna and Royale "theme" assemblies, and the UI automation and ReachFramework in my calculation of the size since they are not WPF specific). The good news is that you don't need to know the "whole api" in order to be productive and start using WPF. Here's a helpful infographic to convey the message:
|
ASP.NET 2.0
|
WinForms 2.0
|
WPF
|
|
|
|
|
|
|
|
1098 public types 1551 classes |
777 public types 1500 classes |
1577
public types 3592 classes |
For some kinds of applications displaying as “maximised” is not enough, either because they want to make use of every single pixel of screen-space possible, or because displaying the task bar and associated window trimmings would be distracting or confusing for users of the application. The PowerPoint slide viewer is a good example of this, starting in “kiosk” mode to create a more immersive presentation and preventing audience members becoming distracted by the task bar and things in the notification area. Fortunately doing this for your own WPF application can be achieved quite easily by setting the WindowStyle and WindowState properties on the Window as shown below.
Xaml Code
<Window x:Class="LearnWPF.KioskMode.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="LearnWPF.KioskMode"
WindowStyle="None"
WindowState="Maximized">
WindowStyle should be set to None (this draws the window without any border, and is the same state you can use to create a WPF splash screen) and the WindowState set to Maximized. These properties can also be set from code. One small issue we have observed is if you try to change the WindowStyle in code after the WindowState has changed to Maximized the resulting window will be drawn without a border, but won’t display over the top of the status bar.
.NET applications traditionally suffer from slower startup time than native applications, caused by the time to load the .NET framework DLLs, JIT time etc. WPF applications have further things that can slow down cold start-time, the extra PresentationCore, PresentationFramework and WindowBase assemblies that need to be loaded and the start-up of the PresentationFontCache service. Any tips to help improve start time is therefore most welcome.
Doug Stockwell recently released an updated version (v1.6 build 2802) of his free RikReader WPF-based RSS Reader, with considerably-improved start time. I've been using RikReader as my primary RSS reader since it was first released, and in previous versions the start time stood out as a blemish on an otherwise excellent app. The performance characteristics of older versions of RikReader were a little different to usual applications, in that the hot start-times were still quite bad (>10 seconds for my list of a couple of hundred feeds), whereas the new version hot-starts in about 4 seconds (roughly equivalent to Expression Blend, Thoughtex and most other WPF applications I use). Cold start-times for RikReader had also improved noticeably.
I contacted Doug to find out what he'd done to achieve this great improvement, and was pleased to hear of the simple change he had made. Instead of using XAML to declaratively set the DataContext for his main window, which contained all the RSS feed data, he switched to setting it programmatically in the Application.OnActivated. This sounds like a tip that would improve the perceived performance of the app (making the main window display more quickly) without improving the actual performance, however it seems to have also improved the actual start time considerably. As with all things performance-related your mileage may vary, and it pays to measure yourself. Fortunately the simplicity of this change means it will be easy to swap between the two methods of setting the DataContext.
I recently had a scenario where I wanted a number of WPF text fields to support a co-ordinated undo/redo capability. The regular undo/redo facility in WPF (and most control tool-kits) applies to a single field. Changes to that field can be undone or re-applied, but each field is very much stand-alone and independent of those around it. I wanted a facility where a number of fields could be logically grouped together for the purposes of undo and redo operations, since I thought this would more closely match the user’s mental model of how the system worked. Changes should be tracked across multiple fields, and undo and redo operations should occur in the order they are made across the different fields. I also wanted the focus to change also as undo/redo operations occurred.
Using it
Using the shared undo/redo scope I created is quite easy, and can be accomplished just using XAML. An “undo manager” is set as an attached property as shown in the code sample below. The SharedUndoRedoScope attached property on the UndoManager type I created is set for a StackPanel. The property is inherited, so it can be set on a parent element (like a panel) and applied to all the children. In the example below the two textboxes share a common “undo/redo manager” because they are both children of the same stackpanel
XAML Fragment
<StackPanel>
<undo:UndoManager.SharedUndoRedoScope>
<undo:UndoManager />
</undo:UndoManager.SharedUndoRedoScope>
<TextBox Text="text box 1" />
<TextBox Text="text box 2" />
</StackPanel>
The sample application (shown below) creates two shared undo/redo scopes, and a third set of elements that don’t have any special undo/redo capabilities for comparison. You can download the sample application with full source from here.
Implementation
The undo manager has two main roles internally – firstly to track changes in the text boxes across all the text boxes it is managing (so they can be un-done in that order), and then actually stepping in at the right time and triggering the undo.
Tracking changes is relatively straightforward - When text changed events are fired for textboxes the undo manager is managing, it pushes the changes onto an internal undo stack. Only changes that are important are added. For example many TextChanged events will fire when someone is typing with the UndoAction of Merge, these aren’t necessary for the UndoManager to track.
Actually triggering Undo and Redo operations is slightly trickier, and I needed to work around some implementation details of the TextBox and RichTextBox controls in WPF. Both of the TextBoxBase-derived controls wire up command handlers on an internal class called the TextEditor inside their constructors. In here amongst a group of internal classes some handlers for ApplicationCommands.Undo and ApplicationCommands.Redo are created. When the WPF TextBox and RichTextBox handle these ApplicationCommands they mark them as “handled” to prevent them bubbling up to your code. While usually this is quite desirable, preventing your application code having to care about undo and redo commands being fired which the TextBox has already taken care of in this instance it causes a problem because the UndoManager needs to step in at this point and potentially do something different. Fortunately with routed events you can optionally choose to “see” routed events that have already been marked as handled, which is what I have done, by calling the AddHandler() method overload that takes a third Boolean parameter for specifying if you want to see the handled events.
C# Code
textBox.AddHandler(CommandManager.PreviewCanExecuteEvent, new CanExecuteRoutedEventHandler(manager.CanExecuteRoutedEventHandler), true);
When the UndoManager sees an Undo or Redo ApplicationCommands it pops an item off its internal undo or redo stack, and calls the Undo() or Redo() method on the text box on the stack as appropriate.
Currently the implementation only tracks changes in TextBox and RichTextBox. You could extend it to handle undo and redo of selection in lists and toggling of checkboxes etc. also.
In implementing this I was conscious of trying to create a programming model that “meshed” with the rest of WPF, in particular I thought choosing an inheritable attached property was an appropriate way to expose this kind of feature. I would be keen to hear any feedback on this aspect of the implementation, in particular how this could have been done better.
Update: Roman was kind enough to point out some embarrassingly obvious flaws in my implementation (see comments below), which are fixed in the source code you can download now.
WPF is all about creating great user experiences, but the user experience of your application starts long before your code starts running on the end user’s machine. An important first step is launching your application and getting your code down onto the end user’s machine as quickly and simply as possible. ClickOnce makes great strides in improving this deployment experience for .NET 2 rich client applications and WPF applications, however the default publish page that is generated by visual studio can be greatly improved. In this article we discuss techniques to reduce the amount of decision-making required of the end user, and give them an experience tailored to their operating system version, browser version and system capabilities to minimize the size of the download for clients on sub-broadband network connections.
The broad approach we’ll be trying to take is:
- Identify potential users who can have WPF installed and can start using our application right away.
- Create a hyperlink to launch our application that works for their browser.
- For those users who need to install .NET Framework 3.0 direct them to do so and then give them a link to launch our application.
- For those users who we believe will not be able to run any WPF applications, give them the option of trying to install .NET Framework 3.0 and our application, but warn them that it may not work and why.
Identifying WPF-capable clients via the User Agent String
The user agent string is an optional parameter that can be sent as part of the HTTP headers when making a request to a web server. The user agent string is intended as a means for the client to identify itself to the server, so the server can optionally adjust the response if appropriate. Although the content of the user agent string is entirely free form and does not carry any guarantees regarding accuracy or authenticity, it is still broadly useful for identifying browser versions and client capabilities.
Identifying WPF-capable Clients using Internet Explorer
By default Internet Explorer includes the versions of the .NET framework present on the client in the user agent string like so:
Example Microsoft Internet Explorer 7.0 User Agent String on Windows Vista:
Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; SLCC1; .NET CLR 2.0.50727; Media Center PC 5.0; .NET CLR 3.0.04506)
(an exhaustive list of User Agent strings can be found here)
Fortunately the System.Web namespace contains the helpful HttpCapabilitiesBase class which can perform the task of parsing out the available CLR versions on the client. The code below assumes that WPF will be included in versions of .net framework subsequent to version 3.
C# Code
HttpCapabilitiesBase httpCapabilities = HttpCapabilitiesBase.GetConfigCapabilities("system.web/browserCaps", HttpContext.Current.Request);
Version wpfV1FinalVersion = new Version("3.0.04506");
Version[] clrVersions = httpCapabilities.GetClrVersions();
foreach (Version clrVersion in clrVersions)
{
if (clrVersion >= wpfV1FinalVersion)
{
// client has WPF
}
}
For clients that have WPF installed we can simply link directly thru to the .application file generated by ClickOnce, which will prompt the user to install our application. For clients that don’t have the .NET Framework 3.0 or better installed we can direct them to where it can be downloaded, and then prompt them to launch our application. Alternatively we could launch the ClickOnce bootstrap setup.exe which can install pre-requisites on the client’s machine.
Identifying WPF-capable Clients using Mozilla Firefox
Unlike Internet Explorer, Mozilla does not include the .NET CLR versions installed on the client computer as part of the user agent string. However since Windows Vista comes with WPF pre-installed on it we can check the Mozilla user agent string for the Windows version, and for Vista users assume they have WPF. For Windows XP and Server 2003 users we can indicate that WPF is supported, that we can’t tell if they have it or not and provide them with a two-step installation process (step 1 being to install .NET Framework 3.0, and step 2 to install our application).
Example Mozilla Firefox 2.0 User Agent String on Windows Vista
Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.8.1.2) Gecko/20070219 Firefox/2.0.0.2
For users that don’t appear to be using Windows, or who are using an older version of windows we revert to our fallback position – tell them that we believe they won’t be able to run our application but they are welcome to try with the two steps listed above.
Serving the Right Files to Launch our Application in Mozilla Firefox
Unfortunately identifying WPF-capable clients using Firefox is only the beginning, because the .application file used to launch your ClickOnce application does not work in Firefox (although there are some add-ins for Firefox that allow them to work). Cross-browser support was de-scoped from ClickOnce between Beta 2 and RTM, but luckily there is a work-around where Mozilla users running windows can be served a .appref-ms file. A .appref-ms is a kind of ClickOnce version of a desktop shortcut, which will then correctly launch your application for them (if they have .NET Framework 3.0 installed). The easiest way to get your hands on one of these files for your application is to deploy it using IE and ClickOnce, and then copy the shortcut that is created in the start menu – that is a .appref-ms file. You will need to deploy this file yourself. If your application is being served up by IIS you may need to add a MIME type mapping for .appref-ms files also.
Why not just direct users to the ClickOnce bootstrap setup.exe program?
The ClickOnce bootstrap executable (setup.exe) is a useful way to launch your application installation in some cases, however there are some issues with it. Setup.exe doesn’t work with Mozilla Firefox if it is the default web browser on the client system. Also Firefox users on Vista see a moderately concerning prompt about running executables downloaded from the internet. For users who already have the pre-requisites necessary to run your application on slower network connections the 400K download of setup.exe is time and bandwidth wasted. For users on XP SP2 running IE who do not have .NET 3.0 installed setup.exe is a good choice.
A sample user control and code for detecting clients with WPF installed can be downloaded from here.
Developers new to WPF are sometimes a little confused when the Width and Height properties of elements report as ‘NaN’ (Not a Number) in code, when these very same elements are clearly visible and do have a width and height. What’s going on?
The short answer is you can interpret ‘NaN’ to mean “not set”. The Width and Height properties of Buttons, TextBoxes and most other controls are inherited from the FrameworkElement superclass. These normal .NET properties in turn backs on to a DependencyProperty (the WidthProperty in the case of Width) that has been registered for FrameworkElement in the class constructor with a default value of ‘NaN’. Until you set that WidthProperty to something, or set the Width .NET property in code or Xaml the Width will stay as ‘NaN’. If you wish to know what the on-screen size for an object is you should instead consult the ActualWidth and ActualHeight properties, which always reflects the actual width and height of the object on screen. These properties are sometimes a little hard to find given the number of public properties and methods on many objects in WPF.
The query-string portion of the URL in a HTTP request is a useful place for passing state between pages in web applications. It is therefore not unexpected that developers would also want to use this common idiom for passing information to WPF XBAPs (Xaml Browser Applications) that they wish to integrate with their site.
Fortunately this is not too difficult, except there is one trick you need to know. The ActivationUri property of the ApplicationDeployment object gives you the Uri that launched the XBAP. To get access to this you need to add a reference to System.Deployment.dll. To get hold of the current ApplicationDeployment object for your XBAP use the static CurrentDeployment property of the ApplicationDeployment object like so.
Uri launchUri = System.Deployment.Application.ApplicationDeployment.CurrentDeployment.ActivationUri;
If you launch this code from inside Visual Studio to debug it won’t work. The way it is launched means when you press F5 means that the CurrentDeployment property will be null and thus cause a NullReferenceException. You can use the static IsNetworkDeployed property of the ApplicationDeployment ojbect to check if you’ve been deployed over the network (for an XBAP application hosted in the browser this should be true).
if (ApplicationDeployment.IsNetworkDeployed)
{
Uri launchUri = ApplicationDeployment.CurrentDeployment.ActivationUri;
}
So far so good, and now for the trick. In order for the deployment infrastructure to actually pass anything through to you via this API you need to set a property in your manifest. Fortunately Visual Studio 2005 gives you a convenient way to do this. Select project properties in Visual Studio 2005 and then go to the publish tab, as shown in figure below.

Now click the Options button and in the options dialog check the box that says “Allow URL parameters to be passed to application”. Click OK and re-build your application.

Once you’ve verified that the URI is being passed through you can use the Query property of the URI to return the query-string portion, and parse out any information you need from there.
The golden rule of WPF multi-threading is "Thou shalt only update UI using code that runs on the same thread as the UI." If you happen to be running on another thread you use the Dispatcher property of any of your UI elements to get back on to the UI thread. This raises the question - how do I know when I'm on the UI thread? It turns out the Dispatcher has two methods you can use - CheckAccess and VerifyAccess. CheckAccess returns true if you are on the UI thread. VerifyAccess is a more aggressive version of this method and throws an exception if you are not running on the UI thread. Strangely CheckAccess is marked with attributes to prevent it appearing in intellisense in Visual Studio. This CheckAccess method is the WPF equivalent of the InvokeRequired property of the Control object in Windows Forms, which had similar thread-affinity rules to WPF.
On a related note the Arbel Network Blog has an excellent tip that uses reflection inside of a method to call back in to itself (but on the UI thread) if necessary. They also have a link to Nick Kramer's threading white paper.
WPF enthusiast Gill Cleeren emailed me recently to let me know about his article on WPF Styles and Triggers that recently went live on the MSDN Belgium site. It provides an excellent starting point for those starting out with styles, and shows enough code to be useful without being overwhelming.
Also noteworthy from MSDN Belgium last year was Jelle Druyts' article on WPF Commands.
The default lauch screen for WPF XBAP applications has changed recently (I believe for RC1). This is what your users will see (hosted inside IE) when your XBAP application is being downloaded for the first time.

In a comment on our previous post on creating glossy-looking items in WPF Jason asks how to emulate the glossy "now playing" section in apple's iTunes MP3 player. Although we don't want to condone the use of Macs, or any apple software on Windows we were prepared to grant Jason's request. Using these iTunes screen-shots as our starting point this is what we came up with.
| iTunes "now playing" |
WPF |
|
|
Xaml Source (July CTP):
<Page xmlns="
http://schemas.microsoft.com/winfx/2006/xaml/presentation
"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
xmlns:x="
http://schemas.microsoft.com/winfx/2006/xaml
"
Background="#785429" >
<Grid Width="200" Height="50">
<Rectangle Stroke="#56584c" StrokeThickness="1.5"
RadiusX="3" RadiusY="3" Fill="#d6dbbf"/>
<Rectangle VerticalAlignment="Top" Height="22" Margin="2,2,2,0"
Stroke="{x:Null}" RadiusX="2" RadiusY="2"
SnapsToDevicePixels="True">
<Rectangle.Fill>
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
<GradientStop Color="#EEF0E5" Offset="0" />
<GradientStop Color="#E4E7D5" Offset="0.9" />
</LinearGradientBrush>
</Rectangle.Fill>
</Rectangle>
</Grid>
</Page>
Glossy, highly reflective-looking UIs are currently quite popular. While there are many ways you can suggest a reflective surface using gradients and hilights, some of the simpler effects are often the best. Here is a simple approach that uses two rectangles placed on top of eachother inside a grid, which gives a nice reflective appearance.
Xaml Code (Jul 2006 CTP)
<Page xmlns="
http://schemas.microsoft.com/winfx/2006/xaml/presentation
"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
xmlns:x="
http://schemas.microsoft.com/winfx/2006/xaml
" Background="#785429" >
<Grid Width="200" Height="70">
<Rectangle Stroke="#FFe1e1e1" RadiusX="10" RadiusY="10"
HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
Width="Auto" Height="Auto" x:Name="Rectangle">
<Rectangle.BitmapEffect>
<DropShadowBitmapEffect ShadowDepth="2"/>
</Rectangle.BitmapEffect>
<Rectangle.Fill>
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
<GradientStop Color="#FFF9F9F9" Offset="0"/>
<GradientStop Color="#FFd9d9d9" Offset="1"/>
</LinearGradientBrush>
</Rectangle.Fill>
</Rectangle>
<Rectangle Stroke="{x:Null}" Margin="3,14,3,3"
RadiusX="14" RadiusY="10" HorizontalAlignment="Stretch"
VerticalAlignment="Stretch" Width="Auto" Height="Auto">
<Rectangle.Fill>
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
<GradientStop Color="#FFE8E8E8" Offset="0"/>
<GradientStop Color="#FFE4E4E4" Offset="0.2"/>
<GradientStop Color="#FFbdbdbd" Offset="1"/>
</LinearGradientBrush>
</Rectangle.Fill>
<Rectangle.BitmapEffect>
<BlurBitmapEffect Radius="1" KernelType="Box"/>
</Rectangle.BitmapEffect>
</Rectangle>
</Grid>
</Page>
Xaml Browser Apps (XBAPs - formerly called WBAs) are an a light-weight way of deploying rich WPF applications to users via their web browser. In addition to all the enhanced display features and stateful programming model that WPF apps have over HTML-based internet applications, XBAPs can also touch local system resources like reading from the file system. Allowing applications that run in the browser direct access to the file system would be a huge security risk. XBAPs ensure that the potentially malicious browser-hosted application can only ever read files that the user has selected for it to read. The XBAP author creates an OpenFileDialog (from the Microsoft.Win32 namespace) and displays it to the user by calling ShowDialog(). If the user selects a file and clicks OK the application can then read the file by calling the OpenFile() method on an OpenFileDialog instance. This returns a read-only stream for loading the data. The example code shown below demonstrates how to do this:
C# Code (WPF Beta 2)
private void OpenFileClick(object sender, RoutedEventArgs e)
{
OpenFileDialog dlg = new OpenFileDialog();
bool? result = dlg.ShowDialog();
if (result == true)
{
using (Stream s = dlg.OpenFile())
{
TextReader reader = new StreamReader(s);
contentsText.Text = reader.ReadToEnd();
}
}
}
The important distinction here is that the un-trusted XBAP can't just open any file it likes, but rather it has to give the user total control of the file selected. The useful thing for developers is that this feature is turned on in even the most restricted permission set, so even XBAPs launched from the internet and not signed with a trusted key will still be able to do this. You can read more about XBAPs and the sandboxed set of features they must operate in here. More general information about XBAPs can be found here.
The OpenFileDialog resides in the Microsoft.Win32 namespace in PresentationFramework.dll, and is very similar to the OpenFileDialog in the System.Windows.Forms namespace (right down to the name of the class), so make sure you're using the correct one.
WPF is a great platform for creating attractive UI. After working with it for some time you may wish to include vector-based graphics in your WPF application, where in the past you might have used icons or a bitmaps. Using vector-based images in your WPF application allows your images to change size in the same way the rest of your WPF application can, without becoming blurry or blocky.
Recently I came across some nice, crisp-looking free vector images created by N.Design Studio in PDF format. I wanted to see how easy it would be to use them in a WPF application. In this article I'm going to describe the process of converting the images to Xaml, and how Xaml vector images can be packaged up for easy re-use. Thanks to the generosity of Nick at N.Design I'll also post all the Xaml source for the images, which can be freely used in your own open-source and commercial WPF applications.
Converting the Images
To embed images as vectors in a WPF application they need to be in Xaml. Currently there are a number utilities and plug-ins available for converting different file formats to Xaml. Most of these are developed by the community, and are at different stages of completeness and currency. As WPF improves in popularity exporting to Xaml from your favorite tool will become easier and more prevalent. I chose to use Mike Swanson'sAdobe Illustrator > Xaml exporter. After installing the Illustrator CS trial version and following the simple install instructions I was able to open the PDFs in illustrator and export them directly to Xaml. Although this conversion was not perfect, it was more than satisfactory for my purposes.
Adding the Images to a Project
I wanted using the images to be as simple as adding a single file to a project, and knowing the names of the individual images. I added all the images as separate resources with their own keys. Use the technique described in this article to include the external resource file in your main application resources.
Using the Images in WPF
To use one of the image resources use the {StaticResource} markup extension, and the name of the image resource. Here is an example that displays an image resource named "Credit-Card" inside a button.
Xaml Code (WPF Beta 2)
<Button Height="75" Width="220" Padding="2">
<StackPanel Orientation="Horizontal">
<ContentControl Template="{StaticResource Credit-Card}" />
<TextBlock FontSize="16" VerticalAlignment="Center" Text="Pay Now!" Margin="3" />
</StackPanel>
</Button>
The button will look like this:
The image resources will resize to fit the available space, and still retain the correct aspect ratio. Here are a number of buttons of different heights with the same image inside them:
This re-sizing requires no additional code or properties to be set by users of the image, and only minimal effort when creating the resource. To achieve the auto-sizing I nested the "raw" image Xaml (produced by Mike Swanson's converter) inside a Viewbox element with the Stretch attribute set to Uniform:
Xaml Code (WPF Beta 2)
<Viewbox Stretch="Uniform">
... <!-- "raw" Xaml - canvases, paths etc go here -->
</Viewbox>
To allow the image resources to be used multiple times the ViewBox (which allowed the images to resize to fit their container) had to be nested inside a ControlTemplate. Objects which derive from FrameworkElement in WPF must normally have a single parent in the tree of WPF objects. Re-using an object deriving from FrameworkElement without first placing it inside a ControlTemplate would result in an error like the following:
Error in markup file 'somefilename.xaml' : Specified element is already the logical child of another element. Disconnect it first.
ControlTemplate allows you to overcome this problem - it has to so that the templates you define for controls like buttons and list boxes etc to be re-used more than once. This technique is described in Chris Sells and Ian Griffiths excellent book Programming Windows Presentation Foundation - p210. After wrapping everything in a ControlTemplate the overall format of all the resources was like the following:
Xaml Code (WPF Beta 2)
<ControlTemplate x:Key="Resource Name">
<Viewbox Stretch="Uniform">
... <!-- "raw" Xaml - canvases, paths etc go here -->
</Viewbox>
</ControlTemplate>
Here are the images and their names (for easy inclusion in your own WPF projects)
Here is the file containing the Xaml code - you are free to use these images created by N.Design Studio in your own projects (both free and commercial) but you are not permitted to re-distribute the Xaml file.
WPF allows you to define pieces of Xaml as resources, and use them in multiple places in your application. This allows us to share things like styles and brushes across our whole application, making it look more consistent and easier to maintain (since changes need only be made in a single place). As applications grow the size of these resource sections can make them more difficult to work with and create contention amongst the development team as different people try to work on the same large resource file. Also we may wish to re-use some resources across different WPF projects. For the same reason it is desirable to split our C# or VB.NET applications into multiple files it is also desirable to do factor out our Xaml resources into multiple files. How can this be accomplished?
Separation of resources across multiple files can be fairly easily done using this technique which I first saw used in Robert Ingebretsen's "SimpleStyles" sample. The technique involves adding external resources to an existing resource (like your application resources, or the resources for a window or pannel) using the MergedDictionaries property of the ResourceDictionary.
Lets walk through a simple example that assumes we have a text block style we want to factor out into a separate file from our application resources. First we create a new Xaml file (in this case called TextStyle.xaml) so that our project structure is as shown
The content of the file is just a ResourceDictionary - and because the ResourceDictionary is the root element in the Xml file we need to define the default namespaces, which you would probably be more used to seeing on a new root-level Window or Page when you create a new Xaml file in Visual Studio. The contents of the resource dictionary is a perfectly normal WPF style.
Xaml Code (WPF Beta 2)
<ResourceDictionary
xmlns="
http://schemas.microsoft.com/winfx/2006/xaml/presentation
"
xmlns:x="
http://schemas.microsoft.com/winfx/2006/xaml
" >
<Style TargetType="{x:Type TextBlock}" x:Key="TextStyle">
<Setter Property="FontFamily" Value="Lucida Sans" />
<Setter Property="FontSize" Value="22" />
<Setter Property="Foreground" Value="#58290A" />
</Style>
</ResourceDictionary>
The second step is to merge this resource stored in an external file into one of the resource dictionaries in our application. For this example we'll merge it in to the Application.Resouces collection (located in the App.xaml file). This is done by adding the elements highlighted below which point to the TextStyle.xaml file we created.
Xaml Code (WPF Beta 2)
<Application x:Class="LearnWPF.FactoringResources.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="Window1.xaml"
>
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="TextStyle.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
<!-- other styles can appear in the resource dictionary too -->
<Style TargetType="{x:Type Button}" x:Key="ButtonStyle">
<Setter Property="Background" Value="#feca00" />
</Style>
</Application.Resources>
</Application>
We can now use the TextBlock style in the TextStyle.xaml file just like any other style in our Application.Resources dictionary
Xaml Snippet (WPF Beta 2)
<StackPanel>
<TextBlock Style="{StaticResource TextStyle}" Text="Sample Text" />
<Button Style="{StaticResource ButtonStyle}" Content="Button" />
</StackPanel>
Not all of your application's window is actually drawn by WPF - In order to integrate with the underlying operating system the border and title bar of WPF windows are still drawn in GDI like other windows. This means that some operations that can be performed on most elements in WPF (like LayoutTransforms and RenderTransforms) cannot be applied to the top-level window element. This also means the rendering of these areas cannot be customized in WPF in the way that normal elements can be using styles or templates. In order to create customized title bars for your windows you have to create a borderless window, and create a title bar yourself in Xaml.
This gets slightly more complicated on Windows Vista, where rendering of form borders and title bars is handled by the Desktop Windows Manager (DWM) which uses a component called MILCore (MIL stands for Media Integration Layer), which calls into DirectX. It turns out WPF uses this same graphics stack to render. WPF's PresentationCore calls into MILCore (which is unmanaged) which then calls into DirectX. While this implementation detail is interesting to know from a programming point of view the outcome is the same on Vista as XP and Windows 2003 - you can't change the appearance of the title bar or scale, skew or rotate your whole windows from WPF using transforms.
Another implication of this is controls on your WPF forms no longer have a window handle (hWnd), since they are not rendered by GDI. Unless you are hosting controls from Windows Forms or MFC the only hWnd in your typical WPF application will be the hWnd of the top-level window. This means UI automation and testing technologies that rely on hWnds to programmatically drive your UI will nolonger work. Fortunately WPF comes with its own UI automation API.
The other region of your WPF windows that will not actually be rendered by WPF are any controls from other presentation frameworks like WindowsForms or MFC that are being hosting inside an HwndHost - they are still rendered by GDI. This also means you can't scale, skew, translate or rotate them using transforms.
In a previous how-to we looked at WPF's styling capabilities. In this example we are going to use styles to change the appearance of an element when the mouse moves over it. This is easily accomplished using a facility in WPF called triggers. Triggers can "watch" certain special object properties in WPF (called dependency properties), and when they change the appearance of the object can be updated. Most properties that WPF UI Elements expose are dependency properties. Triggers can also "fire" based on events, or on changes to data, but for this example we're only going to look at the simple case of an trigger changing as a result of an object property change.
Below is an updated version of the button style we created in a previous how-to. We have added a trigger that is activated when the IsMouseOver property (which the Button object inherits from its parent UIElement) has a value of true.
<Window x:Class="ButtonWithOuterGlow.Window1"
xmlns="
http://schemas.microsoft.com/winfx/2006/xaml/presentation
"
xmlns:x="
http://schemas.microsoft.com/winfx/2006/xaml
"
Title="LearnWPF - Button with Outer Glow" Height="200" Width="400"
>
<Window.Resources>
<Style TargetType="{x:Type Button}">
<Setter Property="Foreground" Value="#58290a" />
<Setter Property="FontFamily" Value="Lucida Console" />
<Setter Property="Background">
<Setter.Value>
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1" >
<LinearGradientBrush.GradientStops>
<GradientStop Color="#feca00" Offset="0.1"/>
<GradientStop Color="#ffe100" Offset="0.4"/>
<GradientStop Color="#feca00" Offset="0.6"/>
<GradientStop Color="Orange" Offset="0.9"/>
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="BitmapEffect">
<Setter.Value>
<OuterGlowBitmapEffect GlowColor="Red" GlowSize="4"/>
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
</Window.Resources>
<Grid Margin="20">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="50"/>
<ColumnDefinition Width="2*"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition/>
</Grid.RowDefinitions>
<Label Content="Field 1" Grid.Column="0" Grid.Row="0"
Height="25"/>
<TextBox Text="Some text goes here" Grid.Column="1"
Grid.Row="0" Height="25"/>
<Button Grid.Column="2" Grid.Row="0" Content="Click me"
Height="25" Margin="5"/>
</Grid>
</Window>
In this example we are changing the appearance of the button by adding an OuterGlowBitmapEffect to the button. This gives the button a colored halo. There are a number of other interesting bitmap effects that can be applied to UI Elements including Blur and DropShadow. The screen-shot below shows the appearance of the button when the mouse moves over it and the trigger is activated.
WPF allows you to specify the appearance of UI elements in a single place, and re-use that "look" in multiple places - either across a form or across your whole application. This mechanism is called styles. They are similar to the styles available in web development in CSS, but more powerful because they can not only be used to change the properties of a UI element (such as a button), they can be used to completely re-define how the control is rendered. They are also declared using XAML, rather than a seperate language like CSS.
The techniques shown below are in no way limited to buttons - you can use styles to change or even completely define the rendering of any WPF controls. The intention with WPF is that controls like button define a behavior, and a default rendering but allow the developer/designer to completely replace the "look" if they wish. For this reason WPF controls are sometimes referred to as "look-less" controls.
Enough theory - how would we use WPF styles to replace the rendering of all the buttons on a form? First lets create a form with two text boxes and two buttons in a grid. We want to define the style for the buttons in a single place and have it automatically applied to the two buttons.
Form XAML Code (Feb 06 CTP):
<Window x:Class="LearnWPF.ButtonStyle.Window1"
xmlns="
http://schemas.microsoft.com/winfx/2006/xaml/presentation
"
xmlns:x="
http://schemas.microsoft.com/winfx/2006/xaml
"
Title="LearnWPF - Changing Elements with Styles"
Width="350" Height="200">
<Grid Margin="20">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200"/>
<ColumnDefinition Width="95"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
</Grid.RowDefinitions>
<TextBox Text="Foo" Grid.Column="0" Grid.Row="0" />
<Button Content="Click Me.." Grid.Column="1" Grid.Row="0"/>
<TextBox Text="Bar" Grid.Column="0" Grid.Row="1" />
<Button Content="Click Me too.." Grid.Column="1" Grid.Row="1"/>
</Grid>
</Window>
On windows XP with the silver theme the window will appear as shown below:
However on Windows XP under the classic windows theme it appears as shown in this second figure:
We can already see that WPF is capable of changing how controls are rendered to suit the context it is running in. So how do we go about defining our own style for the buttons? The following modified version of the form does just that with a Style added to the Resources collection that exists for the window.
Form XAML Code (Feb 06 CTP):
<Window x:Class="LearnWPF.ButtonStyle.Window1"
xmlns="
http://schemas.microsoft.com/winfx/2006/xaml/presentation
"
xmlns:x="
http://schemas.microsoft.com/winfx/2006/xaml
"
Title="LearnWPF - Changing Elements with Styles" Width="350" Height="200">
<Window.Resources>
<Style TargetType="{x:Type Button}">
<Setter Property="Foreground" Value="#58290a" />
<Setter Property="FontFamily" Value="Lucida Console" />
<Setter Property="Background">
<Setter.Value>
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1" >
<LinearGradientBrush.GradientStops>
<GradientStop Color="#feca00" Offset="0.1"/>
<GradientStop Color="#ffe100" Offset="0.4"/>
<GradientStop Color="#feca00" Offset="0.6"/>
<GradientStop Color="Orange" Offset="0.9"/>
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<Grid Margin="20">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200"/>
<ColumnDefinition Width="95"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
</Grid.RowDefinitions>
<TextBox Text="Foo" Grid.Column="0" Grid.Row="0" />
<Button Content="Click Me.." Grid.Column="1" Grid.Row="0"/>
<TextBox Text="Bar" Grid.Column="0" Grid.Row="1" />
<Button Content="Click Me too.." Grid.Column="1" Grid.Row="1"/>
</Grid>
</Window>
The first attribute of the Style that is set is the TargetType, setting this to {x:Type Button} as is being done in the sample above tells WPF that this style should be used for all elements of type Button on the form unless another style is specified explicitly for them. This style sets the Foreground and FontFamily properties of the button to simple values that can be specified in a single string. It also specifies a linear gradient for the Background of the buttons. Because this cannot be specified as a single string the Property Element syntax of WPF is used - when setting a complex property a nested child element is created and the element is given the name of the parent element followed by the name of the property you wish to set. With this style applied the form renders as shown below:
This style merely sets some properties on the button - which we could have achieved ourselves by painstakingly setting properties on all our button controls in XAML. Clearly this approach with styles is better - it declaratively specifies the look we want for our button in a single place. What about going further and totally replacing the way the button renders? We can also do this in a style, be specifying a new Template for the element we want to replace. The Template defines how the element renders itself out. In this modified version of the form below we define a new template for the buttons on our form, which gives us rounded, gel-like buttons.
Form XAML Code (Feb 06 CTP):
<Window x:Class="LearnWPF.ButtonStyle.Window1"
xmlns="
http://schemas.microsoft.com/winfx/2006/xaml/presentation
"
xmlns:x="
http://schemas.microsoft.com/winfx/2006/xaml
"
Title="LearnWPF - Changing Elements with Styles" Width="350" Height="200">
<Window.Resources>
<Style TargetType="{x:Type Button}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch" ClipToBounds="False">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<!-- the background for the button -->
<Rectangle RadiusX="15" RadiusY="10" Grid.RowSpan="2">
<Rectangle.Fill>
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1" >
<LinearGradientBrush.GradientStops>
<GradientStop Color="#feca00" Offset="0"/>
<GradientStop Color="Orange" Offset="0.9"/>
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
</Rectangle.Fill>
</Rectangle>
<!-- the "gel" hilight at the top of the button -->
<Rectangle RadiusX="7" RadiusY="6" Margin="2">
<Rectangle.Fill>
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1" >
<LinearGradientBrush.GradientStops>
<GradientStop Color="#fff399" Offset="0.1"/>
<GradientStop Color="#ffe100" Offset="0.5"/>
<GradientStop Color="#feca00" Offset="0.9"/>
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
</Rectangle.Fill>
</Rectangle>
<!-- place for the content inside the button to be displayed -->
<ContentPresenter Grid.RowSpan="2"
x:Name="PrimaryContent"
HorizontalAlignment="Center" VerticalAlignment="Center"
Margin="{TemplateBinding Padding}"
Content="{Binding Path=Content, RelativeSource={RelativeSource TemplatedParent}}"
/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="Foreground" Value="#58290a" />
<Setter Property="FontFamily" Value="Lucida Console" />
</Style>
</Window.Resources>
<Grid Margin="20">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200"/>
<ColumnDefinition Width="95"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
</Grid.RowDefinitions>
<TextBox Text="Foo" Grid.Column="0" Grid.Row="0" />
<Button Content="Click Me.." Grid.Column="1" Grid.Row="0"/>
<TextBox Text="Bar" Grid.Column="0" Grid.Row="1" />
<Button Content="Click Me too.." Grid.Column="1" Grid.Row="1"/>
</Grid>
</Window>
The appearance of the form is shown below:
If you run the sample you'll see some unfortunate shortcomings with this template - for example it gives no visual indication when the button is clicked however it does demonstrate the power of styles to fully replace the rendering of a control. For a more fully-featured template example (built against the January CTP) you should study Robert Ingebretsen's Orange Shiny Button template which was recently featured on MSDN TV, and for more aesthetically appealing gel buttons have a look at Valentin Iliescu's WPF Aqua Gel button tutorial. For further information on Styles and control templates you should also read chapter 5 of "Programming Windows Presentation Foundation" - this chapter is available for free download.
WPF's content model is usually described as either rich or flexible - but what does the term "content model" mean in this context? Legacy windows programming platforms (MFC,ATL,VB6,Windows Forms etc) had many different types of controls that could be added to UI - buttons, labels, pictures, text boxes, lists etc. Each one of these types of controls usually had a fairly fixed set of things they could display - buttons, labels and text boxes could contain text, picture controls could contain images, lists contained a number of list items, each of which in turn contained text. To go outside this usually involved some effort - either writing a control from scratch that could contain a different type of content, or taking over part of the rendering process and performing some "owner drawing", which was often somewhat involved.
In contrast WPF doesn't make nearly as many assumptions about the types of content you would like to display inside a given control. Content of different kinds can be nested freely inside other elements. The following XAML snippet defines a button. Inside the button is contained some text, an ellipse, a text box and a combo box. Inside the combo box is more text and another ellipse.
XAML (Feb 2006 CTP):
<Button Width="200">
<StackPanel>
<TextBlock>Learn WPF!</TextBlock>
<Ellipse Width="100" Height="40" Fill="#feca00" />
<TextBox Text="this is a text box"></TextBox>
<ComboBox>
<ComboBoxItem>
More text...
</ComboBoxItem>
<ComboBoxItem>
<Ellipse Width="80" Height="20" Fill="#58290A" />
</ComboBoxItem>
</ComboBox>
</StackPanel>
</Button>
Although this example is not the type of functionality that has been required for in any application that I have ever written, it is this flexible way that content can be nested and composed that underpins many of the powerful things that can be done in WPF.