Friday, July 22, 2011

Custom Markup Extension in WPF


WPF allows us to create our own custom Markup Extension. In XAML we can use markup extension inside curly braces { } for e.g. {Binding}, {StaticResource} etc. These markup extensions are provided by WPF. We create our own custom markup extension by deriving MarkupExtension class available in System.Windows.Markup namespace. In this post I will explain how to create a custom Markup Extension using simple example.

Simple steps to create custom markup extension
  1. Create a Class and derived it from MarkupExtension class.
  2. Override ProvideValue method of MarkupExtension class in your class.
  3. Return value from ProvideValue method after doing processing.

XAML
<TextBlock Margin="10" HorizontalAlignment="Center"
    Text="{local:FullNameExtension FirstName=Mitesh, LastName=Sureja}" />

Similarly this can be written as,

<TextBlock Margin="10" HorizontalAlignment="Center">
   <TextBlock.Text>
      <local:FullNameExtension FirstName="Mitesh" LastName="Sureja" />
   </TextBlock.Text>
</TextBlock>

Code
public class FullNameExtension : MarkupExtension
{
    public string FirstName { get; set; }
    public string LastName { get; set; }

    public FullNameExtension() { }

    public FullNameExtension(string firstName, string lastName)
    {
        FirstName = firstName;
        LastName = lastName;
    }
       
    public override object ProvideValue(IServiceProvider serviceProvider)
    {
        return LastName + ", " + FirstName;
    }
}











ProvideValue method is not using serviceProvider (IServiceProvider) object. We can utilize this object to get Target Element and Target Property. GetService method of IServiceProvider interface returns IProvideValueTarget and IProvideValueTarget interface provides TargetObject and TargetProperty. Using this target property we can covert and return our value to target type. Let’s have a look on below modified code which uses IServiceProvider object inside ProvideValue method.

public override object ProvideValue(IServiceProvider serviceProvider)
{
    IProvideValueTarget ipValueTarget =
        serviceProvider.GetService(typeof(IProvideValueTarget)) as IProvideValueTarget;
    if (ipValueTarget == null) return null;

    //Get target element
    FrameworkElement targetElement = ipValueTarget.TargetObject as FrameworkElement;

    object length = LastName.Length + FirstName.Length;

    //Get target property
    DependencyProperty dp = ipValueTarget.TargetProperty as DependencyProperty;
    length = Convert.ChangeType(length, dp.PropertyType);

    return length;
}

In above example, I demonstrated simple way to use IServiceProvider and IProvideValueTarget in ProvideValue method but more complex scenarios could be possible.


Related Links –

1 comment: