MVP Presenter to Presenter communication - winforms

I'm currently preparing core framework for our upcoming project based on WinForms and MVP design pattern.
I'm not sure, what would be the best way, how to communicate between two Views/Presenters. To be more specific - I have a ListView and a DetailView. When user clicks on an item in the ListView, I need to display edit form for this item, which in my case is DetailView.
Options:
Should ListPresenter create DetailPresenter on the click event? (A Factory could be of a help.)
Should instance of DetailPresenter be injected in ListPresenter constructor?
I feel 2) might be the "right" solution, but I would prefer creating DetailView/DetailPresenter just in time I really need it - i.e. when user clicks the button.
The next problem, I don't know how to go about it is the objects lifetime. When I inject a View into Presenter, who is responsible for the cleanup? I'm used to behaviour, where cleanup is made by the same party who created it. But in this case I could imagine View could be disposed by the Presenter.
I hope the questions are not too generic, I have read a lot of articles about MVC/MVP, but they mostly don't go further than showing how to implement single View-Presenter communication.
Thank you.

You could wrap the ListPresenter and the DetailPresenter in a ListDetailPresenter.
public class ListDetailPresenter
{
private ListPresenter _listPresenter;
private DetailPresenter _detailPresenter;
public ListDetailPresenter()
{
_listPresenter = new ListPresenter();
_detailPresenter = new DetailPresenter();
_listPresenter.SelectionChanged += OnSelectionChanged;
}
private void OnSelectionChanged(object sender, EventArgs e)
{
_detailPresenter.SetItem(_listPresenter.SelectedItem);
}
}

Related

MVP: Is it the View or the Presenter that should know of the Model?

