I'm developing a WinForms application in C#. I have limited experience in GUI programming, and I am having to learn a great deal on the fly. That being said, here's what I am building.
See the general GUI look at the following link:
GUI http://img227.imageshack.us/img227/1084/program0.jpg
Now, I have done a lot of the work already, but in the very bad Autonomous design pattern. I did not know the project would ever reach a certain size, and, as such, it is time to do some major refactoring.
I have been studying a great deal about GUI design patterns, and the pattern I am wishing to implement is the Passive View (see http://martinfowler.com/eaaDev/PassiveScreen.html). I am looking for some help on how to bring this all together.
Background:
1) Depending on what the user clicks in the "TreeView", the "List" in the bottom left-hand corner will display a list of objects that can populate the "Editor" area. These objects might be a TextBox or a DataGridView. The user toggles the List to choose what he/she wants to see in the "Editor"
2) The model is essentially a folder with data and configuration files. There is an external program that runs on a given directory, creates output files/folders, etc. This program I am developing is designed to effectively manage/configure these objects in a user-friendly way
3) The problem with the way I have been doing things is that it is next to impossible to test, and hence the move to the MVP-esque Passive View design pattern
I am trying to make it so that the program works independently of the View. I have not been able to find any examples where a more complex, interactive view is used with the Passive View pattern.
Questions:
1) Do I need to implement one large interface/view for the entire "look" of the program, then implement sub-interfaces/sub-views for each of the TreeView, Editor, Logger, etc.? Or is there a better "structure" to doing this?
2) When it comes to "handing off" events from the View to the Presenter/Controller (whatever terminology you wish to use W.R.T. the Passive View design pattern), what is the way I should be doing this? Sometimes I have simple properties that need to be updated, and sometimes I need a whole series of steps to unfold.
I would love suggestions and advice on this topic. I have scoured the Internet, and I haven't found adequate examples to help me continue with this project.
Thanks in advance!
Daniel
Here is a simple example that demonstrates the concept of passive views using the MVP design pattern. Because we are using passive views the view has no knowledge of the presenter. The presenter will simply subscribe to events published by the view and act accordingly.
To start out we need to define a contract for our view. This is typically achieved using an interface, essentially, we want to have a very loose coupling with our view. We want the ability to switch to different views or event create mock views for unit testing.
Here is a contract that describes a simple view that will be used to display customer information
public interface ICustomerManagementView
{
void InitializeCustomers(ICustomer[] customers);
void DisplayCustomer(ICustomer customer);
event EventHandler<EventArgs<ICustomer>> SelectedCustomerChanged;
}
It exposes a single method InitializeCustomers that will be used to initialize our view with objects from our model.
We also have an event SelectedCustomerChanged that will be used by our presenter to receive notification that an action has occurred in the view.
Once we have our contract we can start to handle these interactions in our presenter.
public class CustomerManagementPresenter
{
private ICustomer _selectedCustomer;
private readonly ICustomerManagementView _managementView;
private readonly ICustomerRepository _customerRepository;
public CustomerManagementPresenter(ICustomerManagementView managementView, ICustomerRepository customerRepository)
{
_managementView = managementView;
_managementView.SelectedCustomerChanged += this.SelectedCustomerChanged;
_customerRepository = customerRepository;
_managementView.InitializeCustomers(_customerRepository.FetchCustomers());
}
private void SelectedCustomerChanged(object sender, EventArgs<ICustomer> args)
{
// Perform some logic here to update the view
if(_selectedCustomer != args.Value)
{
_selectedCustomer = args.Value;
_managementView.DisplayCustomer(_selectedCustomer);
}
}
}
In the presenter we can use another design pattern called dependency injection to provide access to our view and any model classes that we may need. In this example I have a CustomerRepository that is responsible for fetching customer details.
In the constructor we have two important lines of code, firstly we have subscribed to the SelectedCustomerChanged event in our view, it is here that we can perform associated actions. Secondly we have called InitilaizeCustomers with data from the repository.
At this point we haven't actually defined a concrete implementation for our view, all we need to do is create an object that implements ICustomerManagementView. For example in a Windows Forms application we can do the following
public partial class CustomerManagementView : Form, ICustomerManagementView
{
public CustomerManagementView()
{
this.InitializeComponents();
}
public void InitializeCustomers(ICustomer[] customers)
{
// Populate the tree view with customer details
}
public void DisplayCustomer(ICustomer customer)
{
// Display the customer...
}
// Event handler that responds to node selection
private void CustomerTreeViewAfterSelect(object sender, TreeViewEventArgs e)
{
var customer = e.Node.Tag as ICustomer;
if(customer != null)
{
this.OnSelectedCustomerChanged(new EventArgs<ICustomer>(customer));
}
}
// Protected method so that we can raise our event
protected virtual void OnSelectedCustomerChanged(EventArgs<ICustomer> args)
{
var eventHandler = this.SelectedCustomerChanged;
if(eventHandler != null)
{
eventHandler.Invoke(this, args);
}
}
// Our view will raise an event each time the selected customer changes
public event EventHandler<EventArgs<ICustomer>> SelectedCustomerChanged;
}
If we wanted to test our presentation logic we could mock our view and perform some assertions.
EDIT : Included custom event args
public class EventArgs<T> : EventArgs
{
private readonly T _value;
public EventArgs(T value)
{
_value = value;
}
public T Value
{
get { return _value; }
}
}
I would break them down into separate views with their own presents, and use a "controlling" presenter / view to manage message delegation between them all. Not only will this aid testability but it'll keep your controls fulfilling SRP, too.
So in your case you might have an IFormManager which your main window will implement, and then an IFileManager, ILoggerWindow etc. etc.
Although it might be a bit overkill to use, I would suggest that you have a look at Smart Client Software Factory (from the Microsoft Patterns and Practices team) - it's not being actively developed any more, but it has a good implementation of MVP and does this sort of view composition stuff quite well, so might give you some good ideas.
Related
I'm writing a ViewModel-first MVVM application using Caliburn.Micro
My View contains a 3rd party UserControl that implements a Method I want/need to call from the associated ViewModel. How do I do that while still upholding the MVVM principles?
There exists an old thread here on SO where a similar question is asked in a more specific context. I would appreciate it if someone could flesh-out the approaches suggested there a bit.
Approach one suggests that the View could subscribe to an IEventAggregator message. But wouldn't I have to use the code behind file to do that? (I thought that was a big no no in MVVM)
Regarding approach two, I have no idea how to do that. And regarding approach three, thats what I tried first but somehow I didn't quite get it to work.
Let me clarify your understanding:
Yes code in the code-behind is generally avoided, but only because MVVM makes it so easy to bind to viewmodel properties and commands in order to wire up your visual element with the functionality behind the scenes
Code that is view-specific in the code-behind of the view is perfectly acceptable assuming it doesn't cross the boundary of concern. For instance, I have a view in my application that does some visual processing of the page, and to do so I require that there is code in the view. This code may also interact with the viewmodel layer, but it will not directly reference the viewmodel, therefore keeping my components loosely coupled
If you have controls that need particular methods calling, then creating an event aggregator message to propagate the notification to the view is perfectly fine since you are still maintaining the separation of concern between the viewmodel and view (and the application components remain encapsulated and testable)
Example View (I've left all event aggregator wire up code and potential dependency injection stuff out for clarity):
public class MyView : IHandle<SomeNotificationMessageType>
{
// Handler for event aggregator messages of type SomeNotificationMessageType
public void Handle(SomeNotificationMessageType message)
{
// Call a method on one of the page controls
SomePageControl.SomeMethod();
}
}
Obviously, what you wouldn't do is something like this in the ViewModel:
public class MyViewModel : IViewAware
{
public void DoSomethingThatAffectsView()
{
var view = this.GetView() as MyView;
view.SomePageControl.SomeMethod();
}
}
Which violates the MVVM principles since you are tightly coupling MyViewModel and MyView.
What if you wanted to use the Context property in caliburn micro which allows multiple views over the same view model? The code above would break - even if you checked the View type, you would still end up with spaghetti code e.g.
public class MyViewModel : IViewAware
{
public void DoSomethingThatAffectsView()
{
var myview = this.GetView() as MyView;
if(myview != null)
myview.SomePageControl.SomeMethod();
var myotherview = this.GetView() as MyOtherView;
if(myotherview != null)
myotherview.SomePageControl.SomeMethod();
// ad infinitum...
}
}
Of course this is subjective: it may be that your usercontrol affects the viewmodel and the view in a complex way, in which case you might want to consider looking at the architecture and working out how that usercontrol can better fit
Have you got any background on what the UC is and what the method on it does?
Suppose it's required to create a child window and handle the result from some viewmodel.
For this we could use the code behind.
Example:
// Code Behind
class SampleView : ISampleView
{
public void CreateChildWindow(params string [] args)
{
var childWIndow = ChildViewFactory.Create(args);
childWindow.Closed +=
() => {
if(childWindow.Result)
{
this.ViewModel.DoSomething();
}
else
{
this.ViewModel.DoSomethingElse();
}
};
childWindow.Show();
}
}
// ViewModel
class SampleViewModel
{
private void OnSomeCommandHandler()
{
((ISampleView)this.View).CreateChildWindow(new []{""});
}
public void DoSomething()
{
}
public void DoSomethingElse()
{
}
}
I haven't seen this approach anywhere, however it seems to be rather logical.
Since that I was wondering - what are the possible disadvantages using this pattern?
You have asked a rather subjective question here. Hardcore MVVM developers might say that you should never use the code behind files, whilst others may say that this is completely fine.
The main reason for the separation of code from views is to allow all of the view model code to be easily tested with mock data access classes. Some people will tell you that this separation also allows us to swap out different views of the same content, but I have never needed to do this.
I'm sure that you'll find people that say that you should never open a view from the view model - that the view model should not know anything about the views. These people would use some kind of service layer to launch views (indirectly) from the view models. Others will tell you that launching child views from parent view code behind is exactly what you should do.
At the end of the day, this really is a personal decision about what suits you and the application that you are developing. As we generally test view models rather than views (yes, I am aware of automated UI testing in WPF), I'd say the only reason for not using the view code behind is because that code won't be tested (at least in the normal way along with the view model code).
However, do we ever really need to test the simple code that launches a child window? In my opinion, we don't... Microsoft have already tested that for us. So to answer your question, I'd say that the disadvantage of using code behind to launch child windows will depend on your personal situation, but it is unlikely to be a serious disadvantage, if any.
In this hypothetical question, let's say the ViewModel publishes a rather complex event that the View subscribes to. The View then manipulates multiple screen elements based on the state within that event. For example, several buttons are made visible/hidden, or enabled/disabled, or maybe a storyboard is started.
// purely as an example:
public class SomeEvent
{
public bool ShouldShowAddButton { get; set; }
public bool ShouldShowDeleteButton { get; set; }
public bool AddButtonEnabled { get; set; }
public bool DeleteButtonEnabled { get; set; }
}
Since the VM does not know anything about the View, it can't actually reach in and do these things and instead relies on the event. Standard MVVM practice, I think. (Another option would be to make each of these items be their own published event, sent one after another.)
However, what if the VM could call into the View without knowing anything about the View?
public class MyViewModel
{
public Action OnShowAddButton { get; set; }
public Action OnShowDeleteButton { get; set; }
...etc
private void OnSomeStateChange()
{
// here, we'd normally publish the SomeEvent class
// instead, we could just call OnShowAddButton (or whatever) instead
}
}
public class MyView
{
public MyView()
{
this.myViewModel.OnShowAddButton = () => ...;
...etc
}
}
Is there a reason this would be frowned upon, other than not being "typical" of MVVM design? As far as I can tell, it's still maintaining the correct level of separation.
I think this variation is mixing a bit of MVC with a bit of MVVM, although it's none of both. So, the Model-View part of the pattern is solved in your proposal by injecting the models straight into the view implementation and then send some kind of commands, via events.
You then need to solve or go around the View-Model part of the pattern by either providing properties in the model that can be set directly by the view, or by exposing some events in the view and do the same kind of injection in the model.
I think it will get ugly. Even if the model is only a set of observable entities and you control them from somewhere else (the controller? :)).
I can already see the code, countless events and properties mixed and mingled... But it all depends on how complicated your UI will become, how many views you will have and how complex will they get. In a view with 10+ buttons and/or inputs I think is a bad idea to go with this approach.
I say that as long as you do not have a dedicated MVVM infrastructure, like WPF or HTML, there's no point in implementing your own. You can't get to that beautiful degree of separation only with a hand-coded framework. You need some support to entirely separate the UI code from the model, do bindings and so on.
Perhaps you can comment some more on what you want to use it. If you need it for a client framework (like HTML/JS) or for a Windows Forms implementation then there may be some dedicated solutions you could use, or better, some easier paths you could take.
This all comes from a guy who implemented an MVP variation on top of ASP.NET Web Forms. If I only could turn back time.
I'm trying to analyse some code here that's been designed using an MVP Approach. No specific MVP Framework has been used. This is all hand-written code.
//Interface Representing our View
public interface IFooView
{
string SomeScreenValue
}
//Presenter Implementation
public class FooPresenter
{
private readonly IFooView _view;
public FooPresenter (IFooView view)
{
//The presenter gets instantiated with a reference to a view.
_view = view
}
public void SomeButton_Click(object sender, EventArgs e)
{
_view.SomeScreenValue = "The Result";
}
}
//The Page Implementation
public class FooPage : System.Web.UI.Page, IFooView
{
private FooPresenter _presenter;
protected void Page_Init(...)
{
_presenter = new FooPresenter(this);
//<-- The View has a Presenter, which references the same View...
Button1.Click += new EventHandler(_presener.SomeButton_Click);
}
}
It works in that it allows the developer to move the business logic away from the code behind into classes, while still affecting the View. But the absense of an actual Model, and the way in which the View => Presenter => View relationship is setup is just a little irksome to me?
So is the above situation a valid implementation of the MVP Pattern ?
This is almost MVP in that your Presenter is de-coupled from the view in such a way that when it updates the UI state it does so through the IFooView interface. However, having a method within your presenter that conforms to a standard .NET event handler seems wrong to me. I would make IFooView raise an event when a button click occurs, then your page can perform the task of handling the button click as you currently do, then raising the event which your Presenter handles. This event can be more closely related to the domain, for example you might want an event such as RecordUpdated exposed via your IFooView.
This will make it easier to provide a mock implementation of IFooView for unit testing, which is after all a big advantage of using an MVP / MVC / MVVM pattern.
If you do not have any data coming from a back-end service, or database, then in the case of simple applications it is OK for the Presenter to take on the role of the model as well. This is the case in your trivial example. The same can be done in MVVM, where the ViewModel can take on the Model responsibilities also. However, I would recommend creating a Model if you do anything non-trivial. In your case, the Presenter would delegate to the Model for maintaining state and would use some sort of 'service' to persist changes to this model, or retrieve model objects from web services.
Yes it is.
But...
I should change the presenter construction to FooPage constructor instead. Sometime you want to handle the preInit event and that´s not possible with this setup.
Yes it is, this is the "passive view" variant of model view presenter. In this variant, the view has no knowledge of the view whatsoever. The view is dumb and fully controlled by the presenter.
The MVP pattern was described by Fowler in 2004 and he retired it in 2006 by splitting the pattern into supervising conroller (sc) and Passive View (pv). In sc, the view is bound to the model and in pv not, in pv the view is only changed by the presenter directly.
I'm writing an application (Silverlight and WPF) using the MVVM pattern and the Prism framework. In my application I have a grid that contains a list of customers. Under that, I various views that present customer details. All of the information is fed from a WCF service that provides data from queries as well as callbacks which fire events when the data has been received. The detail information is updated when the selected item in the grid is changed. There is also a filtering view that controls the date range for the detailed information.
I also need to implement a similar set of views, but for a specific customer. The information presented is the same, so obviously it would be best to reuse the same view and model classes.
My initial thought was to build a separate intermediate service that sat between the models and the WCF service for both scenarios. I would then bind the models to the specific service by registering instances by name.
Unfortunately, this would mean that I would have to instantiate a lot of the classes myself instead of relying on dependency injection which I would prefer.
So, for all the MVVM gurus out there, how should the views, models, and services be structured to best use the features of the Prism framework and promote code-reuse?
Many thanks!
==== Edit: added following text and example ====
Here is a simple example that I hope explains what I'm trying to accomplish.
public class CustomerViewModel : ICustomerViewModel
{
public ICustomerView View { get; private set; }
private readonly ICustomerService customerService { get; set; }
private Customer customer;
public CustomerViewModel(ICustomerView view, ICustomerService service, IEventAggregator eventAggregator)
{
customerService = service;
eventAggregator.GetEvent<SelectedCustomerChangedEvent>().Subscribe(CustomerChanged);
eventAggregator.GetEvent<CustomerInfoUpdatedEvent>().Subscribe(CustomerUpdated);
View = view;
View.Model = this;
}
public string Name
{
get
{
return customer.Name;
}
}
public string Email
{
get
{
return customer.Email;
}
}
public void CustomerChanged(int customerId)
{
customerService.RequestCustomerInfo(customerId);
}
public void CustomerUpdated(Customer customer)
{
this.customer = customer;
}
}
This customer view model based on the current design where the customers are in a grid. Selecting a customer fires the SelectedCustomerChangedEvent which will cause the view model to request information.
It is fed from an underlying WCF service that is using a callback mechanism to provide data (the data can take a long time to retrieve / calculate so a simple WCF call won't work). This works just fine. The problem is that I want to reuse this same view and model in a different area of the application that displays information about a specific customer instead of the current selected customer.
My initial thought was to create an intermediate service that handled the SelectedCustomerChangedEvent for the list and a similar event when the customer-specific view is opened. It would then provide data to the model through the same CustomerInfoUpdatedEvent.
The problem is that since I would now have 2 services that implement the same interface, I would need to name them and then have the view model somehow know which one to retrieve from the container.
I know I've probably made a design error. The good news is that I have time to fix it, but I'm not sure how to fix it.
If the Customer class is the same for all customers (including your specific customer), then use a single service, the same views, and the same model.
Can you tell us why this would not work?
Hmm... there is a lot of information here, but I will take a stab at this.
There's really no reason to complicate this as much as you are trying. It feels like you are receiving callback events from your WCF service... am I right? If so, you want to update the UI if the incoming WCF callback pertains to a customer that the user is viewing. I'll work from these assumptions... let me know if I misunderstand.
I think you have almost what you need. I think all you need to do is the following:
From your WCF callback handler, raise an event with the EventAggregator passing the new customer information along with the customer ID.
From any ViewModel's constructor, subscribe to the CustomerUpdated event and add a filter for the customer ID you are looking at in your view model. You are missing this, but it's critical, otherwise you will get a firehose of events that don't pertain necessarily to your instantiated ViewModel. There is a sample of this technique in this quickstart: http://msdn.microsoft.com/en-us/library/dd458918.aspx
Again, this is my best effort at understanding what you are trying to accomplish. Let us know if it's not.