2
votes

I got a wpf desktop application with 3 ViewModels. I have 1 ViewModel that contains a tabhost and tabs. And I got 2 tabs. Each of those tabs has it's own ViewModel.
The problem I have is that in tab1 I have a listview with searchresults and a button. When I select one item in that list and press the button, I want to change tab and display information about that item I selected in tab2.
I have searched for a solution, but it seems to include creating all ViewModels in the MainViewModel and providing a reference of the MainViewModel to all the subViewModels.
Is there no other way?



EDIT

I just managed to solve my problems with MVVM light that I added to the project.

By binding a method in the MainViewModel and a property in it to the .xaml I can now call it from tab1 with info to tell it to change tab. Also, by binding a method in tab2 I can now send over an item from tab1 in the same manner.

This is how I solved it after importing MVVM light into the project.
In tab1

Messenger.Default.Send<string, tab2ViewModel>(--object to send to tab2--);
Messenger.Default.Send<int, MainViewModel>(--tab index--);

In Main/tab2

Messenger.Default.Register<int>(this, ChangeTab);
public void ChangeTab(int i)
{
   SelectedTabIndex = i; //Bound property in .xaml
}

It seems to automagically just work..

P.s. Thanx for reply. I shall look into how Prism work as well, and see if there is any advantages to use that instead of MVVM light(Not right now however).

1
Can you bind tab2's DataContext property to tab1's SelectedItem?snurre
No, I dont think so atleast. Because they are in separate .xaml files as well.prigas
I do not recommend directly using .NET types to send messages because as it is broadcasted, as other view-model might listen to this type, your application will get quickly spammed and you will have to do horrible handling. Create a type base on GenericMessage<T>. Also I think you can accept the answer.Ucodia
I see, I wassnt sure if that was the case as I was specifying a specific ViewModel, in this case MainViewModel etc. I did do notice that I could register 2 methods in the VM and that both where called with 1 send. It is a nice feature that I will make use of. Are you sure that specifying MainViewModel in the Send method wont limit it to that class?prigas
The issue with not using .Net types because they are broadcast is handled in MVVM light Messaging by using tokens.jfin3204

1 Answers

1
votes

A good solution to your problem would be to use the EventAggregator of Prism.

This service lets you listen to and publish a particular type of event from anywhere in your application without tying your view-models to each other. This is a really nice solution for MVVM and other losely-coupled designs. It is easy and works like a charm.

You can find the documentation here : EventAggregator More information about Prism here : Prism on Codeplex


Here is a concrete sample. Imagine you want to change the title of the main Window from anywhere in the application. You would create this event:

public class TitleChangedEvent : CompositePresentationEvent<string>{}

Then you would suscribe to this event in your MainWindowViewModel like this:

eventAggregator.GetEvent<TitleChangedEvent.Suscribe(
(newTitle) =>
{
    this.WindowTitle = newTitle;
});

And finally you can update the title from anywhere in your application like this:

eventAggregator.GetEvent<TitleChangedEvent>().Publish("This is a new title!");

Quite easy as you can see.


Smililarly with MVVM Light you would first create a message for notification:

public class TitleChangedMessage : GenericMessage<string>{}

Then you would listen to the message like this in your MainWindowViewModel:

Messenger.Register<TitleChangedMessage>(this, 
(message) =>
{
    this.WindowTitle = message.Content;
}

And you would send an update like this:

Messenger.Send<TitleChangedMessage>(this, new TitleChangedMessage("This is a new title!"));

This is the MVVM Light way to do it :)

You can also have a look at this related question: Messenger class in MVVM Light