We've been using the MVP pattern and Winforms with a fair amount of success. However, a question always pops-up about MVP:
What is a good granularity for presenters?
What I mean by that is: With Winforms, a fine-granularity usually works quite well for user controls. That way, it's easy to reuse user controls and use them as building blocks while designing more complex GUIs. However, having the same (fine-)granularity with presenters seems to be a problem.
On one hand, having coarse-grained presenters hinders the ability to use "plug-in" controls and it sorts of violate the DRY principle: Multiple presenters often need to implement the same logic (populate a list of customers, for instance), which is used by multiple, more complex, controls.
On the other hand, fine-grained presenters seem to limit the ability to reuse controls in different situations. For instance, an editing view might sometimes need to save the customer right away; sometimes it needs to link it to something else; sometimes is just needs to validate it; and so on. It often depends on the more complex control. But there's also a fair amount of shared behaviour.
Note that, in both cases, 1-presenter-1-view is achievable. What is considered "1-view" changes.
What is usually considered best-practices for presenter granularity using MVP and Winforms?
Fine-grained presenters and customizable behaviour through options or something of that nature?
Coarse-grained presenters and low presenter reusability?
Something else?
Disclaimer: We mainly use Supervising Controller but I think it also applies to Passive View. Sorry for the long question, too.
We use MVP at all of our clients and this is definitely a conversation that comes up in more than one occasion. How clean should our code behind classes and presenters be? Having said that, we have chosen to use the coarse-grained presenter approach. Basically, every form would have its own presenter and would only get and set properties of any of the controls on a particular form using its view. Populating controls-a call to a db to populate a combobox for example-is located in a public service class. Any validation of user inputted data is located in a BO class which can be reused by any and/or all of the presenters. I hope this helps.
In my CAD-CAM system my presenters don't use user controls. User controls reside in the view which reside in a EXE assembly that implement the view interfaces the presenter use.
If want to display a list of customers I hand it off to the view which has a DisplayCustomerList and it uses whatever combination of user controls it needs to display the customer list. If multiple views show the customer list in the same way then in the ExE/View assembly they share a user control or class for doing that. That class doesn't go outside of that assembly.
Our software is adapted to run many different types of metal cutting machine. So we place a lot of emphasis on being able to rip off the UI and replace it with a completely different UI (corresponding to a different machine). All of these UIs reference the same set of core assemblies.
The hierarchy looks like this
View EXE
Presenter Implementation
Command Assembly - commands are executed by the presenter that modify the model
Presenter Interfaces
Model Assemblies
Off to the side are loadable assemblies that define dynamic content like what file types can be loaded, reports, cutting device drivers, etc. These implement various interfaces found in the model assemblies
One thing I do is that I don't impelment a view presenter for every dialog. If the dialog is tightly bound with a command then it is defined, created, and used along side the command class. Occasionally a group of related commands will share a dialog (File handling for example).
The essential question I ask when using MVP is "What happens if want to completely replace the forms with something else?". The answers to that question will identify where you are too dependent on a particular user control or form engine.
The biggest problem (and one that I haven't got a good answer for) of my setup is that current IDEs and langauges make it very easy to tie user controls to database records. It is so productive compared any other setup it tends to dominate the design. I haven't had to deal with the issue much in my CAD-CAM application so I don't have any answer other than passing the dataset to the view and let it handle it. This site has some patterns that may be of use in this situation.
Related
I'm working on an application written in C# and WPF.
There's a view with a layout that consists of three separated sections (sub views).
A "content" view that contains the current main content (say, a listview of products).
A view located on top of it, containing tools and option
controls.
The main menu view on the left.
I use the .NET dependency injection for my application (Microsoft.Extensions.DependencyInjection, Microsoft.Extensions.Configuration.Abstractions)
When a ViewModel is set for the content view, I also want to set a ViewModel for the top view. These ViewModels have to communicate/reference eachother.
Like, when a command on the top ViewModel is executed, the content ViewModel should be notified and/or do something, and vice-versa.
Say I have a TopViewModel and a ContentViewModel.
One bad thing I could do is:
Requiring the ContentViewModel in the constructor of TopViewModel
and requiring the TopViewModel in the constructor of ContentViewModel.
Of course that won't work, because it's a circular reference.
The alternative I can think of, is just requiring the TopViewModel in the constructor of ContentViewModel and don't do this same kinf of thing with the other class.
The constructor code of ContentViewModel could then listen to events of TopViewModel. The TopViewModel doesn't know anything about ContentViewModel, which can be a problem if it needs to reference it for some logical reason.
Some content views can have multiple top views (they change like when the user selects something)
I'm taking this quite serious. Everything I can think of seems ugly and bad practice to me. While I think this is a quite simple and common situation.
What is the best, generally accepted solution to this that doesn't break the OOP rules?
What is the best, generally accepted solution to this that doesn't break the OOP rules?
Instead of storing a direct reference from one view model to another, you should consider using an event aggregator to communicate between the view models in a loosely coupled way.
This removes the tight coupling between the view model classes and makes your application easier to maintain and evolve over time.
The idea is that a subscriber observes the event aggregator instead of the publisher and the publisher knows only about the event aggregator and not about the subscriber(s). Please refer to the following blog post for more information.
Using the event aggregator pattern to communicate between view models
I'm working on a WPF project using the MVVM pattern and I was wondering if I can improve the internal structure of my ViewModel by abstracting its exposed properties into separate classes.
It's common practice for VMs to contain lots of properties laying around in the same class: Some are used to retrieved user inputs, some are used to expose commands, others to expose the models, and probably some other properties for the view model's own business logic. Not to mention that these properties often have set and get bodies that adds some bulk to the package. This can quickly become messy inside a VM class and finding one's way there can become challenging.
As a way to solve this issue, I am exploring with my team the idea of grouping properties inside my VM into different categories. As a first approach, I chose to group them this way:
ViewData, UserInputs and Commands, each one represented by its own class. Then I referenced them as properties inside my VM class.
My intention is that these classes will only act as placeholders to free up the bloat in my VM and keep it clean and focused only on interaction logic for handling user events.
It's a simple refactoring, but I get the following pros:
Cleaner and readable VM.
Easier binding from the XAML because you know what the entry point is/should be.
Let me elaborate on the latter one: If I want to bind a text box to a property of my VM, I know the binding expression should start with Userinput.MyVMProperty. If I need to show a value from my VM, I know my binding's entry point is going to be ViewData.MyOtherVMProperty. Binding intellisense will also become better because when you know your entry point, the
suggestion list would be smaller and more focused. This also works the other way around: when reading through your XAML controls, any binding that starts with UserInput necessarily means it's a a control that should send data back to the VM.
The only cons I can find is that this will require creating extra classes for each VM, but I believe it's a fair price to pay for the benefits you get.
Take note that the grouping I suggested may not be the best, but I don't mind any other grouping as long as it solves the problem with bulky VMs.
So, has any one ever tried a similar pattern? Do you think this is a good idea/practice? What other good practices I can use to improve my VMs?
Bonus question: One developer in my team who seemed to agree with this idea, suggested to go the extra mile and consider the grouped classes as VM dependencies and that they need to be injected inside the VM. What do you think about this?
So for every ViewModel you need to create own inner classes for every group. You cannot use Interfaces because ViewModels have different properties and commands
Then did you considered that every "groupclass" must to "know" about other groups for ViewModel will work properly.
In my opinion Class should be solid logical structure with minimal outside dependency.
Based on the pros you trying to achieve I can suggest another approach without changing structure of the ViewModel classes
Readability can be achieved partly by #regions.
Or use Partial class for separating different groups in the different files,
while keeping them inside one logical structure
Intellisense can be improved by naming conveniences - using prefix based on group property belong to. For example UserInputMyName, ViewDataFullName or CommandDelete
So I've just started developing C# WinForm applications and each project I've been working on seems to be larger and requires more user functionality. If I add all of the functionality to one form, obviously it can get out of control very quickly. My last project I would divide up the functionality into individual Forms, and whenever someone say wanted to perform "Feature1" I would instantiate Feature1 Form and show it as a dialog with the main Form as it's owner (so they couldn't click off it).
I'm just curious of what other methods are out there for keeping code organized within Forms. If you are forced to have tons of features/functionality on a single form is there a good way to keep items organized? I simply hate having a code file with hundreds/thousands of lines long.
The answer may simply be in the design, try to design the UI up front so you can utilize multiple forms?
Another example I faced. I created a Tab Control and had about 5 tabs. Those 5 tabs had tons of features and were all stored in the same CS file. What other options did I have? Create a new custom TabControl class with my specific functionality for that tab in it?
I don't mind reading, so if there are decent articles out there feel free to link them!
The go-to method is a Controller/Presenter. The idea is that the window should only be responsible for actually handling the UI events of its controls, and it should do so by calling methods on a Controller which do the real work for the window. The window can either have the handlers necessary or it may link the UI events directly to Controller methods; the former is usually the easier method, but it can be tempting to sneak in a line of code here or there that really should be in the Controller method. By doing this, you sever the layout and presentation logic in the Form class with the business logic in the Controller.
Mark Hall's suggestion of User Controls is also a good one. By creating UserControl classes for tabs or for common UI control combinations, you sever the logic responsible for laying out that part of the UI from the main form's code, and the control then just "drops in" and the window works with it in a much simpler way. This is a must for implementing custom but reusable controls; the fundamental tenet of DRY is that if you have two lines of code in two different places doing the same job to two different but interchangeable things, those lines of code should be merged into one place.
I have used UserControls in my projects to group functionality into separate objects that can then be added to your Form.
I tend to split my logic code from the UI as recommended. If you do this, you need to be somewhat cautious with how calls are made across the application to avoid Cross Thread Exceptions. I was taught to create delegates and events to update the UI from the logic class, but MSDN of course also has a lot of information on making thread safe calls.
I know this is a late answer, but if anyone still reads this question, another way to reduce the number of lines of code in your form is to use Data Bindings. If you are using properties, Data Bindings make it so that you don't have to constantly write handlers just to do something like PropertyName = textBox.Text;. Data Bindings work with both datasets and objects.
I have a split container in the left panel is a user control with buttons. In the right panel is an initial user control that will change based on which button is pressed. What I want to know is how does one let the Form with the spilt panel know to paint in view x from the presenter of the button view?
In theory, the Presenter should have access to the Views, in which case the Presenter should be notified about any button clicks from the view in the left panel and then update the Form to show the view in the right panel.
How exactly this is accomplished depends heavily on your specific implementation. Architecture patterns are guidelines... there are no hard and fast rules which one must follow (unless you are using an MVP library of some sort, in which case you will be constrained by that library's implementation).
EDIT: To answer your question below, Chip...
Again, that is wholly dependent on your implementation. In some cases, it may make sense to have one massive Presenter and dozens of views. In other cases, it may make sense to have one presenter for each view. Even if you have multiple presenters, though, you will still need to maintain a hierarchy so that the presenters can talk to one another. So somewhere, at some level, a presenter is going to have knowledge of both the button click and the empty container waiting to be filled, even if that knowledge comes indirectly through another presenter.
EDIT 2: (In response to your updated comment) There are no hard and fast rules, but one common trait among MVP implementations is that the Presenter retains at least partial control. That means that the Presenter must have some level of access to all relevant UI elements. If you nest views within views, then you'll still need to devise a way for the Presenter to interact with them.
This is a performance issue and also a refactoring problem.
I have a .NET user control (UCA.ascx)... which in turn uses 5 other User Controls internally.
Each of these user controls run into greater than 2000 lines of code.
The web page loads UCA.ascx first ... then the other 5 user controls are loaded dynamically based on actions in UCA.ascx.
The code-behind of of these user controls use DTOs and have business logic in them.
The main problem is to resolve the long loading time and delayed operational time (due to postbacks). To resolve this issue, I would need to make sense of the code first.
So, is there guidance on what should be and what should NOT be in the
user-control code-behind codebase?
Is there a tool-driven or easier way to refactor large, unwieldy user controls?
Optimally, there should be no business logic or data access logic in your presentation layer at all. The code in your presentation layer should consist only of code to retrieve business objects and bind them to the appropriate controls on the page.
ReSharper has some built-in refactoring tools where you can extract methods from your codebase, but generally speaking, refactoring like this is delicate and should be approached very carefully, with forethought to how you're approaching the redesign.
As you refactor, try to keep SOLID principles in mind and add unit tests wherever it's feasible.