How do I reflect changes made to ViewModels for other windows? - wpf

My app contains the following moduls:
SystemModel --> SystemViewModel --> SystemWindow
SettingsModel --> SettingsViewModel --> SettingsWindow
My SystemViewModel contain SettingsViewModel and other things.
In my SystemViewModel I create some Instance that its ctor receives SettingsViewModel.
If i want to update the settings I opened new SettingsWindow as ShowDialog with SettingsViewModel as him DataContext. If the user click "ok" I update the settings else I don't update.
My problem is that I dont know how to update the Settings in the Instance that I created in the SystemViewModel (Instance that received SettingsViewModel in his ctor).
Any idea?

Can you create only one instance of settings view model, maybe residing in a common view model that serves kind of a root for the view model and providing the glue that binds the models together?
Something like a view model controller, even if this sound a bit strange. This root view model could react to events from the view models and then can do everything that is required to update the other settings.
Another approach is a messaging based approach like the one that is implemented by MVVM Light Toolit. I have used this once and after the project got rather big this approach was kind of complicated regarding maintenance.
Update:
You can find information about MVVM Light Toolkit here.

Related

How can I instantiate the window/view that implements Caliburn Micro's IShell interface inside an Outlook Task Pane

I have a desktop application that is based on the Caliburn Micro framework. Everything works great. Now I am trying to port the same app into Outlook as a plugin.
In the desktop app, based on an entry inside app.xaml, Caliburn knows where to find the bootstrapper and instantiates it.
In case of the Outlook plugin, I've created an overridden bootstrapper that I instantiate explicitly inside ThisAddIn.ThisAddIn_Startup(). This one of course does not use the Application object.
I can even invoke a particular view using code similar to this
var windowManager = IoC.Get<IWindowManager>();
windowManager.ShowDialog(new MyViewModel());
And that will cause the view associated with the view model to be shown in a modal window on top of Outlook (hence validating that Caliburn Micro is able to find a view from a view model inside my Outlook plugin)
What I haven't figured out how to do is instantiate the Shell so that I can start using its functionality.
My expectation was that since my bootstrapper derives from BootStrapper, and I have registered my shell view model implementation with the MEF container as exporting IShell, Caliburn will automatically instantiate the shell view model and start using it. That is not happening.
My goal is to get the shell loaded inside my plugin's task pane as the container for other views that I will be loading based on user actions.
Any ideas or tips on how I can get this to work? In general has anyone got a shell implementation loading inside an Outlook or Office plugin's task pane?
Thanks!
Do you mean instantiate via Bootstrapper<Shell>. This uses the Window Manager underneath but I don't think that extends to outlook. There is nothing stopping you using the same code above to initialize your shell manually, composition will handle the rest of the application.
IoC.Get, by default calls Activator.CreateInstance so it is possible your problem is with MEF. The method that drives opening the Shell DisplayRootViewFor() calls this line.
windowManager.ShowWindow(IoC.GetInstance(viewModelType, null), null, settings);
If MEF is not hooked up properly it will fail causing your shell not to load.

ViewModel Event Communication

I have a WP7 app I'm creating and I want a login screen to appear if the user hasn't logged in yet. I have Main.xaml which has a view model MainViewModel.cs. For the login or signup portions I have them embedded as a Grid in Main.xaml, but I would think having them as a user control would work fine also. The login and signup portions will have their own view model, possibly the same one for both, AccountViewModel.cs, that the Grid or user control has it's DataContext set to.
After the user signs up or logs in, which occurs in AccountViewModel.cs, what is the best way for MainViewModel.cs or Main.xaml to know that it is complete, and it can begin loading data, or doing whatever it needs to do?
My initial thought is to use MVVM Light's messaging system. After signup/login occurs, broadcast a message that it's complete, and MainViewModel.cs will be registered to the message and can act on it.
Is there another way or more proper way of letting Main know something has occurred in it's child?
If this is too hard to follow I can add code examples.
A messaging system, such as the one in MVVM Light is a great way to decouple these kind of actions and provide notifications in the way you describe. Can't say as I'd advocate anything else really. The Prism library provides an EventAggregator, which does the same thing, but if you're already using MVVM Light, then stick with that.
Another approach would be to store this kind of info (IsLoggedIn) in a "global view model" such as SettingsViewModel.Instance for example. For a viewmodel of global meaning like Settings, it is an approach that makes a lot of sense IMHO. If you make this property raise the PropertyChanged event, this allows you to dynamically modify the UI when the property changes, and hide the login UI smoothly for instance.
cheers,
Laurent

