0

I am attempting to change a picture when clicking on it in the sidebar menu, but however nothing seem to happen when I click on a image. This is done in WPF and for a image editing program. I have been reading up on custom commands and reading other custom commands posts here on StackOverflow but I can't seem to find anything that apply to this case.

public partial class ImageEditor : UserControl
{
    ICommand changePicture;
    public ICommand ChangePicture 
    { 
        get { return changePicture; }
        set { changePicture = value; } 
    }

    public ImageEditor()
    {
        InitializeComponent();
    }

    public void loadImages(string _imageFile)
    {
        string directory = Path.GetDirectoryName(_imageFile);
        string[] _filePaths = Directory.GetFiles(directory, "*.jpg");
        foreach (string image in _filePaths)
        {
            if (image.Length > 0)
            {
                thumbNails.Children.Add(addPictureButton(image));
            }
        }
    }

    public Button addPictureButton(string image)
    {
        Image currentImage = new Image();
        currentImage.Source = new BitmapImage(new Uri(image));
        currentImage.Stretch = Stretch.Fill;

        Grid grid = new Grid();
        grid.Height = 90;
        grid.Children.Add(currentImage);

        var newButton = new MyButton();
        newButton.Content = grid;
        newButton.Name = "button";
        newButton.Height = 100;
        newButton.Background = Brushes.Chocolate;
        newButton.ImageRef = image;
        newButton.Command = ChangePicture;
        return newButton;
    }
}

I think there is a problem with my custom command, this is the main method where I load all the pictures.

private void Window_Loaded(object sender, RoutedEventArgs e)
{
    /// Get the Handle for the Forms System Menu
    IntPtr systemMenuHandle = GetSystemMenu(this.Handle, false);
    /// Create our new System Menu items just before the Close menu item
    InsertMenu(systemMenuHandle, 5, MF_BYPOSITION | MF_SEPARATOR, 0, string.Empty); // <-- Add a menu seperator
    InsertMenu(systemMenuHandle, 6, MF_BYPOSITION, _SettingsSysMenuID, "Inställningar...");
    InsertMenu(systemMenuHandle, 7, MF_BYPOSITION, _CalibrateSysMenuID, "Kalibrerings Läge (På/Av)");
    InsertMenu(systemMenuHandle, 8, MF_BYPOSITION, _ZoomPrevSysMenuID, "Zoom Läge -1");
    InsertMenu(systemMenuHandle, 9, MF_BYPOSITION, _ZoomNextSysMenuID, "Zoom Läge +1");
    //InsertMenu(systemMenuHandle, 10, MF_BYPOSITION, _PrintSysMenuID, "Print...");

    // Attach our WndProc handler to this Window
    HwndSource source = HwndSource.FromHwnd(this.Handle);
    source.AddHook(new HwndSourceHook(WndProc));

    if (ImageFile != null && ImageFile.Length > 0)
    {
        if (_cameraManager != null)
            _cameraManager.IsPaused = true;

        Bitmap bitmap = new Bitmap(ImageFile);
        UcImageGrabbedControls.SetImageToView(bitmap);
        ImagePicker.loadImages(ImageFile);
        ImagePicker.ChangePicture = new CustomCommand(OnPictureClick);

        BtnGrab.IsToggled = true;

        UpdateShownControls();
    }
}

Button goes here

public void OnPictureClick(object sender)
{
    var button = (UserControls.MyButton)sender;
    if (button == null)
        return;

    var bitmap = new Bitmap(button.ImageRef);
    UcImageGrabbedControls.SetImageToView(bitmap);
}

Custom command implementation

public class CustomCommand : ICommand
{
    //public delegate void ExecutedMethod();
    //private ExecutedMethod method;
    private Action<object> onPictureClick;

    public CustomCommand(/*ExecutedMethod executed*/)
    {
        //method = executed;
    }

    public CustomCommand(Action<object> onPictureClick)
    {
        this.onPictureClick = onPictureClick;
    }

    public event EventHandler CanExecuteChanged;

    public bool CanExecute(object parameter)
    {
        return true;
    }

