I'm working on a new WPF application and I'm trying to stay as close to the MVVM pattern as I can. My XAML files right now have no codebehinds, and all my interactivity is achieved using Josh Smith's RelayCommand class and commands in my ViewModel classes.
This worked great until I started working on the housekeeping tasks, such as an about box and a system preferences page. I want to have these as modal dialogs, but if I create a RelayCommand to open these pages, I'll be creating a dependency on the view within my view model.
This strikes me as against the grain of the MVVM pattern.
Is there an established method for creating new windows (modal and/or modeless) within the MVVM pattern without creating a dependency? It seems the only way I can keep the ViewModel clean is to create a Click event handler in the XAML codebehind file and create the new view within the old view.
Any recommendations?
One way to handle this is to implement a service that provides Views to ViewModels. Views register with the service and ViewModels can request dialogs from the service. This is an example of the Gang of Four mediator pattern.
Take a look at my Modal Dialogs solution for Silverlight 4:
Modal dialogs with MVVM and Silverlight 4
Please see my answer to this question about why the Window class itself is a ViewModel, so you can use it directly from your ViewModel without worries.
Laurent Bugnion has a weak-referenced mediator, in which he uses it to show dialog messages. Along with the message that is broadcast, a callback delegate is sent for the subscriber to execute. You could use the same concept to show an about dialog. Check out DialogMessage.cs from the source here.
We use Controller classes which are responsible for the UI Workflow. They create the modal windows and they mediate between various ViewModels.
How you can open a modal window with the View-Model-ViewModel (MVVM) pattern is shown in the ViewModel sample application here:
WPF Application Framework (WAF)
http://waf.codeplex.com
Related
Can anyone help.
We are working on an app which has a consistent header and footer and therefore ideally we'll use one viewmodel for the "home page" but we want the header and footer to remain.
Before we switched to starting using Prism, this was easy enough to navigate as we could control that in the Pages event and set the page.contentFrame.Navigate method to go where we wanted.
Now we're using the MVVM structure (which is superb and wish I'd done it ages ago) the NavigationService class only navigates the entire page (the VisualStateAware page).
How can I set this up so that when calling the Navigate method on the interface in the viewmodel that only the main content frame is ever navigated? or is there a better approach to this?
Any help would be greatly appreciated.
thank you
The question title seems to, pre-empt the details of the question slightly as a solution. But to share a common view model and visual parts across all pages, within a frame, using the navigation service to navigate between pages here is an overview..
Create a shared ViewModel, say "HeaderViewModel" of type say IHeaderViewModel to be shared between the different pages' view models. Inject this into the constructor of each page's ViewModel.
Then expose this as a property of each page's ViewModel. This property could also be called HeaderViewModel too. You can then reference the properties of this common HeaderViewModel in the bindings in the View, using binding '.' notation.
If you are using Unity with Prism, you can create this shared instance HeaderViewModel in the OnInitialize override of the App.
Create a shared part for each Page/View as a UserControl, which can be positioned on each page in the same place. This enables you to bind to the same properties on your HeaderViewModel.
I've been looking at MvvmCross for cross platform mobile development.
Since navigation of views is done by calling ShowViewModel<>(), how would you create the settings pane (which is a user control) in Windows 8 using MvvmCross?
MvvmCross provides a general ShowViewModel<T> navigation mechanism which uses a Presenter to display and set the DataContext on Views. Views that are shown this way typically cover the 'whole screen' and benefit from automatically constructed ViewModels using CIRS (see http://slodge.blogspot.co.uk/2013/03/v3-new-viewmodel-lifecycle.html)
However, just because navigation is typically done using ShowViewModel<T> this doesn't prevent you from using ViewModels in other ways. Common exceptions to the ShowViewModel<T> mechanism are things like iOS Tabbed and SplitView children, WindowsPhone Pivot/Panorama items, Android sub-Fragments and Dialogs, and Windows8 sub-panes such as flyouts.
At a practical level in Windows8, every XAML UserControl has a DataContext property which you can set in code - so you can always:
create any UserControl in code
then create a ViewModel
using new,
using Mvx.IoCConstruct<TViewModel>()
or using Mvx.Resolve<IMvxViewModelLoader>().LoadViewModel(request, state)
then set the UserControls DataContext property
then show the UserControl
Where you do this in your code... whether you use page code-behind, some Messenger-Message receiver or some other mechanism - well that's up to you - but this is something which is appropriate to put into the UI code project - it's definitely a View concern.
One final aside... while it is true that the settings pane is a UserControl, a LayoutAwarePage is also a UserControl too - so you can use LayoutAwarePage in flyouts too - but don't expect to see the OnNavigatedTo calls invoked when you do - e.g. see SettingsFlyout in http://code.msdn.microsoft.com/windowsapps/App-settings-sample-1f762f49
My app (written using MvvmCross and with MVVM pattern in mind) needs to display popup windows where user can choose of confirm certain options. So basically it's a classic modal dialog, but since the app's view model is implemented in a portable class library, it needs to tackle modality in a generalized sense - some platforms simply don't have exact match for a modal dialog.
There are a few threads discussing dialogs in MVVM (Open dialog in WPF MVVM, WPF MVVM dialog example). Following their advices I could probably solve this by introducing DialogService and implementing it for each platform. However I will be treating then dialogs like other services - storage service, map service etc.. But a dialog is a part of the presentation concept, so I wonder if it can be treated more like a view, so instead of calling an instance of an obscure IDialogService I could navigate to it using an MVVM framework of my choice (MvvmCross in my case).
I checked MvvmCross implementation and samples but found almost no dialog-related stuff.
Within MvvmCross, the presenter is responsible for how Views/ViewModels are shown when using ShowViewModel.
This presenter is a view/UI level object - it's ultimately the UIs job to decide if a view should be shown as a page, as a control, in a tab, in a split-view, as a dialog, etc.
v3 does introduce a presentation hint that the ViewModel can help suggest how the View should be shown - but it's up to the presenter on each platform to determine how (if) to use this hint.
Alternatively, Dialogs/flyouts/etc can easily be shown using MvxMessenger messages from ViewModel to View with a little bit of code behind.
For 'modality', also consider Greg's post on 'returning results' - see http://www.gregshackles.com/2012/11/returning-results-from-view-models-in-mvvmcross/
I am loading controls dynamically from the web server from separate XAP files. After creating an instance I want to show them in tab Pages. The controls can be MMVM controls using CM but also non MVVM standard controls.
Before trying the tab I tested to simply show a control dynamically on the page by using:
<ContentControl Name="TestControl" />
Test control is a property of Type UserControl which is set via creating a new Instance of a dynamically loaded control. Now this gives me an error that it can't find the view. In case of non MVVM controls there is of course no view, so how do I load a non MVVM control?
I tried to make the test control a MVVM control, but still get the cannot load view error. Makes sense as such instance is not created. If I create an instance of the dynamically loaded view besides the view model, how do I "Add" this so that CM finds it?
Last but not least, how do I bind this to a tab control in Silverlight? The idea is to have a collection of user controls (plugins) which each is rendered in its separate tab page.
Thanks for any help.
(I got this done in no time NOT using MVVM, still not sure if MVVM is worth all the complexity)
There's no such thing as "mvvm control". MVVM is just a pattern not a control type. Basically, in Caliburn you don't need to work vith UserControls or Views directly, but if you pick the ViewModel first approach, Caliburn framework should be able to find the matching view for you. In your case since you're loading XAP files dynamically, you need to add them to the list of assemblies Caliburn looks to find a View/ViewModel (and bind them together) and this is done through IAssemblySource interface. According to the documentation here:
So, what is AssemblySoure.Instance? This is the place that
Caliburn.Micro looks for Views. You can add assemblies to this at any
time during your application to make them available to the framework,
but there is also a special place to do it in the Bootstrapper.
Lets say that on all my views, or generally at any time in my app, I want to be able to show an error message popup, and it always looks the same. How do I do that?
First thought is having all my view models extend a base view model which facilitates these things, but after that, do I have this base view model actually create the UI widgets and display them?
thanks,
Mark
If you've got some common functionality that you want to provide across a range of views, then you can implement a base class that inherits from the PhoneApplicationPage, and then derive all your classes from that class instead. The XAML for your pages then looks like this:
<local:BasePage xmlns ...
xmlns:local="clr-namespace:MyNamespace"
x:Class="MyNamespace.MyPage">
However, you will not be able to define common UI components in the XAML for your base page. If you wanted to have common UI components you would have create them manually in the code-behind for the base page, perhaps in a handler for the Loaded event, but I think a better solution would be to provide your common UI in a UserControl, which you then add to each of your pages.
If you want to show a Toast or Message Box, then I would recommend the ToastRequestTrigger and MessageBoxRequestTrigger from the Silverlight Toolkit as described in the patterns & practices WP7 Developer Guide.
you could probably define an event on base view model, which is fired inside view model whenever an error occurs, then in view, you can subscribe to this event and display the popup. You can carry error context in EventArgs of the fired event.
Additionally you could unify the logic for displaying the popup but that's probably another story :)
This is testable and nicely decoupled from the view.
Hope this helps,
Robert