Introduction
I've been working with WPF for a couple weeks now and it can get pretty frustrating having to figure out how to mimic Windows controls with XAML. I am building a Menu inside my application and I found that when my Button
isn't enabled, the images inside the Button
are not automatically converted to grayscale. Not what your typical Windows Forms developer would expect. So here is what I discovered.
Using the Code
<Window x:Class="KLCardinal.Window1" x:Name="thisForm"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:KLCardinal"
Title="Window1" Height="300" Width="300">
<Window.Resources>
<local:GrayScaleConverter x:Key="grayConv" />
</Window.Resources>
<Grid>
<Button Template="{DynamicResource buttonTemplate}"
IsEnabled="False" Margin="63,111,34,111">
<Button.Resources>
<ControlTemplate x:Key="buttonTemplate" TargetType="{x:Type Button}">
<StackPanel x:Name="stPanel" HorizontalAlignment="Left"
Width="Auto" Height="Auto"
Orientation="Horizontal">
<Image x:Name="img" Width="30" Height="30" Stretch="Fill"/>
<TextBlock FontSize="14" Margin="5,0,0,0"
VerticalAlignment="Center" Text="My Button"
TextWrapping="Wrap"/>
</StackPanel>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Trigger.Setters>
<Setter TargetName="img" Property="Source"
Value="{Binding ElementName=thisForm,
Path=MyButtonImage,
Converter={StaticResource grayConv}}" />
<Setter TargetName="stPanel" Property="BitmapEffect">
<Setter.Value>
<BlurBitmapEffect Radius="1" />
</Setter.Value>
</Setter>
</Trigger.Setters>
</Trigger>
<Trigger Property="IsEnabled" Value="True">
<Trigger.Setters>
<Setter TargetName="img" Property="Source"
Value="{Binding ElementName=thisForm,
Path=MyButtonImage}" />
<Setter TargetName="stPanel" Property="BitmapEffect"
Value="{x:Null}" />
</Trigger.Setters>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Button.Resources>
</Button>
</Grid>
</Window>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
namespace KLCardinal
{
public partial class Window1 : Window
{
public static readonly DependencyProperty MyButtonImageProperty =
DependencyProperty.Register("MyButtonImage", typeof(ImageSource),
typeof(Window1), new UIPropertyMetadata(null));
public ImageSource MyButtonImage
{
get { return (ImageSource)GetValue(MyButtonImageProperty); }
set { SetValue(MyButtonImageProperty, value); }
}
public Window1()
{
try
{
MyButtonImage = new ImageSourceConverter().ConvertFrom
(@"C:\Users\Public\Pictures\Sample Pictures\creek.jpg")
as BitmapSource;
}
catch { }
InitializeComponent();
}
}
}
Now, we want to create our Converter
that will Convert
a BitmapSource
with a Pixel Format
of Brga32
(PNG) or Brg32
(JPG) to a Grayscale Brga32
/Brg32 BitmapSource
.
public class GrayScaleConverter : IValueConverter
{
public object Convert(object value, Type targetType,
object parameter, System.Globalization.CultureInfo culture)
{
if(value is BitmapSource)
{
BitmapSource orgBmp = (BitmapSource)value;
if (orgBmp.Format == PixelFormats.Bgra32)
{
byte[] orgPixels = new byte[orgBmp.PixelHeight *
orgBmp.PixelWidth * 4];
byte[] newPixels = new byte[orgPixels.Length];
orgBmp.CopyPixels(orgPixels, orgBmp.PixelWidth * 4, 0);
for (int i = 3; i < orgPixels.Length; i += 4)
{
int grayVal = ((int)orgPixels[i - 3] +
(int)orgPixels[i - 2] + (int)orgPixels[i - 1]);
if (grayVal != 0)
grayVal = grayVal / 3;
newPixels[i] = orgPixels[i];
newPixels[i - 3] = (byte)grayVal;
newPixels[i - 2] = (byte)grayVal;
newPixels[i - 1] = (byte)grayVal;
}
return BitmapSource.Create(orgBmp.PixelWidth, orgBmp.PixelHeight,
96, 96, PixelFormats.Bgra32, null, newPixels,
orgBmp.PixelWidth * 4);
}
}
return value;
}
public object ConvertBack(object value, Type targetType, object parameter,
System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
History
- 18th December, 2007: Initial post