Daniel Perez
Daniel Perez

Reputation: 4332

Need to call method of VIewModel from View

Hi I wanted to know if this approach is right, or what should be the right one I have a MVVM pattern, and i have a ListView my idea is that when i select an item in the listview, a property in the viewmodel gets updated with the selected object. HOwever, when the user presses Intro, i want the viewmodel to do something (open a new browser window). I did something like this :

private void listView1_KeyDown(object sender, System.Windows.Input.KeyEventArgs e)
        {
            var vm = Resources["Locator"] as MainViewModel;

            if (listView1.SelectedIndex != -1 && e.Key == Key.Enter)
            {
                vm.OpenBrowserForSelectedOffer();
            }
        }

However i don't know if this is a correct way of having things nicely done, or if something else should be done. Because in this case, the view is actually requesting the viewmodel (which is a resource), maybe it "knows too much" about it, and there's a better practice to solve this kind of problem.

Upvotes: 0

Views: 4223

Answers (3)

Isak Savo
Isak Savo

Reputation: 35944

It's not perfectly clear what OpenBrowserForOffer does but my guess is that it opens a new browser window (using e.g. Process.Start()) for that offer, right?

If so, then I think it's perfectly OK for the viewmodel to handle this since it's part of the business logic.

And there's no problem for the view to know or assume stuff about the viewmodel, it already does anyway (since you are binding to its properties).

And as suggested in another answer, you can easily get your view's current viewmodel by looking at the DataContext. In the views where I need code access to the viewmodel I usually implement two properties for convenience:

private YourViewModelType ViewModel
{
    get { return DataContext as YourViewModelType; }
}

private bool HasViewModel { get { return ViewModel != null; } }

Upvotes: 2

L-Four
L-Four

Reputation: 13551

I assume that you are using WPF or Silverlight. Using the command pattern is of course the correct way to execute a command triggerd by a UI event. But, the problem is that in your case this operation itself does something with UI; and that's not the viewmodel's responsability.

It can be solved in a simple way, so that the viewmodel remains testable. Create an IBrowserService interface, with operation OpenBrowserForOffer.

public void OpenBrowserForOffer(Offer offer, Action<Result> callback)

Create one implementation of it that opens the browser and displays the selected offer. Create another implementation that is a mock implementation without UI stuff.

Then from the viewmodel, inject an instance of IBrowserService, and use it to open the browser or execute the mock logic, depending on being run from real application or test.

Note that in the view you have DataContext at your disposal to get the view model.

Upvotes: 3

eFloh
eFloh

Reputation: 2158

Use a Command in the Viewmodel that is bound to the KeyDown-Event/Command of the listView and Move the code in the command inside the viewmodel, voilá, you got the mvvm pattern clear.

Upvotes: 1

Related Questions