MarkupExtension

The MarkupExtension is the base class for things like StaticResource, DynamicResource, Binding and so on. It basically allows derived classes to participate in XAML more like a first class citizen.

For example, everyone and their dog has written a BooleanToVisibilityConverter (or those less prone to reinventing the wheel will have used something similar from one of the many WPF/XAML frameworks). But for the sake of this post let’s create one again.

public class BooleanToVisibilityConverter : IValueConverter
{
   public object Convert(object value, Type targetType, object parameter,
                         CultureInfo culture)
   {
      bool result = (value is bool?) ?
                         ((bool?) value).GetValueOrDefault(false) :
                         false;
      if(value is bool)
      {
         result = (bool) value;
      }
      return result ? Visibility.Visible : Visibility.Collapsed;
   }

   public object ConvertBack(object value, Type targetType, object parameter,
                             CultureInfo culture)
   {
      return (value is Visibility) ? (Visibility) value == Visibility.Visible : false;
   }
}

Now to use this in XAML we need to declare it within a ResourceDictionary

<Controls:BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />

and to use we do the following

<Button Content="Cancel" Visibility="{Binding IsCancelVisible, 
    Converter={StaticResource BooleanToVisibilityConverter}}" />


There’s absolutely nothing wrong with this approach, but we could alter things slightly by deriving the BooleanToVisibilityConverter from MarkupExtension as per the following

public class BooleanToVisibilityConverter : MarkupExtension, IValueConverter
{
   public override object ProvideValue(IServiceProvider serviceProvider)
   {
      return this;
   }

   // previous code unaltered
}

Now we can remove the entry from the ResourceDictionary and alter the usage in the XAML for the button declaration to

<Button Content="Cancel" Visibility="{Binding IsCancelVisible, 
   Converter={Controls:BooleanToVisibilityConverter}}">


Well you may be thinking that all you gained was the removal of the ResourceDictionary line in the XAML, but actually we’ve now opened up the BooleanToVisibilityConverter to allow it to be more like built in XAML elements.

One thing you might find with alternate BooleanToVisisbilityConverters is that they either use Visibility.Collapsed or Visibility.Hidden for false. Obviously these two Visibility values differ (collapsed allows the parent layout to use the space where a component is collapsed, hidden means the component still takes up space in the layout but is now invisible).

So it’d be nice if out BooleanToVisibilityConverter could have false assigned to either Visibility.Collapsed or Visibility.Hidden depending upon our specific requirement.

So we can change our BooleanToVisibilityConverter source to

public class BooleanToVisibilityConverter : MarkupExtension, IValueConverter
{
   public BooleanToVisibilityConverter()
   {
      WhenFalse = Visibility.Collapsed;
   }

   public BooleanToVisibilityConverter(Visibility whenFalse)
   {
      WhenFalse = whenFalse;
   }

   [ConstructorArgument("WhenFalse")]
   public Visibility WhenFalse { get; set; }

   public override object ProvideValue(IServiceProvider serviceProvider)
   {
      return this;
   }

   public object Convert(object value, Type targetType, object parameter,
                         CultureInfo culture)
   {
      bool result = (value is bool?) ?
                        ((bool?) value).GetValueOrDefault(false) :
                        false;
      if(value is bool)
      {
         result = (bool) value;
      }
      return result ? Visibility.Visible : WhenFalse;
   }

   public object ConvertBack(object value, Type targetType, object parameter,
                             CultureInfo culture)
   {
      return (value is Visibility) ?
                (Visibility) value == Visibility.Visible : false;
   }
}

As you see we’ve now added a new property, WhenFalse, and defaulted this in the constructor and ofcourse altered the return in the Convert method to return WhenFalse when the boolean is false. The ConstructorArgumentAttribute and the non-default constructor are not actually required for this to work, but are here for serialization.

In XAML we now simply declare our button as

<Button Content="Cancel" Visibility="{Binding IsCancelVisible, 
    Converter={FolderViewer:BooleanToVisibilityConverter 
    WhenFalse=Collapsed}}">