Table of contents
- Part 1 (XAML): Learn about XAML and how it is used in WPF applications.
- Part 2 (Layout): Learn about layout panels and how they are used to construct user interfaces.
- Part 3 (Data binding): Learn how WPF data binding works and how it can be used.
- Part 4 (Data templates and triggers): Learn how data templates and triggers work and how they can be used.
- Part 5 (Styles): Learn about how UIs can be styled in WPF.
Introduction
This article is the first in a series which reviews some important features of Microsoft's Windows Presentation Foundation (WPF). The entire series barely scratches the surface of the immense WPF platform, and it does not dive too deeply into any particular topic. The purpose of this series is to familiarize the reader with the basic WPF programming model to the point where he/she is comfortable enough with WPF to fully understand the, rather silly, WPF Horse Race application (available for download via a link at the top of this page).
The subject matter is presented in the context of a completely impractical horse racing application, as seen in the screenshot above. The application was designed with the intention of being used as the focal point of this series. I tried to find the right balance between making the demo application simple enough to be understandable to a WPF newcomer, yet complicated enough to actually do something interesting (or at least mildly amusing).
Prerequisites
In order to run a WPF application you need the .NET Framework version 3.0, or greater. Windows Vista has the .NET Framework v3.0 installed by default, so you only need to install it if you have Windows XP SP2.
To develop WPF applications you should have Visual Studio 2005 with the "Orcas" extensions, or a later version of Visual Studio, and also the Windows SDK. Refer to the External Links section at the end of this article for links to relevant resources.
What is XAML?
XAML stands for eXtensible Application Markup Language. It is an all-purpose XML-based language used for declaring object graphs, which are instantiated at runtime. XAML is used by WPF developers to declare the layout of a user interface (UI), and the resources used in that UI.
It is not at all necessary to use XAML when programming in WPF. Anything that can be done in XAML can also be done in code. Using XAML makes many UI development scenarios much easier and faster, such as creating the layout of a UI and configuring styles, templates, and other WPF-specific entities discussed later in this series.
Performance impact
When you compile a WPF application in Visual Studio it will compile your XAML files into a compressed representation known as Binary Application Markup Language (BAML). The BAML is then saved as a resource in the resultant assembly. When that assembly is loaded and the resource is requested, the BAML is streamed out and very quickly turned into the object graph described by the original XAML.
This two-step process allows the XAML parsing to occur at compile time, thus mitigating the performance overhead of using a text-based object instantiation technology. With that said, it is possible to load XAML programmatically via the XamlReader.Load method. Dynamically loading XAML can be useful in a variety of situations, such as when a volatile portion of your UI is periodically downloaded from a server via XML Web services.
Basic syntax
Since XAML is an XML-based language, it should be quite simple and straightforward for anyone with XML experience. There are two different uses for XML elements in XAML; elements that represent objects and elements that represent properties of objects. An XML attribute always represents a property or event of an object. That's it; it is that simple. There are a few other concepts built on top of those fundamentals, but XAML never becomes complicated.
For example:
<Button Content="Click Me" Click="OnButtonClick">
<Button.Background>
<LinearGradientBrush>
<GradientStop Color="Yellow" Offset="0" />
<GradientStop Color="Green" Offset="1" />
</LinearGradientBrush>
</Button.Background>
</Button>
That XAML results in a funky little button, which is rendered like this:
Let's dissect that XAML to see how it works. The <Button> element declares that an instance of the Button class will be created. That Button object will have its Content property set to the string "Click Me". The Button's Click event will be handled by a method called OnButtonClick in the code-behind file (we'll get into code-behind files soon).
The next element is <Button.Background>, which is said to use the "property element syntax". That XML element represents the Background property of the Button being configured. The child element of a property element is the value to which the property is set. In this case, the Background property is set to a LinearGradientBrush object.
That brush has two <GradientStop> child elements, which might seem confusing at first. What are those GradientStop objects doing there? What are they being assigned or added to? The answer lies in the fact that XAML has some "shortcuts" built in which allow you to specify a property on a class which is considered to be the "content property." You do not need to use the property element syntax to assign a value to the "content property" of a class. Since LinearGradientBrush's content property is the GradientStops property, the following XAML is equivalent to that seen above:
<Button Content="Click Me" Click="OnButtonClick">
<Button.Background>
<LinearGradientBrush>
<LinearGradientBrush.GradientStops>
<GradientStop Color="Yellow" Offset="0" />
<GradientStop Color="Green" Offset="1" />
<LinearGradientBrush.GradientStops>
</LinearGradientBrush>
</Button.Background>
</Button>
The C# version
In case you are curious about what that XAML would look like if it was written in C#, here's the translation:
Button b = new Button();
b.Content = "Click Me";
b.Click += this.OnButtonClick;
LinearGradientBrush lgb = new LinearGradientBrush();
lgb.GradientStops.Add( new GradientStop( Colors.Yellow, 0 ) );
lgb.GradientStops.Add( new GradientStop( Colors.Green, 1 ) );
b.Background = lgb;
Markup extensions
The XAML parser also knows how to work with a special construct known as the "markup extension." Markup extensions allow you to compactly configure objects and reference other objects defined elsewhere in the application. They are used when setting a property on an object, either via an XML attribute or the property element syntax. Markup extensions are used for things such as specifying a null value, declaring an array, referencing an object held in a resource dictionary, binding one property to another, and much more.
The following XAML is roughly equivalent to the example shown previously (with a few minor changes):
<Grid>
<Grid.Resources>
<LinearGradientBrush x:Key="FunkyBrush">
<GradientStop Color="Yellow" Offset="0" />
<GradientStop Color="Green" Offset="1" />
</LinearGradientBrush>
</Grid.Resources>
<Button Background="{StaticResource FunkyBrush}">Click Me</Button>
</Grid>
Notice that the Button's Background property is set, via an XML attribute, to {StaticResource FunkyBrush}. When an attribute is set to a value which begins with { and ends with }, then a markup extension is being used.
In this case the StaticResourceExtension class is being used to reference a LinearGradientBrush stored in the Grid's resource dictionary. (Note: Grid is a layout panel in WPF, not a tabular data presentation control like you might expect.)
Code-behind files
XAML is compiled down into a class. Unless you specify the class name it should use, the compiler will generate a class name for you. However, when you apply the x:Class attribute to the root XML element in a XAML file, you can create a partial class in C# or VB.NET which will be merged with the XAML partial. This is how you can associate behavior with the layout and visuals declared in XAML.
For example, in the demonstration above we created a Button in XAML and assigned an event handling method to its Click event. The OnButtonClick method would be defined in the code-behind file which contains another part of the class associated with the partial class generated by the XAML.
Let's suppose that the Button we've been discussing is in a Window subclass called MyWindow. Here would be the code-behind file (MyWindow.xaml.cs):
public partial class MyWindow : Window
{
public MyWindow()
{
InitializeComponent();
}
void OnButtonClick( object sender, RoutedEventArgs e )
{
MessageBox.Show( "Click me again. That felt good." );
}
}
How the WPF Horse Race uses XAML
The WPF Horse Race application is almost entirely written in XAML. The application uses three C# files: the code-behind for the main Window, a file for the RaceHorse class, and another which contains some value converters (more on those in the article about data binding). The rest of the application is all in XAML.
I encourage you to explore the WPF Horse Race source files and check out what XAML looks like when it's being used to create a real program (as opposed to just a simple demonstration of it). The rest of the articles in this series will examine how that entire application works, but there is no substitute for just digging into the source files now and exploring how it works on your own.
External links
Prerequisites
XAML
General WPF Tips
History
- April 1, 2007 - Created the article.
- April 3, 2007 - Removed superfluous
ColumnDefinitions from the Grid in RaceHorseDataTemplate.xaml and updated the demo project download file.
- April 18, 2007 - Fixed an incorrect statement about markup extensions. Originally I asserted that they are only used in conjunction with XML attributes, but they can be used with the property element syntax, as well.
|
|
 |
 | Very Good Abhishek Sur | 10:15 8 Nov '09 |
|
 |
I started learning WPF recently. Its the most basic one and also very clear.
Thanks for this lovely series Josh.
|
|
|
|
 |
 | thanks zhujinlong19840913 | 2:53 27 Aug '09 |
|
|
 |
 | J.S. Bach! Clay Shannon | 10:02 18 Jun '09 |
|
 |
Yes! J.S. Bach rocks!! er...well, I can't picture him in a combo with Ted Nugent, actually, but his music is awesome nevertheless. How about, "J.S. Bach classicals!"? It doesn't have the same ring to it.
|
|
|
|
 |
 | great article! sth_Weird | 4:03 17 Jun '09 |
|
 |
Thanx for this article! I'm rather new to wpf, so far I've only used c# .NET 2.0 and used a lot of owner drawing to make the guis look nice. I was so happy to find out it's so much "quicker" to do in wpf, but most beginners guides show controls that do not look very impressive and those controls that do are advanced. Your example is a good compromise, it looks professional but it easy enough to understand for somebody who does not have much experience yet. Totally off topic, but I noticed you are using regions in you code...ha! There are so many region-haters on the net, claiming their only use is hiding smelly code or too long classes, I sometimes feel guilty using them. But you're using them too and I do consider you an experienced programmer. I use them the way you did, to group constructors, properties, methods, interface implementations, events.
|
|
|
|
 |
 | Why does the app change my screen resolution when run in VS2008 CrashMigo | 5:46 1 Dec '08 |
|
 |
For some reason when I run this app from VS 2008 it changes my screen resolution to 640x480
|
|
|
|
 |
|
 |
CrashMigo wrote: For some reason when I run this app from VS 2008 it changes my screen resolution to 640x480
I have no idea. That's really weird.
|
|
|
|
 |
|
 |
It's inconsistent happens a couple times run it again and it doesn't....weird.
|
|
|
|
 |
 | Hi Josh Santhapur | 5:20 7 Aug '08 |
|
 |
Thanks for your article .. I would like to is there any Textbook that you can suggest for the Begineers and to learn WPF step by step..
Santhapoor
|
|
|
|
 |
|
 |
Santhapur wrote: I would like to is there any Textbook that you can suggest for the Begineers and to learn WPF step by step..
I am not aware of any textbooks that teach WPF. There are plenty of WPF books our there, but not textbooks (as in, books used to teach courses).
|
|
|
|
 |
|
 |
Which one do u suggest in those plenty? or are there any Video tutorials websites other than www.WIndowsclient.net
|
|
|
|
 |
|
 |
Santhapur wrote: Which one do u suggest in those plenty?
I liked reading Chris Anderson's Essential WPF, and Adam Nathan's WPF Unleashed. I haven't read all of the WPF books out there, so take my recommendations with that in mind.
|
|
|
|
 |
|
|
 |
 | Wonderful. MAHorn | 11:44 28 Jul '08 |
|
 |
Thank you for sharing so many insights and tidbits of WPF. I very much enjoy reading all your WPF articles.
I wonder if you might have some ideas on the following problem. I have a third party ActiveX Control that I am currently embedding in a WinForm. The ActiveX Control exposes an API that allows me to request streaming video (MJPEG, MPEG, etc...) from a server componenent of the vendor. I do not have access to the live stream under the hood; i.e., I do not, in general, have access to the video frames as they come into the ActiveX Control.
I would like to place an overlay on top of the ActiveX Control streaming video content. Under WinForms I can do this in a limited fashion, and the solution I have is lacking in several respects. However, my initial readings suggest this problem may be completely solved with WPF.
I have made it passed hosting the ActiveX Control in a WPF Form, and I can get video streaming to the host. All that is left is adding an overlay.
Again, thank you for your articles, and any advice you may have on my problem is greatly appreciated.
|
|
|
|
 |
|
 |
Hi MAHorn,
If by adding an overlay on the video, you mean adding some WPF visual on top, you might find this difficult to do cleanly with an ActiveX. Any Win32 control hosted in WPF is subject to the "interop airspace rules" (http://msdn.microsoft.com/en-us/library/aa970688.aspx[^]. Simply put, you cannot put WPF content on top of anything, but other WPF content. There have been a few interesting workarounds, but nothing that doesn't largely increase complexity for a simple problem.
There may be hope though depending what type of 3rd party system (and libraries) you are dealing with. For instance, if you are dealing with an Axis webcam ActiveX, I have been able to get video directly into WPF because they supply DirectShow filters. If the 3rd party system has standard streaming protocols and formats, it may also be possible to directly stream the video in WPF via MediaElement...sometimes with a few extra CODECs installed.
Feel free to email me at jeremiah.morrill [at] gmail.com or reply here and I'll see if we can't get this workin for you!
-Jer
|
|
|
|
 |
|
 |
Hi Jer,
Thank you for the response.
Unfortunately, I can only assume the streaming video is available at the managed level, and thus I do not have access to the stream [although several of these vendors do offer unmanaged API's to the stream using Direct Show as you suggested.] I also cannot access the cameras directly, or any technology offered by the camera manufacturer. I must go through the vendor based servers via the ActiveX control.
The hurdle is now appearing steeper than I first thought. As it stands, WPF does not appear to natively support ActiveX Controls so I must embed the control in a WinForm (or another lower level .NET Control) and then host the WinForm in my WPF Form. That's just to get the streaming video in the WPF context. The overlay now must work in this arrangement. The MSDN "airspace rules" link does explain some of that, but it is still all a little blurry. [I thank you for that link.]
I think this problem can be studied by hosting MediaPlayer in a WPF Form, for example, and placing an overlay on the streaming video without using any built in overlay features of MediaPlayer (only .NET related technologies.) A worthy problem, and I would give a 5 to that project for sure.
Thanks again for you time and help.
|
|
|
|
 |
|
 |
Yeah, using the WindowsFormsHost class is probably the easiest way to get an ActiveX into WPF. There is also the HwndHost class, but that would probably be more unneeded complexity...and certainly won't fix your airspace issue.
If you are stuck with an ActiveX, you really don't have many options. One option is to create a layered WPF window (AllowsTransparency=True) that is always ontop of your ActiveX area. You can get a library that does this here (but shows it done with a D3D content) http://blogs.msdn.com/pantal/archive/2007/07/31/managed-directx-interop-with-wpf-part-2.aspx[^]
-Jer
|
|
|
|
 |
|
|
 |
 | can we develop an application in WPF Member 3665753 | 0:17 4 Jul '08 |
|
 |
hi josh
I am new to WPF and i am little bit confused after reading documents about WPF. Can we develope a full fledged application using WPF. Do we get all advantages to a WPF application like the one developed using the traditional windows forms.
For example there is no datagridview in WPF. So how can we display data with datagridview properties and events.
thanks Praveen
|
|
|
|
 |
|
 |
Yes, you can create complete applications that rely on WPF for the front end. That's its purpose. There are already many companies doing exactly that. They are using third-party datagrids, but if you really prefer to use a datagrid by Microsoft, they are building one.
:josh: My WPF Blog[ ^] All of life is just a big rambling blog post.
|
|
|
|
 |
 | 'Specified cast is not valid.' when looking at the XAMl Member 2375577 | 9:55 27 May '08 |
|
 |
Downloaded your solution.
Window1.xaml file shows the above in the design.
Stack Trace: at WpfHorseRace.RaceHorseProgressIndicatorWidthConverter.Convert(Object[] values, Type targetType, Object parameter, CultureInfo culture) in C:\Sandbox\WPF\WpfHorseRace\WpfHorseRace\WpfHorseRace\ValueConverters.cs:line 37 at System.Windows.Data.MultiBindingExpression.TransferValue() at System.Windows.Data.MultiBindingExpression.Transfer() at System.Windows.Data.MultiBindingExpression.UpdateTarget(Boolean includeInnerBindings) at System.Windows.Data.MultiBindingExpression.AttachToContext(Boolean lastChance) at System.Windows.Data.MultiBindingExpression.MS.Internal.Data.IDataBindEngineClient.AttachToContext(Boolean lastChance) at MS.Internal.Data.DataBindEngine.Task.Run(Boolean lastChance) at MS.Internal.Data.DataBindEngine.Run(Object arg) at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Boolean isSingleParameter) at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Boolean isSingleParameter, Delegate catchHandler)
The application runs. ? i have is that is it possible to place break points in the xaml which may be causing this error?
|
|
|
|
 |
|
 |
Look at the fix posted in this message board by RHarding_1
:josh: My WPF Blog[ ^] All of life is just a big rambling blog post.
|
|
|
|
 |
|
 |
Replace in ValueConvert.cs the class RaceHorseProgressIndicatorWidthConverter with the code below to fix this for VS 2008. When you build the solution and reload the XAML file you should be able to see the screen design.
public class RaceHorseProgressIndicatorWidthConverter : IMultiValueConverter { public object Convert( object[] values, Type targetType, object parameter, CultureInfo culture ) { if (values == null || values.Length < 2) return false; if (!(values[0] is int)) return false; if (!(values[1] is double)) return false;
int percentComplete = (int)values[0]; double availableWidth = (double)values[1]; double width = Math.Floor( availableWidth * (percentComplete / 100.0) ); return percentComplete == 100 ? width - 4 : width; }
|
|
|
|
 |
 | XAML typo Richard Albury | 9:16 5 May '08 |
|
 |
In the second sample block, the second <LinearGradientBrush.GradientStops> should be </LinearGradientBrush.GradientStops>
|
|
|
|
 |
|
 |
Good catch. Thanks.
:josh: My WPF Blog[ ^] All of life is just a big rambling blog post.
|
|
|
|
 |
 | thanks. I so like your article :) Member 2256708 | 22:17 21 Mar '08 |
|
 |
cuts straight to the chase
|
|
|
|
 |
|
|