Thursday, December 12, 2013

Custom Markup Extension

WPF Version 4.0

My inner geek got really excited when I read about Custom Markup Extensions. Over the months I've become used to {binding} and {staticresource} but it never occured to me that I could use {myspecialmarkup} until I read about it. It turns out to be extremely easy - very similar to converters, in fact. Let's walk it through. Start by creating a new WPF application called WPFTest. Make sure the default namespace is also WPFTest because we will refer to it later. Good. Now add a new class file called MarkupExtension, and add a class called MyExtension which derives from MarkupExtension. There are two methods we will add. Look at the complete code below.

Imports System.Windows.Markup
Public Class MyExtension
    Inherits MarkupExtension

    Public Property Parameter As String
    Public Sub New(Parameter As String)
        _Parameter = Parameter
    End Sub
    Public Overrides Function ProvideValue(serviceProvider As System.IServiceProvider) As Object
        Return "You said " & _Parameter
    End Function
End Class

We are going to accept a single string in the constructor and save it to a property. When the XAML is loaded the ProvideValue method is called. We will return "You said " plus the string passed to the constructor. Whatever property is bound to MyExtension will receive this string. To reference our new markup extension we have to add an xmlns and a reference to the extension in MainWindow.xaml. Look at the xaml below...

<Window x:Class="MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:WPFTest"
    Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Label Content="{local:My Thing}"/>
    </Grid>
</Window>

The xmlns:local line tells the xaml that anything starting with local: can be resolved within the WPFTest assembly. When it sees local:My it looks for a class called MyExtension (the Extension is added automatically) in the WPFTest assembly. It will then call the constructor and pass the string 'Thing'. Later on, when it wants to know what value to put in the label's content it calls the ProvideValue method on the object it created earlier.

This explains why the error message you see when you mess up the content of markup refers to the ProvideValue method. Interestingly the only parameter passed to ProvideValue contains the line and column number of the markup that called the Markup Extension. So you can reference the same Markup Extension from many places but the error message can tell you exactly which piece of markup caused the error to be thrown.

No comments:

Post a Comment