I have an MVVM Cross application, and I'm trying to figure out why the initial screen isn't showing (this is on WinRT).
The following code looks like it loads the ViewModel MainViewModel:
var setup = new Setup(rootFrame);
setup.Initialize();
var start = Cirrious.CrossCore.Mvx.Resolve<Cirrious.MvvmCross.ViewModels.IMvxAppStart>();
start.Start();
However, the Start method of MainViewModel never gets called. The reason appears to be this error in the output:
Error seen during navigation request to MainViewModel - error KeyNotFoundException: Could not find view for MyApp.PCL.ViewModels.MainViewModel
So, here's my guess as to the problem: it's looking for MyApp.PCL.ViewModels.MainView, Obviously, this doesn't exist. The view is in: MyApp.Views.MainView. Is my assumption correct and, if so, how can I persuade MVVMCross to look in the correct place?
EDIT:
The Setup method is called from the MyApp.Windows WinRT app.
protected override IMvxApplication CreateApp()
{
return new MyApp.PCL.App();
}
MyApp.PCL is a portable class library that is referenced from MyApp.Windows.
MyApp.PCL contains the ViewModels, and MyApp.Windows contains the views.
I have tried to override Start():
public class MainViewModel
: MvxViewModel
{
public override void Start()
{
System.Diagnostics.Debugger.Break();
base.Start();
}
but this never gets hit.
Massive Doh! here, but I'll post the solution; my view was not using the MvxStoreView, but the standard StoreView.
The solution was to change the view as follows:
...
xmlns:views="using:Cirrious.MvvmCross.WindowsStore.Views"
...
<views:MvxStorePage
All, I would like to know the recognised best approach/industry standard of launching [child] dialogs/windows from an WPF using the MVVM pattern. I have come across the following articles:
A. CodeProject - Showing Dialogs When Using the MVVM Pattern
This approach seems good but excessive to me. The is some degree of code replication and I am not convinced this is the right way to go.
B. WPF MVVM and Showing Dialogs
This briefly runs through three options with various links which are all fairly/very poor at explaining the methodology or are of-topic.
Can someone please provide an explanation of the industry standard method/approach of launching dialogs from a WPF application using MVVM and preferably some links to further reading material? If you can provide an example yourself I would of course be most appreciative!
Thanks for your time.
First of all, i don't know of any "industry-standard" way for showing dialogs using MVVM because there is no such thing.
Secondly, Welcome to MVVM, you have just touched on of the areas that MVVM don't have a standard for.
To tell you the truth, MVVM has many pain points and this is the reason why there are tons of MVVM frameworks out there, just to mention a few MVVM Light, PRISM, Caliburn.Micro, Cinch, Catel, WAF, Baboon, shell i stop or you want more.
Now to answer your question and after dealing with most of those frameworks, i noticed one commonality, they all use a DI/IoC container and then provide you with an interface, something like IDialogManager and an implementation of their own, and then they ask you to accept this interface in your view model and use it to show dialogs. So to sum this up, i would use dependency injection, have an interface for showing dialogs, and then provide and implementation of that, and register it with the di container and then consume it from my view model or views.
Edit: So you have picked PRISM (which in my opinion) is hardest between them all in showing dialogs. Now that's aside, there is the hard way which is by using Interaction Requests (check the middle of the article), or you can use this Answer as a quicker way.
Recently, I've implemented my own Navigation Service for WPF, which uses Caliburn.Micro's WindowManager (but you could replace it by something else).
Example (how to use):
_navigationService.GetWindow<ClientDetailsViewModel>()
.WithParam(vm => vm.IsEditing, true)
.WithParam(vm => vm.Client, SelectedClient)
.DoIfSuccess(() => RefreshSelectedClient())
.ShowWindowModal();
Implementation:
namespace ClientApplication.Utilities
{
public class NavigationService : INavigationService
{
SimpleContainer _container;
IWindowManager _windowManager;
public NavigationService(SimpleContainer container, IWindowManager windowManager)
{
_container = container;
_windowManager = windowManager;
}
public INavigationService<TViewModel> GetWindow<TViewModel>()
{
return new NavigationService<TViewModel>(_windowManager, (TViewModel)_container.GetInstance(typeof(TViewModel), null));
}
}
public class NavigationService<TVM> : INavigationService<TVM>
{
IWindowManager _windowManager;
TVM _viewModel;
System.Action _action;
public NavigationService(IWindowManager windowManager, TVM viewModel)
{
_windowManager = windowManager;
_viewModel = viewModel;
}
public INavigationService<TVM> WithParam<TProperty>(Expression<Func<TVM, TProperty>> property, TProperty value)
{
var prop = (PropertyInfo)((MemberExpression)property.Body).Member;
prop.SetValue(_viewModel, value, null);
return this;
}
public INavigationService<TVM> DoBeforeShow(Action<TVM> action)
{
action(_viewModel);
return this;
}
public INavigationService<TVM> DoIfSuccess(System.Action action)
{
_action = action;
return this;
}
public void ShowWindow(IDictionary<string, object> settings = null)
{
_windowManager.ShowWindow(_viewModel, null, settings);
}
public bool ShowWindowModal(IDictionary<string, object> settings = null)
{
bool result = _windowManager.ShowDialog(_viewModel, null, settings) ?? false;
if (result && _action != null)
_action();
return result;
}
}
}
Interfaces:
namespace Common
{
public interface INavigationService<TVM>
{
INavigationService<TVM> WithParam<TProperty>(Expression<Func<TVM, TProperty>> property, TProperty value);
INavigationService<TVM> DoIfSuccess(System.Action action);
INavigationService<TVM> DoBeforeShow(Action<TVM> action);
void ShowWindow(IDictionary<string, object> settings = null);
bool ShowWindowModal(IDictionary<string, object> settings = null);
}
public interface INavigationService
{
INavigationService<TViewModel> GetWindow<TViewModel>();
}
}
The most recent release of Prism (download here) contains a so-called "Reference Implementation" of an MVVM application called "Stock Trader". My rationale was that if the Prism team is calling it a "Reference Implementation", that's the most "standard" from their point of view (if anything in MVVM is standard), and the logical choice to press on with.
The source contains an infrastructure library for raising modal dialogs, and it's pretty good. So I adopted that library and have deployed it successfully (I uploaded such an app to Codeplex).
I needed to tweak the code to 1 add the parent's icon to the title bar because the library didn't provide for it; and [2] add some meaningful text to the title bar because the library left it blank and [3] add a delegate to invoke when the dialog closes. It's abstracted to the extent that a VM can raise a dialog by passing two strings (i.e., the Unity Registration Names) to a mediator. Those changes are available on Codeplex.
So among all the other 'standards' the "Reference Implementation" should minimally participate as a viable choice. The more oblique answer to your question is that if your View Models are sufficiently isolated and work entirely through POCO interfaces, then in THEORY, it shouldn't matter because switching to another 'standard' should be a trivial exercise.
i simply use a dialogservice, see here
within your viewmodel you just have to do:
var result = this.uiDialogService.ShowDialog("Dialogwindow title goes here", dialogwindowVM);
... do anything with the dialog result...
Creating a dialog service has worked out well for me, and is also suggested in both your links.
Later I saw the same solution at the dev days in an MVVM presentation by Gill Cleeren. Check the link for working code samples (though written for Metro)
Only thing that nags me a bit about the dialog service is that it is in some way UI technology (rich client) dependent.
A simple request-response web frontend View can be built on top of the same ViewModel and Model code that the WPF XAML binds to. Until the ViewModel starts popping up dialogs through the dialog service. I would not know how to implement the dialog service for a web view. Implementing dialogs there would require pushing a bit more logic to the view.
Purpose of using interface to implement dialogs is to make code testable. In this case, "A" is widely used, but it is still hard to say "Standard". If you do not have test on your ViewModel or you can test your ViewModel avoid touching dialogs, such as using Extract-Override, you can definitely do not follow the instruction.
While watching a video about MVVM on Pluralsight there was a situation where the MVVM pattern got violated but no correct way of doing it was shown:
The view had a button that uses ICommand to trigger a handler in the ViewModel.
The handler correctly relayed the execution to a repository implementation.
The concrete implementation of the repository called a web service method.
However: if the webservice call failed, the ViewModel would bring up a message box that informs the user about the error.
As the ViewModel is an abstraction of the View, it should not directly create UI, but what is the 100% clean way to get that message box presented to the user?
Create a service:
interface IDialogService
{
void ShowMessageBox(string message);
}
Implement it:
class DialogService : IDialogService
{
public void ShowMessageBox(string message)
{
MessageBox.Show(); // ...
}
}
Use dependency injection:
class ViewModel
{
[Import] // This is MEF-specific sample
private readonly IDialogService dialogService;
}
or service location:
class ViewModel
{
private AnyCommandExecute()
{
// This is MEF-specific sample
var dialogService = container.GetExportedValue<IDialogService>();
}
}
to obtain a concrete IDialogService in your view model, then call the obtained implementation from ViewModel.
The same approach is applicable for any other similar cases: show open/save dialog, show your custom view model in dialog.
There are several ways to do this that adhere to the MVVM pattern, such as Interaction Service and Interaction Request.
Interaction Service
... a service that can be used by the view model to initiate interaction
with the user, thereby preserving its independence on the view's
implementation
Interaction Request
... uses events raised by the view model to express the intent to
interact with the user, along with components in the view that are
bound to these events and that manage the visual aspects of the
interaction.
Source
Both quotes above are from this source (which also contains more detailed information about the patterns): http://msdn.microsoft.com/en-us/library/gg405494(v=pandp.40).aspx#sec10
I am taking over an application developed with MvvmCross.vNext.
While trying to update it with MvvmCross.V3, I found the following breaking change: in the constructor of the MainViewModel, we show the LoginViewModel (ShowViewModel()).
It worked fine in vNext.
But with V3, the LoginView doesn't show.
After a long search, I found out that the following code, added in MvxStoreMainThreadDispatcher.RequestMainThreadAction :
if (_uiDispatcher.HasThreadAccess)
{
action();
return true;
}
was responsible for my troubles.
If I comment it out, my application works as previously, but I guess this code is there for some reasons...
Do you have any suggestions ?
Can I force the previous behavior without changing MvvmCross source code?
Should I refactor the code to handle the LoginView differently ?
Thanks in advance for your comments.
Philippe
While trying to update it with MvvmCross.V3, I found the following breaking change: in the constructor of the MainViewModel, we show the LoginViewModel (ShowViewModel()). It worked fine in vNext.
I think your constructor navigation would have broken on several platforms in any MvvmCross version. To be honest, I think you were lucky it worked before.
The problem is that ViewModels are constructed (or located) during View events such as ViewDidLoad, OnNavigatedTo, and OnCreate - and these events are normally
called during 'page transitions'
To work around this you will need to move your login navigation out of the constructor.
How you do this depends on your app
if you do need the Home->Login backstack, then you can trigger off some async or time delay or you can trigger off some other View event such as something like ViewDidAppear
if you don't need that backstack then the way I normally implement this sort of thing is to use a custom IMvxAppStart - something like:
public class AppStart
: MvxNavigatingObject
, IMvxAppStart
{
public void Start(object hint = null)
{
var authService = Mvx.Resolve<IMySerice>();
if (authService.IsLoggedIn)
{
ShowViewModel<HomeViewModel>();
}
else
{
ShowViewModel<LoginViewModel>();
}
}
}
(you can see another example in https://github.com/slodge/MvvmCross/blob/v3/Sample%20-%20CirriousConference/Cirrious.Conference.Core/ApplicationObjects/AppStart.cs)
This can be registered in App.cs startup using:
RegisterAppStart(new AppStart());
Technologies
C# 4.0
Prism 4 with Unity for DI
WPF
MVVM
Preface
There are two projects in my solution, MyApp.Shell and MyApp.ModuleFoo
MyApp.Shell's Unity Bootstrapper
protected override IModuleCatalog CreateModuleCatalog()
{
// Module assemblies are read from a directory.
DirectoryModuleCatalog moduleCatalog = new DirectoryModuleCatalog();
moduleCatalog.ModulePath = #".\Modules";
return moduleCatalog;
}
The project MyApp.ModuleFoo contains a View and a View Model.
The ViewModel
// Somehow, Unity sees this class and registers the type.
public class FooViewModel : ViewModelBaseClass
{
public string FooText
{
get { return "Foo!"; }
}
}
The View
<Label Content={Binding FooText} />
The View's Code-behind
// Unity automatically sees this as Constructor Injection,
// which is exactly what I desire.
public FooView(FooViewModel viewModel)
{
DataContext = viewModel;
...
}
MyApp.FooModule's Initialization
Perhaps registering FooView with the region manager is inadvertently registering FooViewModel with Unity?
public void Initialize()
{
var regionManager = ServiceLocator.Current.GetInstance<IRegionManager>();
regionManager.RegisterViewWithRegion("FooRegion", typeof(FooView));
}
The view correctly displays "Foo!".
Problems
How do I tell Unity to register only a single instance of FooViewModel?
Additionally, (and I'm thinking ahead here), how would I tell unity not to register FooViewModel?
Thanks for the help.
Edit:
Added MyApp.FooModule's Initialization code
Edit (Solution):
It turns out RegisterViewWithRegion has two overloads. From Prism's documentation, when the overload I'm using is used, a new instance of the view is created. I'm assuming this also creates a new instance of FooViewModel.
The other overload uses a delegate to resolve FooView. The documentation says this overload is used in the "ViewModel-first" approach. I'm going to make this question as answered, but if anyone has any additional insight, I'd love to hear.
// Somehow, Unity sees this class and registers the type.
public class FooViewModel : ViewModelBaseClass
...
I am surprised that you say this as Unity does not register types inside the container by default. You have to tell it to do so either programmatically or in the config file.
When you have concrete classes (not interfaces) they will automatically get created by Unity whether they are registered or not. If not the default behavior is to create a new instance each time. No lifetime management is applied also.
As far as your questions:
To register only one type within your initialisation of your module just have.
Container.RegisterType<FooViewModel>(new ContainerControlledLifetimeManager());
The lifetime manager will instruct unity to only create one instance of the view model.