Relatively new to patterns, let me straight away show an example in the context of WinForms.
I have a basic MVP Passive View structure, which one should I go ahead with:
public partial class UserView : Form, IUserView
{
public event EventHandler Save;
public UserView()
{
InitializeComponent();
new UserPresenter(new UserModel(), this);
}
}
public class UserPresenter
{
public UserPresenter(IUser model, IUserView view)
{
view.Save += (sender, e) => model.Save();
}
}
or
public partial class UserView : Form, IUserView
{
public event EventHandler Save;
public UserView()
{
InitializeComponent();
new UserPresenter(this);
}
}
public class UserPresenter
{
public UserPresenter(IUserView view)
{
var model = new UserModel();
//assuming I have the logic to bind property values from View to Model
view.Save += (sender, e) => model.Save();
}
}
My questions are:
1) Who should know of the concrete instance of model User, View or Presenter?
2) What will be the benefit in that case?
3) Suppose my Model is never dependent on the View. In that case what's wrong if View knows Model? After all UserView is made to present UserModel isn't it?
4) If Presenter should interact with only interfaces of Model and View, then to call model.Save in Save eventhandler, where do I get the concrete instance of Model from?
There are two duplicate questions here and here, but they aren't exactly dealing with my scenario I guess..
Strictly speaking, you should have the following rules:
Model does not know the View or the Presenter.
View does not know the Model or the Presenter.
Presenter knows both Models and Views, but only through their interfaces.
The Presenter coordinates all communication between the Model and the View, typically by handling events that are raised by the View. So to answer your questions:
1) Who should know of the concrete instance of model User, View or Presenter?
Ideally, neither. The Presenter should be communicating with UserModel through an IUserModel interface. The concrete instance is injected into the Presenter (e.g. through its constructor).
2) What will be the benefit in that case?
The primary benefit is for automated unit testing. You can inject mock Models or Views to test units in isolation.
3) Suppose my Model is never dependent on the View. In that case what's wrong if View knows Model? After all UserView is made to present UserModel isn't it?
There's nothing inherently wrong with it. There are variations of MVP that support direct communication from the View to the Model, typically to take advantage of data binding. You lose some testability in exchange for not having to write the binding code from scratch.
4) If Presenter should interact with only interfaces of Model and View, then to call model.Save in Save eventhandler, where do I get the concrete instance of Model from?
Depedency injection, such as the simplified example shown below.
public class SamplePresenter
{
public SamplePresenter(ISampleModel model, ISampleView view)
{
view.Saved += (sender, e) => model.Save();
}
}
public interface ISampleModel
{
void Save();
}
public interface ISampleView
{
void Show();
event EventHandler Saved;
}
public class Program
{
[STAThread]
static void Main()
{
ISampleModel model = new SampleModel();
ISampleView view = new SampleView();
SamplePresenter presenter = new SamplePresenter(model, view);
view.Show();
}
}
What's wrong if view knows model? After all UserView is made
specifically for UserModel isnt it?
Nothing. It's accepted practice in the Supervising Controller variant of the MVP pattern. The view interacts directly with the model for simple operations while more complex operations are marshalled throught the presenter. While in Passive View, everything goes through the presenter.
Additionally, see Jeremy Miller's Build your own CAB series to get a better idea on the differences between the two approaches: Supervising Controller and Passive View.
The Presenter should know about the Model, the View should not. A presententation layer is a good idea in many user interface applications. A presentation layer is simply an adapter. It presents an interface that's easy for a user interface layer to use (i.e., it presents lots of events, bindable properties, and so on) while obscuring the underlying data layer. This makes the data layer easier to re-use.
EDIT
So why can't the view just talk to the model directly? It certainly can. The problem is that there is usually an impedence mismatch between the model and the view. In other words, the programming interface that's natural for the view to use does not match the interface that's natural for the model to expose. If you adapt the model to suit the view's needs, then you end up creating a strong coupling between the model and the particular type of interface you're using.
For example, your app might be a GUI app today, but what if tomorrow you're asked to produce a version for the cloud? The events and bindable properties that are helpful for Winforms will just get in the way when you try to switch to WCF Rest. If you use a presentation layer, then adapting your code to the new environment will be much easier.
If it's not too much for your introduction to presentation patterns, I'd urge you to take a look at the Presenter-first variant of MVP.
In this variant, and providing an answer to your question, the presenter knows both the model and view but only via interfaces. Neither the view, nor the model know of each other. The presenter co-ordinates each via events and methods.
http://atomicobject.com/pages/presenter+first
http://spin.atomicobject.com/2008/01/30/presenter-first-get-your-triads-talking/
Example:
Class Presenter {
private IModel model;
private IView view;
void Presenter(IModel model, IView view) {
_model = model;
_view = view;
}
void Initialise() {
// Attach handler to event view will raise on save
_view.OnSave += HandleViewSave();
}
void HandleViewSave(){
_model.Save(_view.GetStuffToSave());
}
}
Very basic example but illustrates the point. The presenter is merely a conduit for communication between the view and model.
Creating the presenter can be done with Poor Man's DI or a proper container:
Presenter p = new Presenter(new CustomerModel(), new CustomerForm());
Note that AtomicObject recommend no reference to presenter, so it actually looks like this:
new Presenter(existingCustomerModel, existingCustomerForm);
existingCustomerModel.Initialise();
The fact that the model and view have scope means the presenter also stays in scope via its references... clever.

WPF DataBinding with Code First Entity Framework

