0

I have made quite a bit of progress on my first MVVM WPF application, the issue I am now having is I have a Window that has a viewmodel.
This window has a button which opens another window that has another viewmodel. Imagine a textbox on the first window.
Once the second is opened the user will select a value and click save, this window will close and update the first window with its value.
When pushing save I have an ICommand on the childwindows Viewmodel that calls the SaveMethod. I have the selected value stored in a property on the Child windows viewmodel.

But how do I update the Main Windows textbox with this value? I imagine I bind a property on the main windows view model, but unsure on how to continue.

Please advise, I can provide code examples if needed, but I think I may have explained it well enough,
oh and thanks to everyone at StackOverflow for the help on my questions I have learnt a lot.

Gilad
  • 6,437
  • 14
  • 61
  • 119
David B
  • 889
  • 2
  • 11
  • 29
  • please share some code of what you have tried so far. – Gilad Apr 16 '15 at 16:35
  • you really need to show some code in order for anyone to help you – CharlesMighty Apr 16 '15 at 16:48
  • Is the child window modal dialog? That means that you need to close the dialog in order to continue working in parent window. Mostly, it's the case. I have written an example of working with dialogs in mvvm here: http://stackoverflow.com/questions/501886/how-should-the-viewmodel-close-the-form/29052421#29052421. It demonstrates login window popup, where parent window's viewmodel accesses the child vm – Liero Apr 16 '15 at 18:18

4 Answers4

2

This is pretty straightforward using the MVVM Light framework. For the purposes of demonstration I'm going to use a string as the value you're passing, but it's easy to construct a different message type for whatever you need to pass.

In the constructor of your first Window's ViewModel you register to receive NotificationMessages. NotificationMessages are used to send string messages:

public MyFirstViewModel()
{
    Messenger.Default.Register<NotificationMessage>(this, NotificationMessageReceived);
}

In the SaveMethod in your second Window's ViewModel you send a message with the value you want to pass. I'm using MyStringValue as the name of the property that stores the value chosen by the user in your second Window:

private void SaveMethod()
{
    MessengerInstance.Send(new NotificationMessage(MyStringValue));
}

When that message is received by the ViewModel of the first Window the NoitificationMessageReceived method is called. I'm going to put that value in a string property on the first ViewModel called MySavedValue:

private void NotificationMessageReceived(NotificationMessage msg)
{
    MySavedValue = msg.Notification;
}

In your View for the first Window you have a TextBox with its Text property bound to MySavedValue. This updates whenever MySavedValue is updated.

goobering
  • 1,547
  • 2
  • 10
  • 24
  • Thanks, what is MessengerInstance? I cannot find this – David B Apr 17 '15 at 14:39
  • MessengerInstance is part of the Messenger class from the MVVM Light framework. The easiest way to add the necessary references is through Nuget with ID: 'MVVM Light'. Be careful when you add the reference - the framework places a few new items in your project, including a ViewModel called 'MainViewModel'. If you already have something called MainViewModel in there then don't copy over it with the new one. After that there are a couple of fairly trivial registration jobs to do and you should be up and running. Lots of info here: http://blog.galasoft.ch/posts/ – goobering Apr 17 '15 at 15:02
  • Thanks for the help, I have added the MVVM Light Framework but still it cannot find the MessengerInstance. It does have Messenger.Default though? – David B Apr 17 '15 at 15:06
  • I've got it in the namespace Galasoft.MvvmLight . Do you have a 'using Galasoft.MvvmLight;' declaration? – goobering Apr 17 '15 at 15:12
  • I do, its version 5.1.1.35049. I have found it in Galasoft.MvvmLight ViewModelBase – David B Apr 17 '15 at 15:41
  • I still have the same error? With that using, I have restarted VS, done a clean build etc. Error 1 The name 'MessengerInstance' does not exist in the current context – David B Apr 17 '15 at 15:50
  • 1
    I changed it to Messenger.Default.Send and this works fine, thanks – David B Apr 17 '15 at 16:02
0

In the parent viewmodel, you'll need a reference to the child viewmodel. When the child window is closed, you'll want to get the value of the secondviewmodel's property and set it to a appropriate property of the first parent viewmodel.

Russ Wilson
  • 110
  • 10
0

One of the posible (and simple) solutions is to keep one ViewModel for both windows

<Grid>
    <StackPanel>
        <TextBox Text="{Binding TheText}" />
        <Button Command="{Binding ShowOptionsCommand}" Content="..."/>
    </StackPanel>
    <Popup IsOpen="{Binding IsShowingOptions}">
        <StackPanel>
            <ListBox ItemsSource="{Binding Options}" 
                    SelectedItem="{Binding SelectedOption,Mode=TwoWay}"/>
            <Button Command="{Binding SaveOption}">Save</Button>
        </StackPanel>
    </Popup>
</Grid>

//ShowOptionsCommand handler
void ShowOptions() 
{
    IsShowingOptions = true;
}
//SaveOptionCommand handler
void SaveOption() 
{
    TheText = SelectedOption;
    IsShowingOptions = false;
}

I'm using the Popup to simplify the example.

igorushi
  • 1,855
  • 21
  • 19
0

Personally I'd go with the mvvm light framework already mentioned, but another option is to leverage IOC, also included with the above framework.

With this pattern view models have interfaces and are bound as properties from a view model locator data source. Within that, the child view model can be injected to the parent view model. Because IOC can create singleton instances of objects, the same instance gets given to the parent as is bound to the child window. That way you get a reference to the view model but through an interface thus preserving the separation.

Just offering this as an alternative technical solution beyond those already offered.

kidshaw
  • 3,423
  • 2
  • 16
  • 28