I have more of an architectural question. I'm trying to implement MVP in C# as follows:
IView creates Presenter
IPresenter has a property IView which holds View, that is bound to it
View CAN be Form, but Presenter does not distinguish between Form and non-Form types, so View can be swapped and the solution is to be testable
What I sometimes need to do, is to open some other form. E.g., I have Browser view with DataGrid and when I double-click on a grid item or select something and click Edit button, Edit event is raised and Presenter acts.
Now, Presenter needs to open a Editor view, which is also a Form, but the problem is, presenter should not construct the Form itself, because then it is impossible to Mock the View.
I'm pretty struggling with the proper concept. My code looks something like this:
var editorView = new EditorForm();
editorView.Presenter.Entity = SelectedEntity;
editorView.ShowDialog(View as Form);
Under the hood, EditorForm constructor constructs the presenter and assigns this (View instance) to the presenter:
public EditorForm()
{
Presenter = new EditorPresenter(this);
InitializeComponents();
}
From the View perspective, I can swap it to MockView simply by implementing the Mock and then instantiating the same Presenter from MockView's constructor.
I was searching for some other Q&A here and over the web but did not find anything suitable.
Thank you for all your hints.
If I understand your conception,
I suggest you to project the Edit presentation issue according to MVP pattern as you did with main view.
So create IEditView and EditPresenter and finally in main presenter create instance of EditPresenter. Generally control the edit view through its presenter.
After some brainstorming with some friends, we came to the conclusion, the best way to handle the case of instantiating different set of Views for production (FormViews) and different set for testing (MockViews) is constructing them in some context - in my case, Spring context is an option.
So far, I consider this as an answer for the problem. If you have some more clever solution, please feel free to share!
Related
I've created a dialog service using interfaces to show custom dialog/confirmation boxes (I know that Prism comes with this ability but the dialog boxes don't appear to be customizable and don't match my layout/color scheme). The dialog service has a register function that registers the dialog view type with dialog viewmodel type in a dictionary. This is done so that a viewmodel can be passed in and in a loosely coupled fashion, an instance of the needed view can be created. The code looks like this:
private readonly IDialogService dialogService = new DialogService(Application.Current.MainWindow);
// Registers the confirmation window viewmodel with the confirmation window view
dialogService.Register<ConfirmationWindowViewModel, ConfirmationWindow>();
so my initial thought was to try to create this in the unity bootstrapper (because of the registration passing in views and viewmodels) but I can't seem to find a way to do that and pass in the dialog service.
I must note that the constructor for the main window viewmodel also injects the region manager and the event aggregator for Prism; I had tried creating an instance in the bootstrapper and registering the instance but the creation of the region manager vs the injection causes errors. If I declare and initialize the dialog service in the main window viewmodel it of course works but from my understanding of MVVM we don't want the viewmodels to have any knowledge of the views so I'm trying to find another way to do it, without breaking IoC for region manager and event aggregator.
I am new to MVVM and Prism/Unity so my grasp of these concepts isn't fully solidified yet.
I know that Prism comes with this ability but the dialog boxes don't appear to be customizable and don't match my layout/color scheme
You can create whatever you like as dialog, just derive from PopupWindowAction and override CreateWindow (and other methods as needed) to create the dialog you always wanted.
In case anyone sees this later and is curious, my end decision was to get rid of the 'Register' function altogether in favor of a solid convention instead.
Previously, I would use this function and kept a dictionary of all the registered views/viewmodels:
dialogService.Register<ConfirmationWindowViewModel, ConfirmationWindow>();
this would register take the and store them in the dictionary so I could later pass in a viewmodel and create an instance of the appropriate confirmation message view. Instead I removed all code regarding this part of the solution and replaced it with some reflection mixed in with naming conventions.
Step 1: Ensure all views are named with the suffix View at the end.
Step 2: Ensure all viewmodels are named with the suffix ViewModel at the end.
Step 3: Ensure these are all in appropriately named namespaces (views in views namespace and viewmodels in viewmodels namespace).
(most of this ^^ is done anyway)
Final Step: Replaced dictionary with this code:
var viewTypeName = viewModel.GetType().AssemblyQualifiedName.Replace("Model", "");
var viewType = Type.GetType(viewTypeName);
in the dialog interface. Now, no matter what viewmodel is passed in, it will pull the appropriate view with less code and no necessary linking as was done before.
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 would like to learn the most proper way to go about this: I have a Listview in my GameView that is bound to an ObservableCollection<Adventurer>. Upon double-clicking on a cell, I need a new window (or something else if anything is more appropriate) to open and display data about the correct Adventurer according to the cell. So far I haven't been able to. This is what I have so far (it's not much, but nothing I've tried has worked).
The trigger/command in my ListView in GameView.xaml
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseDoubleClick">
<cmd:EventToCommand Command="{Binding Mode=OneWay, Path=ShowAdvCommand}"
CommandParameter="{Binding ElementName=AdvListView,
Path=SelectedItem}"
PassEventArgsToCommand="True" />
</i:EventTrigger>
</i:Interaction.Triggers>
And the command in GameViewModel.cs
ShowAdvCommand = new RelayCommand<Adventurer>(p =>
{
System.Windows.MessageBox.Show(p.Name);
});
The MessageBox is just there to confirm that Eventtocommand was working.
I essentially need a container that will take in the correct Adventurer as a parameter after double-clicking a Listview cell and allow me to display data specific to that instance. I would also prefer to stick to something MVVM-friendly.
Any advice would be greatly appreciated.
Update: I may have made a little progress:
GameViewModel:
ShowAdvCommand = new RelayCommand<Adventurer>(p =>
{
AdventurerView adv = new AdventurerView(p);
adv.Show();
});
AdventurerView:
public partial class AdventurerView : Window
{
Adventurer adv;
public AdventurerView(Adventurer adv)
{
this.adv = adv;
InitializeComponent();
}
}
Now I need to figure out how to make this work in XAML, databinding and such.
Update: ...and then I realized that this completely goes against MVVM. Does anybody have any advice?
Update: Would MVVM Light's messenger help me here? I've been tinkering with it but haven't gotten it to work.
Update: This question is still up in the air. I tried the Prism approach but there was some conflict between Prism and MVVM Light that caused more trouble than it was worth. I'm open to any ideas that are compatible with MVVM Light and the MVVM pattern in general.
Update: Also, I would like to do this in a way where multiple popups can exist concurrently, if possible.
In a similar situation, I've used MvvmLight's Messenger, and it worked really well. On double click, send a message from your viewmodel containing the entity you want to pass. Somewhere you will need to register to receive the message, depending on how you have set up your views and viewmodels to be activated.
You could register to receive the message in your MainPage.xaml, and either pass the entity straight to the view's constructor, or access the view's DataContext via an interface to pass the entity, depending on whether you're using a viewmodel in you childwindow. E.g.
AdventurerView adv = new AdventurerView();
IEntityViewModel vm = adv.DataContext as IEntityViewModel;
vm.SetCurrentEntity(entity);
adv.Show();
The IEntityViewModel might look like the following:
public interface IEntityViewModel<T> where T : class
{
void SetCurrentEntity(T entity);
}
The viewmodel would implement this interface:
public class AdventurerViewModel : IEntityViewModel<Adventurer>
{
public void SetCurrentEntity(Adventurer entity)
{
// Do what you need to with the entity - depending on your needs,
// you might keep it intact in case editing is cancelled, and just
// work on a copy.
}
}
As you've pointed out, proper MVVM wouldn't instantiate the view and pass the view model in through the constructor. You'd be better off binding the ViewModel to the View and there are many different ways of doing it.
One pattern that has emerged is a concept known as a "screen conductor". This is a top level ViewModel or controller that handles which ViewModel represents the main window. Again, many different ways to do this. For example, the ViewModel could raise a standard .net event that the Screen Conductor handles. You could use an message passing system like Caliburn.Micro's EventAggregator or MVVM Light's Messenger. I think MEFedMVVM also has an event aggregator to accomplish this as well.
Caliburn.Micro also has a WindowManager that you can pass in your ViewModel and have it automatically find the corresponding View and manage the window lifetime.
Lots of options. Find the one that works the best for you.
This is a nice case for Prism's InteractionRequest. Essentially, you have an InteractionRequest object on your ViewModel that you raise when you double click (inside your double click command). Your view has an Action on it that handles the Raised event and shows the new view. You pass a new ViewModel to that interaction and that's the DataContext for the window that'll display. Here's some good information to get you started. This is how I display all child windows in my application.
I'm learning MVP pattern, but still have some doubts.
Martin Hunter in his MVC/MVP overview wrote:
In MVP, the view becomes an ultra-thin component whose purpose is purely to provide a presentation to the user. The view catches and handles events raised by the user, but forwards these directly to the presenter who knows how to deal with them.
(...)
However, with MVP the view catches events raised and forwards them to the controller (presenter)
This is fine with buttons and text boxes, but what in case there are some more complex controls? Lets say I'm using 3rd party components, like Devexpress's TreeList control. Assume I want to dinamically build sub-nodes when user clicks expand button "+". Not using any pattern I could code this like that:
private void BeforeExpand_EventHandler(object sender, BeforeExpandEventArgs e)
{
TreeList treeList = sender as TreeList;
MyModelObject nodeObj = e.Node.Tag as MyModelObject;
treeList.BeginUnboundLoad();
//Create sub-nodes depending on nodeObj
treeList.EndUnboundLoad();
}
As you can see there are some View-objects, like BeforeExpandEventArgs, TreeListNode, some specific actions like BeginUnboundLoad(), and so on. In that case my View layer cannot be "ultra thin". I cannot pass directly to Presenter objects like BeforeExpandEventArgs because it would affect the Presenter with some View stuff.
My question is then: How much logic I can put into View layer? For example, is code presented below ok?
private void BeforeExpand_EventHandler(object sender, BeforeExpandEventArgs e)
{
TreeList treeList = sender as TreeList;
MyModelObject nodeObj = e.Node.Tag as MyModelObject;
treeList.BeginUnboundLoad();
e.Node.Nodes = this.presenter.GetNodes(nodeObj);
treeList.EndUnboundLoad();
}
I think the View is responsible for handling this issue.The idea of MVP(MVC) is that you can switch to other View without changing Model & Presenter at least theoretically ;). So that the View logic may stay at view layer as you did.
One thing I don't agree in your sample is a reference to the Presenter.You should do the opposite. The presenter has to have reference to View as well as Model objects. In this case the View invokes its event which Presenter has already listen and Presenter returns array of nodes to View.
In a MVVM WPF application.
How do you set a second windows parent from the ViewModel?
example:
view1 -- viewModel1
viewModel1's command calls:
var view2 = new view2
view2.Owner = <----This is the problem area. How do I get view1 as the owner here from the viewModel?
view2.Show()
EDIT:
See accepted answer below, then read the following edit.
I'am using MVVM light -> http://mvvmlight.codeplex.com/ (awesome btw)
The baked-in messaging system is great. I am now sending a message from the viewmodel to my view telling it to show another window.
For the message I'am currently using a string with a switch statement in the main view to determine what view to open; however I may tinker with the tokens that also are part of MVVM light toolkit.
Thank you!
In my opinion, opening a new window is the responsibility of the View, not of the ViewModel. Personally, I would use the same approach as used for displaying a dialog box (this was discussed in this forum already):
Have the ViewModel send a Message to the View requesting that it opens a new Window.
(alternatively) use an IDialogService or whatever you want to call it which you pass to the ViewModel's constructor. This service will be in charge of opening the Window (or of delegating this task to the View).
This way, you keep a clean separation of concerns and your VM remains testable (you can unit test that the request to open the new WIndow has been sent, but you couldn't test that the window has been, indeed, open).
Does that make sense?
Cheers,
Laurent
From your viewmodel call
Messenger.Default.Send<NotificationMessage>(new NotificationMessage("Open Window"));
And from your view's codebehind (a view that call the second
view) easily write this in the constructor:
Messenger.Default.Register<NotificationMessage>(this, ReplyToMessage);
And also write this method in the view's codebehind:
private void ReplyToMessage(NotificationMessage msg)
{
if (msg.Notification == "Open Window")
{
SecondWindow win = new SecondWindow();
win.ShowDialog();
}
}
I don't have an answer of my own but here's a few links to things I've been looking at lately that might help. I'll also be interested in anything others suggest.
As I understand it, the key thing is, you shouldn't be creating Views from within a View Model if possible, so you need a means of communicating what you need in a loosely coupled fashion.
http://www.codeproject.com/KB/WPF/XAMLDialog.aspx
http://www.codeproject.com/KB/architecture/MVVM_Dialogs.aspx
Handling Dialogs in WPF with MVVM
You can do in this way like you need to create some events and register those in view and call these in view model.and open that pop up window.
Like This example
public class Mainclass : MainView
{
public delegate abc RegisterPopUp(abc A);
public RegisterPopUp POpUpEvent;
public RelayCommand ShowCommand { private set; get; }
public void ShowCommand()
{
ShowCommand("Your parameter");
}
}
inside the view
MainView mn = new MainView();
Register the event here like mn.POpUpEvent += then click on tab button double time and in registers popup method write the code for opening the pop up window.
Prism-Event Aggrigator is good approach, where we can create independent module without dependency. first viewmodel will publish event and then another view or view or viewmodel can subscribe that event from event aggrigator.
in this case Unity container can also use to inject one viewmodel in to another with dependency injection.