I have a View base class, derived from UserControl that I use for all views. It allows for later addition of shared functionality to all my views without code duplication. I have now worked up to a level where I have an application whose top level views comprise only a 'NavBarView' and a 'WorkingView'. The latter is empty and merely a host for other child views provided by MEF plugins.
My question is, is it enough to host these two views in the MainWindow 'view' of the application, or should I rather create a ShellView containing them, and have that as simply the only child of MainWindow?
Don't forget, the purpose (of MVVM, MVC, MVP, et al) is to expose testable UI. In my case for an MVP WinForms application I simply have abstracted the implementation of actually showing views (as in, the underlying Forms etc). I would suggest MainWindow will suffice for bootstrapping, but if you intend to put substantial logic in it then go with ShellView in order to later test that logic. To me it sounds as though this is thin and I would personally start with MainWindow to get up and running. You can always refactor later.
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've been dabbling with MVVM. In fact, I've religiously tried to follow it's rules and best practices.
How is program initialization handled properly?
Specifically, I am confused as to why you would call the view (from the App.xaml) first.
My assumptions has been, that a controller still owns the abstraction of the view (ViewModel) and uses it to update the view. (I prefer to separate presentation and processing into different classes, which I guess would make this "MVVMC").
So in my eyes, the view should not be the first thing to be initialized.
This being said, my solution has been to start the controller from the app.xaml code-behind and pass the ViewModel to the controller.
Even though I get a nice information pipline, I have the feeling that this is not the correct way, since I am still using the app.xaml code-behind.
This is what my application looks like:
So, what is the best/most-efficient/most-accepted way to initialize an application?
First of all, MVVM isn't a very strict ruleset and it definitely leaves space for a wide variety of flavors.
Based on whether View or ViewModel is instantiated first, you can differenciate two aproaches:
ViewModel first approach, where instance of ViewModel is created first and then typically based on some convention a View is selected. DataTemplateSelector is a good example.
View first approach, where view is created first (typically a Window or UserControl) and using some convention view is selected. It might be a responsibility of a View to create a ViewModel instance for itself, or it might be delegated to somebody else.
When it comes to initialization, it must always be done in app.xaml resp app.xaml.cs as it is the entry point for your app. You also must realize, the application process is
bound to the Dispatcher loop. When the last Window in your app is closed, dispatcher loops ends and the application process exits. The last window is typically the MainWindow.
Also, take the application startup time into account. You want to display some Window as soon as possible. So if you want to do any logic before the Window is shows, make sure you don't do any I/O, database or API calls, etc.
I typically have Bootstrapper.cs class that I invoke from App.xaml.cs. It's responsibility is to setup IoC and display the UI. It might be a loading window and then MainWindow.
In Bootstrapper.cs you might create instance of MainWindowViewModel first, the create MainWindow and assign the ViewModel to it's DataContext, or you might just create MainWindow and leave the ViewModel creation up to the MainWindow itself. I tend to do the latter.
There is nothing wrong with either of the approaches and neither violates the MVVM principle.
My biggest recommendation to you is - if you can't decide between two or more options, choose the simpler. Or in other words, don't complicate things unless you have very good reason to. KISS
If the code-behind for the View is meant to consist of nothing but the constructor with the InitializeComponent() call, why not just use DataContext="{Binding RelativeSource={RelativeSource Self}}" and use the view itself as a view model?
I get that this technically violates the Single Responsibility Principle, but since the XAML and code-behind are defined independently from each other, it doesn't cause the usual mess. Having separate view models for everything causes more mess to the file structure.
ViewModel describes view state. For testing and reusing purposes it must be UI independent.
Benefits:
You can cover ViewModel by unit tests and you haven't to refer UI
classes in test
You can reuse your ViewModel on other UI targets:
console app, WinForms App, UWP app, Xamarin iOS/Android App, no
display IoT project. You'll need to write only view for new target platform.
Sometimes even in WPF and MVVM you have to write some code behind for View-only purpose because it may be much more simpler, readable and reliable then create some new entity for that. And you'll get mess if you have also ViewModel in code behind.
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.
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.