Search code examples
wpfbinding.net-3.5valueconverterbrush

Creating a WPF ValueConverter for a Brush


On the Nerd Plus Art blog today, there was a post about creating WPF Resources for arrows, which the author uses frequently. I have a side project that has Back and Forward buttons, so I thought that the Left and Right arrows would work great on those buttons.

I added the LeftArrow and RightArrow Geometries to my application's resources, and then used them as the content of the buttons:

<Application x:Class="Notes.App"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    StartupUri="Views/MainWindow.xaml">
    <Application.Resources>
        <Geometry x:Key="RightArrow">M0,0 L1,0.5 0,1Z</Geometry>
        <Geometry x:Key="LeftArrow">M0,0.5 L1,1 1,0Z</Geometry>
    </Application.Resources>
</Application>

<Button x:Name="BackButton"
    Padding="5,5,5,5"
    Command="{x:Static n:Commands.GoBackCommand}">
    <Path Data="{StaticResource LeftArrow}" Width="10" Height="8"
        Stretch="Fill" Fill="Black"/>
    </Button>
<Button x:Name="ForwardButton"
    Padding="5,5,5,5"
    Command="{x:Static n:Commands.GoForwardCommand}">
    <Path Data="{StaticResource RightArrow}" Width="10" Height="8"
        Stretch="Fill" Fill="Red" />
</Button>

That worked, except that the arrows were drawn in black regardless of whether the button was enabled or not. So, I created a ValueConverter to go from a bool to a Brush:

class EnabledColorConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter,
        CultureInfo culture)
    {
        bool b = (bool)value;
        return b ? Brushes.Black : Brushes.Gray;
    }

    public object ConvertBack(object value, Type targetType, object parameter,
        CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

(I realize that I should probably use system colors instead of hard coded black and gray, but I just wanted to get this working, first.)

I modified the Fill property of the Path to use my converter (which I created within the application's resources):

<Path Data="{StaticResource LeftArrow}" Width="10" Height="8"
    Stretch="Fill"
    Fill="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=Button}, Path=IsEnabled, Converter={StaticResource EnabledColorConverter}}"/>

Unfortunately, this doesn't work, and I'm not sure why. When I run it, the arrow isn't drawn at all. I checked the Output window in Visual Studio, and no binding errors were displayed. I also verified that the bool is the right value in the converter, based on the whether the button should be enabled or not.

If I change the Path back to a TextBlock (and bind its Foreground property in the same manner as Path.Fill), the text is always drawn in black.

Am I doing something wrong? Why is the Brush returned by my converter not used to render the Path in the button?


Solution

  • Why no just bind the Fill of your Path to the Foreground of the Button?

    <Button x:Name="BackButton"
        Padding="5,5,5,5"
        Command="{x:Static n:Commands.GoBackCommand}">
        <Path Data="{StaticResource LeftArrow}" Width="10" Height="8"
            Stretch="Fill" Fill="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=Button}, Path=Foreground"/>
        </Button>