-1

I have a view with an image that has a tap gesture bound to a command:

VIEW:

var clickableImage = new Image(...);
var imageTap = new TapGestureRecognizer();
clickableImage.GestureRecognizers.Add(imageTap);
imageTap.SetBinding<MyViewModel>(TapGestureRecognizer.CommandProperty, _ => _.MyCommand);

The command is in the view model like this:

VIEW MODEL

public ICommand MyCommand
{
    get
    {
        return new Command((parameters) =>
        {               
            // Can I access imageTap element here?
        });
    }
}

Is there any way to access the imageTap element from within the command that it's bound to?

Tseng
  • 61,549
  • 15
  • 193
  • 205
jbyrd
  • 5,287
  • 7
  • 52
  • 86
  • 2
    Whoever downvoted - please tell me why. I don't learn anything if you downvote without explanation. – jbyrd Apr 07 '16 at 16:40
  • Others have posted solutions on how you can achieve this with command parameter, I will just add that you should probably rethink why you are doing this in the first place. The command is located inside the ViewModel, the ViewModel should not have any knowledge of your view, only the other way around. MVVM has clean separation of these layers and you are walking all over that if you pass references to the image or depend on the Xamarin.Forms namespace at all in the view model – irreal Apr 07 '16 at 17:59
  • @irreal - so, I have a custom element (basically a block with an icon, and various bits of text) that has 4 variations. Based on the variation, I want the command to do slightly different things - therefore, the command needs to know what variation my custom element is. By passing the element into the command parameter, I can do that. Does that make sense now, or do you still think my approach is problematic? – jbyrd Apr 07 '16 at 18:08
  • I still think it's problematic. Your viewmodel should contain your logic state. Your description is a bit too generic, but in general, your viewmodel should contain it's state data and it's functions (commands) that work with that data. The view can then read the state data and display it accordingly, and also call the commands to act on it. View should only hold state data which has NO impact on application logic. Such as the active tab, animation progression, etc. – irreal Apr 07 '16 at 18:35
  • I am new to MVVM, so I wouldn't be surprised if my approach isn't quite right. But, let me give you a more specific example of the kind of thing I'm trying to do. Let's say I have 4 buttons. Clicking on each of those buttons calls a custom popup modal (not Navigation.PushModalAsync(), but the kind where you can see the current page dimmed in the background, and you have a popup on top of that), but each modal would display different content based on the button you click. I mean I could have 4 different commands. But why can't I just have 1 command and pass a parameter in? – jbyrd Apr 07 '16 at 19:05
  • Of course you can pass a parameter, you just pass a meaningful business parameter, not a view control! Also, if it is only about displaying a popup, without any other business logic of any sort occuring, you shouldn't even need to use commands at all, your buttons should handle view logic (page code behind, for instance) to display the popup which is bound to the appropriate VM properties. This is literally the only valid use for code behind C# code - manipulating visual state and visual logic of the app. – irreal Apr 12 '16 at 11:00
  • I see - yup, makes sense - thanks, @irreal – jbyrd Apr 20 '16 at 17:15

2 Answers2

1

Yes, you can make use of command parameter.

You can refer this answer/post from one our engineers on Forms team. https://stackoverflow.com/a/25914911/85606

imageTap.SetBinding<MyViewModel>(TapGestureRecognizer.CommandProperty, _ => _.MyCommand);
//Command parameter
imageTap.SetBinding<MyViewModel>(TapGestureRecognizer.CommandParameterProperty, _ => imageTap);

The CommandParameter is another bindable property on the TapGestureRecognizer, you can set it on another line.

Community
  • 1
  • 1
Prashant Cholachagudda
  • 13,012
  • 23
  • 97
  • 162
  • Hmm, what would that look like in C# code (vs. XAML)? And inside the command itself, how would I refer to the bound element? – jbyrd Apr 07 '16 at 16:22
  • When I try that, I get an error "Specified cast is not valid", directly related to the CommandParameterProperty line. – jbyrd Apr 07 '16 at 18:25
1

To explain a little bit more thoroughly, when you're using the CommandParameter, the object you bind to gets passed in as the parameter for your Command's Action when it is run. You then have to cast the parameter to the desired type to be able to use it or modify it.

For instance, if you wanted to get a reference to the Image element from within your Command you would set up you Control like so:

var clickableImage = new Image (...);
var imageTap = new TapGestureRecognizer();
clickableImage.GestureRecognizers.Add(imageTap);
imageTap.SetBinding<MyViewModel>(TapGestureRecognizer.CommandProperty, _ => _.MyCommand);
imageTap.SetBinding<MyViewModel>(TapGestureRecognizer.CommandParameterProperty, _ => clickableImage); // clickableImage will be passed to MyCommand when it is run

Then in your MyViewModel class, you would set up your Command like so:

public ICommand MyCommand
{
    get
    {
        return new Command((parameter) => // the bound parameter (the Image element in this case) is passed in as an object
        {               
            var clickableImage = (Image)parameter; // cast the parameter object to an Image.
            // Use the element for whatever you need
            ...
        });
    }
}
Will Decker
  • 3,216
  • 20
  • 30
  • When I try that, I get an error "Specified cast is not valid", directly related to the CommandParameterProperty line. – jbyrd Apr 07 '16 at 18:25
  • Oh, that would be because it's looking for a property on the MyViewModel class and clickableImage is not a property nor is it in MyViewModel. Can you share a little more information on what you want to accomplish? As a general rule, the ViewModel should not have knowledge of the View in a strict MVVM sense. I'd be happy to help if I know what your end goal is. – Will Decker Apr 07 '16 at 18:47