0

My XAML uses a DataContext which is != self.
All of the properties are linked to that DataSource.

I would like to make my "Click" event handler in the DataContext as well, and NOT in the code behind.

I saw some "Commands" solutions, which I'm not familiar with at all, but these looked quite complicated for that tiny need...

Is there any simple solution for that?

MTZ
  • 109
  • 1
  • 12
  • As first option, you can use the commands Another way also would be that, public methods in viewmodel can be called from view event handlers – Ugur Jul 26 '16 at 14:12

1 Answers1

1

The most compact solution possible is using a MarkupExtension to construct a Command on the fly.

<Button Command="{me:CallCommand MyMethod}" />
public class CallCommand : MarkupExtension, ICommand
{
    public string MethodName { get; set; }

    FrameworkElement element;

    public CallCommand() { }

    public CallCommand(string methodName) : this()
    {
        MethodName = methodName;
    }

    public event EventHandler CanExecuteChanged;

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

    public void Execute(object parameter)
    {
        if (MethodName == null) throw new InvalidOperationException($"{nameof(MethodName)} cannot be null.");

        var context = element.GetValue(FrameworkElement.DataContextProperty);
        context.GetType().GetMethod(MethodName).Invoke(context, null);
    }

    public override object ProvideValue(IServiceProvider serviceProvider)
    {
        var target = (IProvideValueTarget)serviceProvider.GetService(typeof(IProvideValueTarget));

        element = (FrameworkElement)target.TargetObject;

        return this;
    }
}
H.B.
  • 166,899
  • 29
  • 327
  • 400
  • This is a great solution. Adding one points here, The Calling method should be `public` and defined in the `ViewModel`. – Abin Jul 26 '16 at 15:19
  • Hi, How do we extend this class to handle CanExecuteChanged and handling parameters from View. – Abin Jul 26 '16 at 15:23
  • 1
    @AbinMathew: You would just add more properties, taking parameters or pointing to methods or events (- and more constructor parameters, if that shorthand is desired -) and do the necessary reflection to call methods/subscribe to the event, it should be fairly straightforward. The only thing that is problematic is doing bindings, which cannot be done on a markup extension itself, one would need to pass in a `DependencyObject` with bindable properties, see e.g. [this](http://stackoverflow.com/questions/6461826/in-wpf-can-you-filter-a-collectionviewsource-without-code-behind/6462282#6462282). – H.B. Jul 26 '16 at 15:51