Silverlight authentication during startup - how to mimic syncronous behavior? - silverlight

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.

Related

Should Prism RequestNavigate work with no UI?

I have a Prism 4.0 enabled WPF application that uses RequestNavigate extensively, and it is working well. I have a scenario where I would like to render part of my UI to an image and store it for later use from a Windows service. I already know how to use RenderTargetBitmap to generate the image, but whenever my code tries to call RequestNavigate, nothing happens. I am calling the bootstrapper, so I would expect that all of the types are loaded, but it just is not working. Can anyone tell me if this should even be possible? Is there anything inherent to RequestNavigate that prevents it from working when there is no UI present?
Individual steps:
First, I call Run on my MefBootstrapper. This loads up all of the assemblies into the AggregateCatalog.
Then, I use MEF CompositionContainer.GetExportedValue to create a WPF UserControl that has a single ContentControl that is assigned a RegionManager.RegionName. This always creates the initial UserControl just fine.
Finally, I call MefRegionManager.RequestNavigate with the region name on my UserControl and the path to another UserControl that I want it to load. This fails to load the UserControl that I am attempting to navigate to.
If these are the only steps that I follow, then the final UserControl fails to load whether I am running from a Windows Service or from within my WPF application. However, if I call SetRegionManager to explicitely add the region from my host UserControl before calling RequestNavigate, then the last UserControl will load properly, as long as the code is run from within the WPF application. If this same code is run from my Windows service, then it still does not load.
RequestNavigate is exactly that, a request to navigate to a loaded (but inactive) region. It won't do any loading itself. You need to separately manage the loading of views (including views within views).
If your nested user control is only over loaded within the parent, and you don't need to manage it at runtime, then you can use ViewDiscovery. You register all the views in advance, and then when the region is created, it looks for (and loads) all the nested views. If you need to manage the views at runtime, switch them in and out, etc, then you can use ViewInjection.
For ViewDiscovery, in the Initialize method of the ModuleInit class in your module, insert the following line:
_regionManager.RegisterViewWithRegion("RegionNameOfYourNestedControl",
() => this.container.Resolve<NestedUserControl>());
Then when your region is loaded, the NestedUserControl will automatically be loaded into your ContentControl (region).
For more detail on ViewDiscovery, ViewInjection and UI composition, have a read of the prism documentation

WPF client for class library : how to notify error to UI?

I'm new to WPF and I'm working on a project that will have the following components : a WCF server class library, a WCF client class library, a WPF client UI and a WPF server UI.
I have a method in WCF client that add a user to a collection in the client and then register this user in the server. The method checks that user doesn't already exist locally then register in on the server that throws a FaultException if the user already exist on it.
How can I notify the client that operation doesn't succeed and that he must choose an other name? Throwing an exception? Adding code in ViewModel to check if user exists before calling add method?
Thank you.
IMHO, the best option is to check from the ViewModel on the server if the user already exists, if so, show a message on the UI.
Exceptions must be used for unexpected situations, and this is not the case.
A couple of ways. Take a moment to learn ValidationRules. This should help with that.
How to disable a Button on TextBox ValidationErrors in WPF
Howevever, you could do the same thing without a ValidationRule. Just have some error text that has Visibility bound to a bool in the ViewModel. Of course the error text would only be Visibile if user already exists.
Once you have looked at those two options, you should know which on is best for your project.

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

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.

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

Multiple calls to data service from SL3?

I have an SL3 that makes asynchronous calls to a data service. Basically, there is a treeview that is bound to a collection of objects. The idea is that as a user selects a specific treeviewitem, a call is made to the data service, with a parameter specific to the selected treeviewitem being passed to the corresponding web method in the data service. The data service returns data back to the SL3 client, and the client presents the data to the user.
This works well. The problem is that when users start to navigate through the treeview using the arrow keys on their keyboard, they could press the down arrow key, for example, 10 times, and 10 calls will be made to the data service, and then each of the 10 items will be displayed to the user momentarily, until finishing with the data for the most recently selected treeview item.
So - onto the question. How can I put in some form of delay, to allow someone to navigate quickly through a treeview, then, once then stop at a certain treeviewitem, a call is made to the data service?
Thanks for any suggestions.
Chris
use Rx for silverlight
As suggested by funwithcoding, you could try using the Reactive Extensions for .Net (Rx), I've not used it myself but from what I hear it would do what you're after.
However if you don't feel like you want to / have time to learn Rx etc. maybe look at using a DispatcherTimer to create a slight delay in you Treeview selected event, before you call the service to retrieve the data.

Resources