I am just getting familiar with WPF databinding. I've figured out most of the basics but I'm having trouble figuring out a couple of things.
First, let's say I have an object called Synth that has a collection of Banks. In turn, a Bank has a collection of Patches. I have a synth window to which I set the DataContext to a single Synth object. I have one listbox (lstBanks) that shows all the banks ({Binding Banks}) and another (lstPatches) that shows all the patches ({Binding ElementName=lstBanks, Path=SelectedItem.Patches}). This all works great. I see the applicable patches when I select a bank.
Question 1: How can I load a selected Patch into a dialog window with two-way binding, yet cancel those changes if DialogResult = false?
Right now, I have a patch dialog that receives a patch in the constructor which it sets as its DataContext, but I am only using OneWay binding. This happens on the doubleclick of lstPatches.
private void Patch_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{
Models.Patch patch = (Models.Patch)((ListBoxItem)sender).DataContext;
PatchEdit p = new PatchEdit(patch);
p.Owner = this;
if (p.ShowDialog().GetValueOrDefault())
{
// Do stuff if applicable
}
}
Here is my PatchEdit constructor and OK button event:
public PatchEdit(Models.Patch Patch) : this()
{
this.DataContext = Patch;
}
private void btnOK_Click(object sender, RoutedEventArgs e)
{
Models.Patch p = (Models.Patch)DataContext;
p.Name = txtName.Text;
p.MidiProgramChangeValue = int.Parse(txtPCN.Text);
this.DialogResult = true;
this.Close();
}
If the user clicks OK on the patch dialog, that's when I set the properties from the form back to the DataContext. I wasn't sure if this was the best way to do it. I don't want to really save the changes until the user clicks OK on the main synth window. So all bank and patch edits should only remain local, and only be "locally" committed if the user clicks OK and not Cancel on the dialog.
Question 2: Once a patch is updated via the dialog, how can I get that change reflected in lstPatches?
I understand that directly navigating my models which are essential of type DBSet aren't Observable. I've seen posts regarding using an Observable collection, but doesn't this just complicate something that is supposed to be easy with WPF databinding? If it's the only way, how do I accomplish this easily using my code first models?
Question 1: Bind to a second/temporary object. If the user cancels, throw it away. If they don't, use it to update your original object. Data-binding doesn't really offer an "undo" or "reset" method.
Question 2: No, using ObservableCollection's doesn't complicate things. It is the recommended way of doing things. It is actually much harder to work without them.

WPF UI Scenario - Best way to add a functionality in 50 views?

I want some suggestions to implement this functionality with a neat design and without any code replication. I have an application with many views and grid control in most of the views. I need to add an export functionality (export records to excel).The grid control supports this OOB, just need to call 'Grid.Export()'. I am planning a UI button on the side of every grid and call this method.
So, obviously I need to write the code in code-behind only since I need the control's instance to invoke the method. But, I like to keep the code in one place and somehow invoke the code from all Xamls. (all WPF views).
One technique is to write a BaseView class and derive all Views from this.
But would like to know if WPF suppots any techniques by which I can achieve this. (behaviours etc..?)
Thanks,
Mani
Create a UserControl that includes both the datagrid and the export button. In effect, make it part of the grid itself.
Use this UserControl instead of the default datagrid in all of your views, and you're done.
Furthermore, if you ever have to modify the look and feel of your button or its behaviour, you have only one place in which to change it, and it will be updated in all of your views.
One of solutions is to use WPF routed command.
Note: I wrote this answer with the assumption that your "View" is a subclass of Window class.
First, add a custom routed command to your project.
public static class MyCommands
{
private static readonly RoutedUICommand exportCommand = new RoutedUICommand("description", "Export", typeof(MyCommands));
public static RoutedUICommand ExportCommand
{
get
{
return exportCommand;
}
}
}
In each View, set your custom command to Button.Command and bind a target object to Button.CommandTarget.
<Button Command="local:MyCommands.ExportCommand" CommandTarget="{Binding ElementName=dataGrid1}">Export</Button>
Firnally, in your Application class (named App by default), register a command binding between your custom command and Window.
public partial class App : Application
{
public App()
{
var binding = new CommandBinding(MyCommands.ExportCommand, Export, CanExport);
CommandManager.RegisterClassCommandBinding(typeof(Window), binding);
}
private void Export(object sender, ExecutedRoutedEventArgs e)
{
// e.Source refers to the object is bound to Button.CommandTarget.
var dataGrid = (DataGrid)e.Source;
// Export data.
}
private void CanExport(object sender, CanExecuteRoutedEventArgs e)
{
// Assign true to e.CanExecute if your application can export data.
e.CanExecute = true;
}
}
Now, App.Export is invoked when user click a button.
Sample is available here.

Easy way to make Silverlight combo boxes perform like HTML select boxes?