    public void Execute(object parameter)
    {
        //method();
    }
}
Manfred Radlwimmer
  • 13,257
  • 13
  • 53
  • 62
  • Is the code that's not working is in `OnPictureClick`, which is not included? – Manfred Radlwimmer Oct 31 '17 at 11:16
  • Ah sorry Manfred, that was nothing, just a previous attempt to use it as a event instead, I'm instead using custom commands, edited it out to remove that comment. The code that is not working is the newbutton.command –  Oct 31 '17 at 11:19
  • So where does this one go? `ImagePicker.ChangePicture = new CustomCommand(OnPictureClick);` As far as I understand, you create a new Command, assign it to the `ChangePicture` property of your ImagePicker which is assigned to every Button created via `addPictureButton`. – Manfred Radlwimmer Oct 31 '17 at 11:25
  • I forgot to add that, so I edited that code and put it into the post –  Oct 31 '17 at 11:29
  • Ok, so does the method not get called when you click the button or does it get called but doesn't work? – Manfred Radlwimmer Oct 31 '17 at 11:43
  • Good question, I checked it in the debugger again just to be sure, and the method does never get called –  Oct 31 '17 at 11:51
  • Did you override the `Command` property in your MyButton? What does the `CustomCommand` look like? Do you create the buttons before assigning `ChangePicture` (e.g. in `InsertMenu`)? – Manfred Radlwimmer Oct 31 '17 at 11:58
  • Hmm, thanks a lot for the help Manfred, really appreciating it. Where do I see if command property is overriden and I think the button is created before assigning changepicture. Also added the code for customcommand –  Oct 31 '17 at 12:07
  • *"I think the button is created before assigning changepicture"* Then I think we have found the problem. When you set `newButton.Command = ChangePicture;` in your `addPictureButton` method **before** you assign `ImagePicker.ChangePicture = new CustomCommand(OnPictureClick);` then the command of your button is `null` and nothing can execute. No matter what you assign to `ChangePicture` **after** that, the buttons `Command` will still be `null`. You need to assign it **before** using it while creating the buttons. – Manfred Radlwimmer Oct 31 '17 at 12:18
  • I just double checked to make sure I understand you, first the Window_Loaded method is run, then after that addpicturebutton method is run. Is this what you meant? –  Oct 31 '17 at 12:22
  • That's how it should be, yes. First assign the Command, then use it. If you change the original source later, that does nothing for the buttons. If you want to check if the buttons have a `Command` assigned at runtime, I suggest you get [Snoop](https://github.com/cplotts/snoopwpf) and take a look at the button's properties. – Manfred Radlwimmer Oct 31 '17 at 12:29
  • Unsure what to be looking for with snoop, but I found in datacontext that "object is NULL" currentfocuscope = mainwindow, in button properties it say command = local –  Oct 31 '17 at 12:45
  • Just keep following that trail. When you click a button you expect the following things to happen (in that order): A MouseDown or Click event on your button, the command's `CanExecute` method (must return **true**!), the command's `Execute` method, and then your `OnPictureClick` method. We have already established that your function doesn't get called, so somewhere along this line you have an error or simply missed an assignment. – Manfred Radlwimmer Oct 31 '17 at 12:55
  • A mousedown event happens when clicking the button, handled by button(MyButton), then inside it says (Image) handled false, however I couldn't find the "CanExecute method (must return true!), the command's Execute method, and then your OnPictureClick method". I'm not sure if the mousedown event actually does anything –  Oct 31 '17 at 13:02
  • The `CanExecute` and `Execute` methods must be part of your `CustomCommand` otherwise it wouldn't compile since it has to inherit from `ICommand`. – Manfred Radlwimmer Oct 31 '17 at 13:09
  • Hmm, I'm not sure at all what you mean. What is the canexecute and execute methods? –  Nov 01 '17 at 08:33
  • `CustomCommand` is a class that must inherit from `ICommand` because otherwise you couldn't assign it to the button's `Command` property. The `ICommand` interface requires you to implement two methods: `CanExecute` (if it returns false the button is disabled) and `Execute` which should call you method. Is `CustomCommand` part of a framework you are using or do you have the source-code and can debug it? – Manfred Radlwimmer Nov 01 '17 at 19:10
  • Hey Manfred! I actually found the source code you are telling me about and edited it into the post, sorry for not knowing that much. I'm just an intern that got handed a project that way too many people had been working on, and the last one got fired. –  Nov 02 '17 at 09:17
  • Does it really look *exactly* like that or did you somehow redact it? Cause the `Execute` method is completely empty and can't work like that. It should read (approximately) `onPictureClick.Invoke(parameter);` (why such a generic named command has such specific fields is beyond me - you should rename that to command or action or something) – Manfred Radlwimmer Nov 02 '17 at 09:29

1 Answers1

0

This class looks like a lot of people tinkered with it until it broke, so I removed everything that is no longer in use anyway.

public class CustomCommand : ICommand
{
    private Action<object> onPictureClick;

    public CustomCommand(Action<object> onPictureClick)
    {
        this.onPictureClick = onPictureClick;
    }

    public event EventHandler CanExecuteChanged;

    public bool CanExecute(object parameter)
    {
        return true;
    }

    public void Execute(object parameter)
    {
        // Nothing happening here :(
    }
}

The basic problem is, that the Execute method doesn't do anything - unsurprisingly any button executing this command doesn't do anything either. The simplest fix would be to simply restore functionality to this method by invoking the method passed to the constructor:

public void Execute(object parameter)
{
    onPictureClick.Invoke(parameter);
    // or onPictureClick(parameter)
}

Since you are already working on that method, I suggest you rename the action to something less specific, e.g _action.

If you ever intend (or need) to make use of the CanExecute feature and/or use the CommandParameter I suggest you take a look at a RelayCommand implementation.
(This answer has a detailed explanation).

Manfred Radlwimmer
  • 13,257
  • 13
  • 53
  • 62
  • Thanks Manfred! To answer your earlier comment, yes, that was exactly how the class looked. Still doesn't seem to work though, but I will read up on that link you linked. Seems there are no references to the execute command –  Nov 02 '17 at 11:52