I have to write a new UserControl for AccountManagement. To integrate in your application with several TabItems my UserControl has to implement the IModule interface which looks something like:
public interface IModule : INotifyPropertyChanged
{
FrameworkElement TabContent { get; }
ImageSource TabIcon { get; }
string TabTitle { get; }
}
I want to build the UserControl for AccountManagement with MVVM so I want to implement the IModule interface in my ViewModel.
My two questions are:
Is this a good solution, or should I prefer to implement IModule in my View-CodeBehind?
If I implement IModule in the ViewModel, how can I pass the View as TabContent to the parent?
No. FrameworkElement is a view concept and should not be in the ViewModel. I assume you will have to implement it in code-behind, but why don't you see how other tabs are written and ensure you are consistent with the existing codebase?
EDIT:
You will still need to implement the above in the View. All three properties are view based, with the possible exception of TabTitle which could pull its name from the view model. There is nothing stopping you moving toward MVVM for the content of the tab, but this existing requirement will have to be done in the view.
A good rule of thumb for deciding if something belongs in the VM is to consider whether you could unit test the VM without any view at all, or whether you could theoretically write a text based console view to drive the VM.
Related
I'm learning UWP at the moment in an attempt to port an old Win32 to the new platform. I'm using Template10 and everything runs fine so far, except I'm bit confused on how to implement the problem below.
Problem: In a page, I have to constantly remove and insert user controls depending on a view model property. The user controls are fairly complex and they all look and behave differently. Imagine a wizard with back and next buttons. On every click I have to remove the old content and insert a new one, with completely different view model.
Question: What would be the recommended way of implementing this in a MVVM way?
At the moment, my only idea is to send a message from the page's view model and subscribe for the message in page's code behind where I can create the required component and insert it dynamically in the page (after removing the old one).
In MyPageViewModel:
public IComponentViewModel CurrentComponent {get; set;}
...
public DelegateCommand NextItemCommand = new DelegateCommand(() =>
{
var evt = App.EventAggregator.GetEvent<ItemChangedMessage>();
evt.Publish(CurrentComponent);
});
In MyPage.xaml.cs code behind
public MyPage()
{
InitializeComponent();
var evt = App.EventAggregator.GetEvent<ItemChangedMessage>();
evt.Subscribe(OnItemChanged);
}
private void OnItemChanged(IComponentViewModel viewModel)
{
switch (viewModel.Type)
{
case 1:
// create the new user control and insert it in the container
var component = new TypeOneComponent();
component.DataContext = (TypeOneCompoentViewModel)viewModel;
// ...
case 2:
...
}
}
Not sure this is the best approach tho.
I've been thinking about a Wizard approach lately myself. It seems to me that a FlipView with re-templated left/right buttons is the easiest approach. My WizardViewModel would have several children view-models; something like Page1ViewModel, Page2ViewModel, and so on. I strongly feel that each page view-model would have a dedicated UserControl so the UI can be unique but not dynamic - I think it makes sense to design against dynamic UI, while embracing an adaptive UI - which is a different concept altogether.
The pseudo code might look like this:
public interface IWizardPage { }
public class Page1ViewModel : ViewModelBase, IWizardPage { }
public class Page2ViewModel : ViewModelBase, IWizardPage { }
public class Page3ViewModel : ViewModelBase, IWizardPage { }
public class MainPageViewModel : ViewModelBase
{
public IWizardPage CurrentPage { get; set; }
public IWizardPage Page1ViewModel { get; set; }
public IWizardPage Page2ViewModel { get; set; }
public IWizardPage Page3ViewModel { get; set; }
}
And this:
<FlipView Template="{StaticResource WizardFlipView}"
SelectedItem="{Binding CurrentPage, Mode=TwoWay}">
<Page1UserControl DataContext="{Binding Page1ViewModel}" />
<Page2UserControl DataContext="{Binding Page2ViewModel}" />
<Page3UserControl DataContext="{Binding Page3ViewModel}" />
</FlipView>
This is just a recommendation. But to answer your question, this would be very amenable to the MVVM pattern. I also think this would allow for you to be very flexible without getting so dynamic that maintenance is affordably time consuming. There are lots of ways to do wizards. I think this would be a fine solution, good with the MVVM pattern and fine with Template 10.
Best of luck.
I typically use an ItemsControl. This allows you to have a generic item template and a item specific template if you want and you can add / remove items at will by binding to the ItemsSource.
In your example of a wizard, you might make the main wizard container an ItemsControl that only shows one item at a time and a page would be an "item". The distinction with MVVM is that you don't add child controls, you add data and then specify a template to render it. So your items are going to be simple databound poco objects.
For your actual example, I guess you can add child controls to the ItemsControl and they would render automatically without even using a template since a ContentPresenter knows how to render controls. I would still use data only classes though since one of the tenants of MVVM is to separate the data from the UI. So your child item would be a model and your item specific template would be the UI layout bound to the item data.
little question. I'm progrraming in MVVM design pattern (C#).
the View is an Excel add-in, and I want to run from the View_Model a method that found in the View. I thought about 2 ways:
Hold in the View Model a pointer to the View (the pointer type is an interface that the View and the View_Model inherit from, otherwise I would get a circular independence because the View hold the View_Model and the View_Model hold the View), and then run the method directly from him.
Create an event in the View_Model and sign the method in the View to that event in the View_Model pointer which I already have in the View, and raise the event when I want to run this method.
Somehow, way number 2 feel little like screaming in the street to only one man instead off go straight and talk to him normally. On the other hand, the advantage in way number 2, is that in the future if I would have other method that relate to this operation I could just sign them to that event and not call them specially.
what would you do?
Method 1 breaks the MVVM principle since the view model should not know about the view. Your approach is a bit like the MVP design pattern.
I would say method 2 is the better approach, it's perfectly fine for the view to know about the view model. It also gives you the flexibility to do whatever you want when that event is raised, say for example, if you wanted to use a different view and call a different method.
Also, this kind of thing can be done using a good messaging framework. The view model publishes a message, the view subscribes to it. The mvvmlight frame work has a good implementation of this, but I am sure there are others too.
take an Interface, implement the view from it. And instantiate the viewmodel by passing this view.
lets say -
Interface
public interface IFooView
{
...
}
View
public Class FooView : IFooView
{
private FooViewModel _viewModel;
public FooView()
{
_viewModel = new FooViewModel(this);
}
}
ViewModel
public class FooViewModel
{
private FooView _view;
public FooViewModel(IFooView view)
{
_view = view;
}
}
Now, you can call the ViewModel from View, also View from ViewModel.
I am doing some data presentation using CM and WPF, and some of the data tabs have very similar formats but have to be kept in separate VM containing tabs as part of the standard for the application.
My initial thoughts were that I could do this programmatically in the VM by looking for any property pertaining to Views on the VM object (which itself is a Screen object derivation.) Its direct superclass is used as a contract for [ImportMany] so that the parent VM and View can tabulate the collection.
[ImportingConstructor]
public PartiesMasterPartiesViewModel(
IEventAggregator events,
IHelpService help,
ResourceManager<B_Action> actionResource,
IActionService actionService)
: base( events, help, actionResource, actionService)
{
}
protected override void OnActivate()
{
base.OnActivate();
this.Views.Add(new KeyValuePair<object, object>(this,
new PartiesMasterListView()));
}
So either I am not using this property correctly, or it does not do what I thought it does and I need to use another way.
Another way I'm thinking of doing it this explicitly instantiating multiple instances of the same viewmodel and manually adding them to the collection, but this seems like it would be violating what MEF's [ImportMany] would be here to do and weaken the design of the application.
The simplest way to achieve a view shared by multiple view models is to configure the ViewLocator with some extra rules.
In this example I have two view models Examples.ViewModels.SharedData1ViewModel and Examples.ViewModels.SharedData1ViewModel and a single view Examples.Views.SharedDataView that I'd like to be the view that Caliburn.Micro locates for both by default.
In my set up code I can add the following simple regular expression to the ViewLocator.
ViewLocator.NameTransformer.AddRule(
#"^Examples.ViewModels\.SharedData(\d+)ViewModel",
#"Examples.Views.SharedDataView");
I am aware there are a couple of questions similar to this one, however I have not quite been able to find a definitive answer. I'm trying to dive in with MVVM, and keep things as pure as possible, but not sure how exactly to go about launching/closing windows while sticking to the pattern.
My original thinking was data bound commands to the ViewModel triggering code to start a new View, with the View's DataContext then set to it's ViewModel via XAML. But this violates pure MVVM I think...
After some googling/reading answers I came across the concept of a WindowManager (like in CaliburnMicro), now if I was to implement one of these in a vanilla MVVM project, does this go in with my ViewModels? or just in the core of my application? I'm currently separating out my project into a Model assembly/project, ViewModel assembly/project and View assembly/project. Should this go into a different, "Core" assembly?
Which leads on a bit to my next question (relates somewhat to the above), how do I launch my application from an MVVM point of view? Initially I would launch my MainView.xaml from App.xaml, and the DataContext in the XAML would attach the assigned ViewModel. If I add a WindowManager, is this the first thing that is launched by my Application? Do I do this from the code behind of App.xaml.cs?
Well it mainly depends on how your application looks like (i.e. how many windows opened at the same time, modal windows or not...etc).
A general recommendation I would give is to not try to do "pure" MVVM ; I often read things like "there should be ZERO code-behind"...etc., I disagree.
I'm currently separating out my project into a Model assembly/project,
ViewModel assembly/project and View assembly/project. Should this go
into a different, "Core" assembly?
Separating views and ViewModels into different assemblies is the best thing you can do to ensure you won't ever reference something related to the views in your viewModel. You'll be fine with this strong separation.
Separating Model from ViewModel using two different assemblies could be a good idea too, but it depends on what your model looks like. I personally like 3-tier architectures, so generally my model is the WCF client proxies and are indeed stored in their own assembly.
A "Core" assembly is always a good idea anyway (IMHO), but only to expose basic utility methods that can be used in all the layers of your application (such as basic extension methods....etc.).
Now for your questions about views (how to show them...etc), I would say do simple. Personally I like instantiating my ViewModels in the code-behind of my Views. I also often use events in my ViewModels so the associated view is notified it should open another view for example.
For example, the scenario you have a MainWindow that should shows a child window when the user click on a button:
// Main viewModel
public MainViewModel : ViewModelBase
{
...
// EventArgs<T> inherits from EventArgs and contains a EventArgsData property containing the T instance
public event EventHandler<EventArgs<MyPopupViewModel>> ConfirmationRequested;
...
// Called when ICommand is executed thanks to RelayCommands
public void DoSomething()
{
if (this.ConfirmationRequested != null)
{
var vm = new MyPopupViewModel
{
// Initializes property of "child" viewmodel depending
// on the current viewModel state
};
this.ConfirmationRequested(this, new EventArgs<MyPopupViewModel>(vm));
}
}
}
...
// Main View
public partial class MainWindow : Window
{
public public MainWindow()
{
this.InitializeComponent();
// Instantiates the viewModel here
this.ViewModel = new MainViewModel();
// Attaches event handlers
this.ViewModel.ConfirmationRequested += (sender, e) =>
{
// Shows the child Window here
// Pass the viewModel in the constructor of the Window
var myPopup = new PopupWindow(e.EventArgsData);
myPopup.Show();
};
}
public MainViewModel ViewModel { get; private set; }
}
// App.xaml, starts MainWindow by setting the StartupUri
<Application x:Class="XXX.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
...
StartupUri="Views/MainWindow.xaml">
I wanna implement an interface(Add behavior) for set of WPF usercontrols.
I'm using MVVM design pattern.
Where I should implement the interface? in usercontrol code behind or in View model class?
Ex:
My Interface is
interface IWizard
{
event RoutedEventHandler MoveNext;
event RoutedEventHandler MoveBack;
event RoutedEventHandler Cancelled;
bool IsLast;
bool IsFirst;
}
Now in other place I wanna access user controls which are implemented this interface as this.
((IWizard)userControl).MoveNext += ...
((IWizard)userControl).MoveBack += ...
((IWizard)userControl).IsLast = true;
etc..
Implement in UserControl Code behind
I can't acess the interface's properties/methods directly in view model. I have to link them manually. right ?
PS: In this example I wanna Bind(TwoWay Bind) IsLast Property with a visibility of a button.
Implement in View model class
I can't access the usercontrol as a Interface object.
ex: ((IWizard)userControl).MoveNext += ...
What is the best practice on Implementing an Interface on Usercontrol with MVVM design Pattern?
You should implement this interface in UserControl because it is directly related to UserControl, it has nothing to do with ViewModel. View Model is for business logic and interaction between View and Model. Events which occurs on UI/View should not be doing anything on ViewModel directly.
I know you won't be able to access properties directly in view model but that's what MVVM is for. Use the bindings and commands to bind properties and methods from Control to your ViewModel
In perfect-world MVVM, ViewModel has no knowledge whatsoever about View. Whether View implements any interface at all is irrelevant from ViewModel's point of view.
In your scenario, what I think is more important is who will respond to MoveNext, MoveBack and Canceled events. Most likely, that would be ViewModel. What that means you probably could use methods such as WizardMoved(object sender, EventArgs e) in those ViewModels. Look what we've done here - ViewModel needs to have kind of indirect knowledge about View. That is not a good sign.
Perhaps instead, you could approach problem differently. Maybe what you need is IWizardMovement interface that will define methods to handle wizard moving events - and this interface will be implemented by ViewModels. So that when you pass ViewModel to View, it can easily subscribe ViewModel's handlers to its own events (note that not it doesn't really matter what interface View implements).
public interface IWizardMovementViewModel
{
void WizardMovedNext(object sender, EventArgs e);
void WizardMovedBack(object sender, EventArgs e);
void WizardMoveCanceled(object sender, EventArgs e);
}
Now, since in MVVM View knows about ViewModel (and never the other way around), you can easily utilize this knowledge:
// Wizard user control constructor
public Wizard(IWizardMovementViewModel viewModel)
{
MoveNext += viewModel.WizardMovedNext;
MoveBack += viewModel.WizardMovedBack;
Canceled += viewModel.WizardMoveCanceled;
}
ViewModel is separated from View for good now, and how your View looks like is not important anymore (as it should never been in first place).
First of all, your view-model shouldn't have a field called "userControl".
When you design an MVVM application you should think in terms of layers. The Model layer should be usable by itself. The View-Model layer shoul be usable with the Models and Services. The View is what combines everything together.
But what about navigation?
Rather than giving your view-model direct access to the user control, you should only give it access to the abstract notion of navigation. In WPF that means NavigationWindow.NavigationService or Frame.NavigationService.
You can see an example of this in NavigationViewModel class in Granite.Xaml (http://granite.codeplex.com/SourceControl/changeset/view/85060#2109525). Since it takes an abstract interface (INavigator in my case, IWizard in yours) you can still test the view-model in isolation using simple mocking techniques.
Add a IsLast property to the ViewModel, make sure it raises NotifyPropertyChanged correctly.
Bind the Visibility of the Button to the IsLast property using a ValueConverter that converts a boolean into a Visability and back.
Done.