I'm fairly new to Silverlight but experienced in web development, and I'm finding myself highly annoyed with Silverlight's default combobox. It seems to be lacking any concept of use for regular data entry. Primarily I'm wishing it would function like an HTML select box, where you can hit the drop down, then type a letter and it takes you down to the first item with that letter. Is there an easy way I'm missing to make it function like this, or a third party control that can do this?
Thanks!
You could write an attached behavior to provide this functionality. The problem is that the items in a ComboBox in Silverlight aren't always strings. They may be entire controls that the user has templated as the ItemTemplate. If you know yours are going to be string you can implement a Behavior<ComboBox> to attach to the KeyDown event and select the correct one.
public class HTMLSelectBehavior : Behavior<ComboBox>
{
protected override void OnAttached()
{
AssociatedObject.KeyDown += OnKeyDown;
}
private void OnKeyDown(object sender, KeyEventArgs e)
{
SelectedItem = AssociatedObject.ItemsSource
.FirstOrDefault(i => i.ToString().BeginsWith((char)e.Key));
}
}
This is off the top of my head so it may not be exactly right and definitely lacks many safety checks, but it should give you an idea.

using MVVM light messenger with Silverlight 4 ChildWindow dialog class

Greetings! Am enjoying using MVVM light -great framework - has made my life much easier, and has removed a number of barriers that were proving difficult to overcome....
Question:
I am attempting to setup a custom dialog box for editing messages users send to each other. I am attempting to construct a silverlight custom dialog box using the ChildWindow object using the MVVM framework.
Was wondering if there were any suggestions as to how this might be accomplished
Following the dialog MVVM sample code I found here: http://mvvmlight.codeplex.com/Thread/View.aspx?ThreadId=209338 I got stuck because the ChildWindow dialog object in Silverlight is async, and has a different Result class.
So - the Basic idea I have now is using the view model of the class (in this case the Matrix.MessageViewModel) to create an instance of the custom dialog box, send it through the Messenger.Send<>, process the registered message in the view to display the dialog, then have the ChildWindow dialog box's Save button handler fire a Messenger.Send with the modified contents that is then stored using the Save method on the viewmodel...
Seems a bit round-about - so wanted to make sure there wasn't a cleaner way....
Relevant code bits:
view model:
messageDialogBox = new MessageEditorDialog(
selectedMessage, this.SelectedSiteId, this.LoggedOnEmployee.Id, this.Projects);
DialogMessage editMessage = new DialogMessage(
this, messageDialogBox,"Edit Message", DialogMessageCallback);
Messenger.Default.Send(editMessage);
View:
public ViewHost()
{
InitializeComponent();
Loaded += new RoutedEventHandler(ViewHost_Loaded);
if (!ViewModelBase.IsInDesignModeStatic)
{
// Use MEF To load the View Model
CompositionInitializer.SatisfyImports(this);
}
ApplicationMessages.IsBusyMessage.Register(this, OnIsBusyChange);
Messenger.Default.Register<DialogMessage>(this, msg => ShowDialog(msg));
}
private void ShowDialog(DialogMessage msg)
{
MessageEditorDialog myDialog = (MessageEditorDialog) msg.Target;
myDialog.Show();
}
Dialog Save:
private void ButtonSave_Click(object sender, RoutedEventArgs e)
{
Messenger.Default.Send<Message>(
this.MessageItem, CommandMessages.MessageTypes.MessageSave);
}
This ties back into the ViewModel, that has a Messenger.Default.Register<> watching for the CommandTypes.MessageSave which routes the resulting MessageItem to the model for storage.....
That's pretty darn close to what I'd do, except there are a couple of things I do differently.
I'd have a view model for my dialog view, and move the messaging logic to it rather than the view's code behind.
I'd use a Save command in my view model, and bind the ButtonSave to that command. That moves the save logic to the view model instead of the code behind of your view.
You're using a different message when the save button is clicked. Also, you're not using the DialogMessage's callback. Assuming you change to using a Save command, you could save the message in a private member in the view model, then use message's callback when the user saves.
You may want to think about re-using the dialog view, or ensuring that the view is being cleaned up correctly so you don't end up with a memory leak.
Here's the changes I'd make to your view model following suggestions 2 & 3.
public class MessageEditorDialogViewModel : ViewModelBase
{
private DialogMessage _dialogMessage;
public RelayCommand SaveCommand { get; private set; }
public DialogMessage Message { get; set; }
public MessageEditorDialogViewModel()
{
SaveCommand = new RelayCommand(SaveCommandExecute);
}
private SaveCommandExecute()
{
Message.Execute();
}
}

Resources