1

I'm bit confused with the behavior of my code. I'm still newbee in MVVM light.

I have NewMessageWindow which is shown by command

    private ICommand newMessageCommand;
    public ICommand NewMessageCommand
    {
        get
        {
            if (newMessageCommand == null)
                newMessageCommand = new RelayCommand(() =>
                {
                    new NewMessageWindow().Show();
                });
            return newMessageCommand;
        }
    }

There can be multiple NewMessageWindows and each of them should have separate ViewModel. But I've noticed when I open multiple windows and if I change something in them it affects all windows. For example when I change combobox then combox values changes in all windows.

How to avoid it? How can I open multiple windows with seprate viewmodels that wouldn't affect each other?

Objects that are changing are ObservableCollections that are bound to view.

Edit:

This is how the ViewLocator looks like

    public NewMessageWindowModel NewMessage
    {
        get
        {
            return ServiceLocator.Current.GetInstance<NewMessageWindowModel>();
        }
    }

and in constructor

    SimpleIoc.Default.Register<NewMessageWindowModel>();

This is how binding looks like:

 DataContext="{Binding NewMessage,
                          Source={StaticResource Locator}}"

I've fixed problem with

 ServiceLocator.Current.GetInstance<NewMessageWindowModel(System.Guid.NewGuid().ToString());

but I've read that old instances are cached. How to get rid of them?

Robert
  • 19,800
  • 5
  • 55
  • 85
  • 1
    Does each view have it's own viewmodel? If the views all have the same viewmodel, then your INofifyPropertyChanged (Or your similar MVVM implementation) will notify all of the windows and change accordingly. – Kestami Jul 08 '13 at 12:49
  • how can I check it? They are all extending `ViewModelBase` – Robert Jul 08 '13 at 12:52
  • Without seeing more code it's hard to tell; I'm assuming your views are XAML windows, are you setting each one's datacontext to that of a different view model? – Kestami Jul 08 '13 at 12:53
  • well where do you create the VM for `NewMessageWindow` ? that's where you check if it does indeed create new VM's per View instance – Viv Jul 08 '13 at 12:53
  • They are xaml windows this is how I set dataContext `DataContext="{Binding NewMessage, Source={StaticResource Locator}}"` – Robert Jul 08 '13 at 12:54
  • there is also this line that registers windows in SimpleIoc `SimpleIoc.Default.Register();` the line is in ViewModelLocator class – Robert Jul 08 '13 at 12:56
  • so in your `ViewModelLocator` class for `NewMessage` property what's the getter looking like? – Viv Jul 08 '13 at 12:56
  • I've edited post take a look at it. – Robert Jul 08 '13 at 12:57
  • [You aren't getting a new instance with what you have right now](http://stackoverflow.com/questions/9342294/simpleioc-can-it-provide-new-instance-each-time-required) – Viv Jul 08 '13 at 12:59
  • I understand so where can I find any article or anything that will tell me how to close open windows and register/unregister them properly? Could you give me some? – Robert Jul 08 '13 at 13:03
  • you can have a look at [this](http://stackoverflow.com/questions/16995365/creating-a-new-instance-of-an-object-each-time-method-is-called) I'll see if i can post an example for you in a min for your case – Viv Jul 08 '13 at 13:03
  • I've solved the problem with opening the windows, but I need now to get rid of these being cached. Where should I put the code of messanger that closes these windows? – Robert Jul 08 '13 at 13:11

2 Answers2

1

SimpleIoC from MVVM Light does not create a new VM per call with ServiceLocator.Current.GetInstance<...>();

You can find the explanation from the library's author to get a new VM each time Here

For your case,

I'd probably just set the DataContext in the code-behind constructor of NewMessageWindow than directly in xaml with something like:

public NewMessageWindow() {
  InitializeComponent();
  var uniqueKey = System.Guid.NewGuid().ToString();
  DataContext = SimpleIoc.Default.GetInstance<NewMessageWindowModel>(uniqueKey);
  Closed += (sender, args) => SimpleIoc.Default.Unregister(uniqueKey);
}

This way when the Window is closed, the VM will be removed from the cache.

Do note this is not the only way to do this, you have quite a few other options,

  • You can keep the binding in the xaml for DataContext and when the Window is closed, using the Messenger class in MVVM Light send a message to the ViewModelLocator to remove the cache.
  • You can implement the Cleanup() function in the ViewModelLocator to remove the cache when presented with a key.

Pick an implementation that you prefer and go with it or use something like Unity or other DI-container helpers to get even more control of VM object lifetime's.

Community
  • 1
  • 1
Viv
  • 17,170
  • 4
  • 51
  • 71
  • I've put the code in view and it doesn't work, the only solution that works is to use `return ServiceLocator.Current.GetInstance(System.Guid.NewGuid().ToString());` but in that way I don't know how to get rid of cached window. – Robert Jul 08 '13 at 13:23
  • @Robert I've made a few edit's in the code paste, you sure you copied the latest? also make sure to remove the xaml binding for `DataContext` from `NewMessageWindow.xaml` – Viv Jul 08 '13 at 13:25
  • After your edited code it works. I'll accept the answer. Thank you for your time. – Robert Jul 08 '13 at 13:30
0

This behaviro is because of the Servicelocator. which return the same instance of the object. where you get the changes all over the shared instances. If you want to have a saperate copy of you ViewModel. You coudl implement the GetNewInstance into Service locator.

JSJ
  • 5,653
  • 3
  • 25
  • 32