Click here to Skip to main content
15,885,141 members
Articles / Desktop Programming / WPF

Making WPF Images ICommand Aware

Rate me:
Please Sign up or sign in to vote.
4.43/5 (4 votes)
24 Jan 2012CPOL1 min read 15.9K   2   2
Here's a quick post to show how to make images (and any other framework element) react to an ICommand when clicked.

Here’s a quick post to show how to make images (and any other framework element) react to an ICommand when clicked.

I used to get this question quite a lot from developers using WPF for the first time. They’d get the bit about a button being able to run commands when pressed, but when it came to images, etc., they quickly found that there was no support for it. Of course, you could go down the route of replacing the ContentTemplate for a button and achieving the same thing.

But, as you’ll know (or find out), there’s more than one way to skin a cat in WPF. Anyway, I thought I’d share another way and then you can choose to use it or another way, at least you have the options.

I simply created a new WPF application and then added the following classes:

C#
public static class ClickCommand
{
    public static readonly DependencyProperty CommandProperty =

    DependencyProperty.RegisterAttached("Command",
    typeof(ICommand),
    typeof(ClickCommand),
    new FrameworkPropertyMetadata(OnCommandChanged));

    public static readonly DependencyProperty CommandParameterProperty =
    DependencyProperty.RegisterAttached(
    "CommandParameter",
    typeof(object),
    typeof(ClickCommand));

    public static readonly DependencyProperty IsEnabledProperty =
    DependencyProperty.RegisterAttached(
    "IsEnabled",
    typeof(bool),
    typeof(ClickCommand));

    public static void SetCommand(DependencyObject element, ICommand value)
    {
        element.SetValue(CommandProperty, value);
    }

    public static ICommand GetCommand(DependencyObject element)
    {
        return (ICommand)element.GetValue(CommandProperty);
    }

    public static void SetCommandParameter(DependencyObject element, object value)
    {
        element.SetValue(CommandParameterProperty, value);
    }

    public static object GetCommandParameter(DependencyObject element)
    {
        return element.GetValue(CommandParameterProperty);
    }

    public static void SetIsEnabled(DependencyObject element, bool value)
    {
        element.SetValue(IsEnabledProperty, value);
    }

    public static bool GetIsEnabled(DependencyObject element)
    {
        return (bool)element.GetValue(IsEnabledProperty);
    }

    private static void OnCommandChanged
    (DependencyObject obj, DependencyPropertyChangedEventArgs args)
    {
        var frameworkElement = obj as FrameworkElement;
        frameworkElement.PreviewMouseLeftButtonUp -= PreviewMouseLeftButtonUp;
        frameworkElement.PreviewMouseLeftButtonUp += PreviewMouseLeftButtonUp;

        var command = GetCommand(frameworkElement);

        SetIsEnabled(frameworkElement, command.CanExecute(null));

        command.CanExecuteChanged += (s, e) =>
        {
            SetIsEnabled(frameworkElement, command.CanExecute(null));
        };
    }

    private static void PreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
    {
        var obj = sender as DependencyObject;

        var command = GetCommand(obj);

        if (command != null)
        {
            command.Execute(GetCommandParameter(obj));

            e.Handled = false;
        }
    }
}

This class effectively defines some dependency properties for the Command, Command Parameter and Is Enabled. When the Command property changes, it attaches to the mouse click events and when triggered, simply executes the command with any CommandParameter that was attached.

The XAML looks like this:

XML
<Window
    x:Class="WpfApplication5.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:WpfApplication5"
    Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Image
            Source="/WpfApplication5;component/the-angry-programmer.png"
            Width="200"
            Height="200"
            Cursor="Hand"
            local:ClickCommand.Command="{Binding ImageClickCommand}"/>
    </Grid>
</Window>

As you can see, the Command dependency property is set to a binding of the DataContext’s ImageClickCommand. This is the command that will be run when the image is clicked on.

For a demonstration of it in action, please download the code from here.

This article was originally posted at http://tap-source.com?p=225

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior) NoProblem Software Ltd
United Kingdom United Kingdom
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
QuestionLiked it, but... Pin
Calvin1128-Jan-12 13:08
Calvin1128-Jan-12 13:08 
AnswerRe: Liked it, but... Pin
SteveAdey7-Feb-12 4:22
SteveAdey7-Feb-12 4:22 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.