I'm aware this question has already been asked numerous times, and I've read many answers referring to it. Nevertheless, none of them fulfilled my requirements, and hence I need some advice.
The application I'm developing at the current moment looks like this: http://screenshooter.net/100101493/smrkpog
It's a WPF MVVM application based on MVVM Light Toolkit. The area with a grid is a ListBox
+ Canvas
. The items (let's call them 'Neumes') consist again of a ListBox
+ Canvas
each and are dynamically created by a user. Every Neume is composed of 'Elements' which are rendered as the red shapes.
When the user double-clicks a Neume, a new window opens. It is supposed to enable editing (translate, resize, rotate) of the Elements the selected Neume is made of. What I'd like to do is to pass my SelectedNeume (with a list of Elements) stored in my MainViewModel to the ViewModel of my newly created window. I have a few ideas on how to achieve this:
DataContext
of the new window,I'm looking for a solution that is both simple and neat. I'd be most happy to make use of option 3., but I'm a relative newbie as far as WPF is concerned, and don't know how to start really. Also, I'm afraid there might be a problem with the fact that the new window is opened when a double-click event on the main ListBox is fired, since I couldn't find a way to bind a command to the ListBoxItem neither in its Style nor DataTemplate (the event trigger/EventToCommand solution didn't work for me).
This is the event:
private void ListBox_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{
var item = ((FrameworkElement)e.OriginalSource).DataContext as Neume;
if (item != null)
{
var view2 = new EditWindow();
view2.Owner = this;
view2.SetDataContext();
view2.ShowDialog();
}
}
The SetDataContext()
method currently takes care of binding the DataContext according to the 1. option:
public void SetDataContext()
{
if(this.Owner != null)
DataContext = this.Owner.DataContext;
}
My question is: Which option would you recommend? Are there any problems with either 1. or 2.? Possible memory leaks?
There are two ways to pass information between View Models: Implement the ISupportParameter interface to pass parameters between View Models: Passing Data Between ViewModels (ISupportParameter). Use the Messenger service: Layer Communication. Messenger.
I decided to do it the traditional way: 1) define a thread-safe singleton 2) in Application_Startup, instantiate the singleton and all the ViewModels (at least the VM's that need to share info with each other), then save references to all the VM's in the Singleton.
ViewModel as the bridge between the View and the Model. TL;DR: We can pass parameters to our ViewModel, use it as a data holder, also to share data between Fragments, and to persist its state across process recreation. This is part of a multi-part series regarding Advanced ViewModels on Android.
No that is fine; each object should be a ViewModel in its own right.
Personally I would go with option 3.
The messaging mechanism keeps your viewmodels separated from each other and once you work through one example, you'll see it is quite easy.
Personally I like to add a message broker class with static methods for each message type I want to send, this helps me centralise changes - but essentially you've got a send and receive. You can send what you want and if something wants to receive it they can.
MVVM Light is a great framework for this.
Send:
GalaSoft.MvvmLight.Messaging.Messenger.Send<LoginSuccessMessage>(new LoginSuccessMessage() { UserName = user });
Receive, in my target View Model constructor:
this.MessengerInstance.Register<LoginSuccessMessage>(this, this.OnLoginSuccessMessage);
Handler in the target View Model:
private async void OnLoginSuccessMessage(LoginSuccessMessage message)
{
this.CurrentUserName = message.UserName;
this.MoveToState(ApplicationViewModelState.Active);
await Task.Delay(5000);
this.MoveToState(ApplicationViewModelState.Idle);
}
In this example, I am sending a user ID as a property on the message class:
public class LoginSuccessMessage : MessageBase
{
private string _UserName;
public string UserName
{
get
{
return this._UserName;
}
set
{
this._UserName = value;
}
}
}
Replace that property with whatever you want be that a collection or complex object.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With