Implementing disabled WPF toolbar buttons for Visual Studio 2010

 

If you�ve ever wanted to implement a toolbar in WPF you may have come upon this limitation: you can easily set images for the toolbar buttons, but there is no default way of making these images appear grayed when the toolbar buttons are disabled.

To implement the toolbar buttons and menu items, Visual Studio 2010 uses a custom algorithm to create gray images from the original picture. This is publicly available  for consumption via a converter Microsoft.VisualStudio.PlatformUI.GrayscaleImageConverter, implemented in Microsoft.VisualStudio.Shell.10.0 assembly. The converter takes as input an ImageSource and converts to an Image element that uses for source the grayed out version of the image.

If you need to implement toolbars for your package/dialogs you should strongly consider using shell-implemented toolbars (defined by your application via *.vsct files) and used through IVsToolWindowToolbar/IVsToolWindowToolbarHost interfaces. That guarantees a consistent look of all the buttons, separators or split-buttons in your toolbar with the rest of the shell.

For instance, to display a shell-owned toolbar in a WPF dialog you can use IVsUIShell4.CreateToolbarTray() interface to obtain an IVsToolbarTrayHost, then call AddToolbar() on this object to add the toolbar using the guid of your package and the resource Id of the toolbar in vsct, then get the UIElement representing the toolbar using IVsToolbarTrayHost.GetToolbarTray() and position the element to your liking in the dialog.

 

However, there may be situations when you�ll want to implement your own WPF toolbar buttons. To maintain a consistent grayed out look of disabled buttons you may choose to reuse the GrayscaleImageConverter implemented by the shell. Below I describe a way to do this:

1)  Implement a ToolbarButtonImage class having a Source dependency property. You�ll use this to set the button�s image in the �normal� state.

2) The style of the ToolbarButtonImage class will use a trigger to switch the template of the button�s content when the button gets enabled/disabled between a control template (ToolbarButtonImage_Normal) containing the image in the normal state and a control template (ToolbarButtonImage_Disabled) containing the grayed out image produced by the  GrayscaleImageConverter.

3) Add the buttons to the toolbars as follows:

<ToolBar>
    <Button IsEnabled="{Binding ���.}">
       <local:ToolbarButtonImage Source="Resources\ButtonNormalImage.png"/>
    </Button>
</ToolBar>

Below is the sample code for the ToolbarButtonImage and its style:

----------------------------------------------
ToolbarButtonImage.cs
----------------------------------------------

using
System;

using
System.Windows;

using
System.Windows.Controls;

using
System.Windows.Data;

using
System.Windows.Media;

using
System.Windows.Media.Imaging;


namespace
YourApplicationNamespace 
{ 
    public class ToolbarButtonImage : UserControl
 
    { 
        static ToolbarButtonImage()
        {
              DefaultStyleKeyProperty.OverrideMetadata(
typeof(ToolbarButtonImage),

                                new FrameworkPropertyMetadata(typeof(ToolbarButtonImage)));
        } 

        public
static readonly DependencyProperty SourceProperty = DependencyProperty.Register

                               ("Source", typeof(BitmapSource), typeof(ToolbarButtonImage)); 

        public
BitmapSource
Source
        {
            get
            {
                 return (BitmapSource)GetValue(SourceProperty);
            }
            set

            {
                SetValue(SourceProperty,
value);
            }
        }
    }
}

----------------------------------------------
ToolbarButtonImageStyle.xaml
----------------------------------------------

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:YourApplicationNamespace"

    xmlns:ui="clr-namespace:Microsoft.VisualStudio.PlatformUI;assembly=Microsoft.VisualStudio.Shell.10.0">


<ui:GrayscaleImageConverter x:Key="GrayscaleImageConverter"/>


<ControlTemplate x:Key="ToolbarButtonImage_Normal" TargetType="{x:Type local:ToolbarButtonImage}">

     <Image Width="16" Height="16" Source="{TemplateBinding Property=Source}"/>

</ControlTemplate>


<ControlTemplate x:Key="ToolbarButtonImage_Disabled" TargetType="{x:Type local:ToolbarButtonImage}">

     <ContentPresenter Width="16" Height="16" Content="{TemplateBinding Property=Source, Converter={StaticResource GrayscaleImageConverter}}"/>

</ControlTemplate>


<Style x:Key="{x:Type local:ToolbarButtonImage}" TargetType="{x:Type local:ToolbarButtonImage}">
 
    <Setter Property="Template" Value="{StaticResource ToolbarButtonImage_Normal}"/>

    <Style.Triggers>

        <DataTrigger Binding="{Binding IsEnabled, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Button}}}" Value="False">

            <Setter Property="Template" Value="{StaticResource ToolbarButtonImage_Disabled}"/>

        </DataTrigger>

    </Style.Triggers>

</Style>

</ResourceDictionary>

Previous
Next Post »