Silverlight authentication during startup - how to mimic syncronous behavior?

I have a Silverlight app that is using the MVVM pattern. I have a WCF service which will allow me to authenticate users (I don't have direct control over that service - assume it is a black box that just returns me the user info and a list of privileges the user has). So, when the app starts up, I want to pull security data from that service.
Right now, when I do this, my views and view models can end up getting initialized before the service returns with the security data. This causes problems because the view models need to disable buttons and make things visible/invisible based on the user having certain privileges.
Is there a pattern that allows me to prevent the initialization of the views / view models until the WCF call has returned? How would you go about solving this problem as elegantly as possible?
Generally, you use BusyIndicator from Silverlight Toolkit for scenarios like this one.
Instead of disabling the UI, it shows them a progress instead.
What you do is provide a IsBusy property on ViewModel. While loading data, set it to True and False rest of the time. Wrap your UI with a BusyIndicator control and bind that property's value with BusyIndicator's IsBusy property.
With this in place, your UI will acknowledge whenever it's busy.

WPF PRISM event subcriptions not dying

I have a PRISM RegionManager with a couple of region - a Ribbon region on the top, and a main content region for my view underneath it - fairly basic.
The app starts with a "home" view in the main content area. When I click a button on the Ribbon, I inject a second view into the content area and navigate to it in the region manager. When I click a button on this view, it should be removed and the original view should be shown.
I'm currently doing this using the RegionManager.Add() method to manually add the second view. When I want to remove it, I publish an event which is consumed by a manager class that gets the current active remove, calls Remove() on the Region Manager for it, and then navigates back to the original view.
This all works great, except that when the second view is left alive after I call Remove(), and keeps a handle onto any subscriptions that it made during its lifetime! I've tried calling Subscribe explicitly with false for weak event references, but this is the default anyway, and it didn't help. I've tried both types of creating the view (discovery and injection) and removing the view via Remove and Deactivate. None of them helped. This is a real problem as when I want to create the same view in the future (a new instance of that view), I'm left with several instances of them, all subscribing to the same events, even though some of those instances were removed ages ago from the Region Manager.
Do I need to manually unsubscribe from every event that I subscribe to in my views (highly undesirable)? Or is there some way that I can dispose of the control / mark it as deactivated so that its subscriptions get removed?
I get the feeling that I'm doing something silly here but it's got me completely stumped.
Thanks
This is a known issue. There is a bug in the eventAggregator code. Take a look at the following blog and the suggested hack to overcome it
http://greenicicleblog.com/2010/04/28/prism-event-aggregator-more-leaky-than-it-seems/
Hope this helps

WCF RIA Services, SL4

After I edit an entity and save it, how do I reload the datasource to refresh the entities? I have a listbox with entities, and after I edit the entities the datasource is still showing the old information. the MyEntityDataSource.Load() method is not working.
The problem arises because I am not navigating to a separate page to do the editing. I am reusing the flipping window from the SLBA template. So when I flip back to the front, i'm basically still using the old object that are still in memory, not creating new objects that will fetch the data again. So I need to renew the old data.
You need to make sure that the ItemsSource property of the ListBox is bound to a collection of objects that implement the INotifyPropertyChanged interface . Ideally the collection itself will implement the INotifyCollectionChanged interface (such as the ObservableCollection generic class).

Resources