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
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
Specifically, in this case the Application itself would be the recipient. My thought process is that this would allow for the least possible linkage between Views and View-Models when dealing with the scenario where a new View would be created: They would deal strictly in messages and the App level of the WPF application would handle these messages, creating new views (and implicitly view models through the DataContext of those Views) as appropriate.
This is straightforward enough, as far as I can tell, if I go into the codebehind (app.xaml.cs). However, I would ideally like to handle this message recipient registration in the xaml if at all possible since the behavior is fairly straightforward, all it would really be doing is calling ShowDialog for the appropriate View (I don't think any further handling would be needed, but I may be forgetting something).
For the life of me, I can't think of a way to avoid the codebehind though (I know that MVVM does not really forbid the use of codebehind and I'm making things harder on myself with this, but I think it would make for better code organization if it is possible without violating some other MVVM principle). I thought I had it when I considered the use of System.Windows.Interactivity and tying an EventTrigger to the Startup event of the Application class, but was foiled when I discovered that it needs to extend DependencyObject for that to work.
To summarize, my question is twofold:
A. Is it even possible to handle message recipient registration within the app.xaml for the subset of messages that involve the creation of Views.
B. Is this even an appropriate structure to try and apply or am I way off-base with my thoughts on how to organize responsibility for the handling of messages that relate to other views. If it is not an appropriate approach, is there an easier way or a better way?
The View should contain all view-related code and no programme logic - this is MVVM separation. If your view needs to display a message box, this must then be handled by code in the View. This is the same as animation which must be defined in the View but can be easier in the code behind.
MVVMLight messages allow a simple way for a ViewModel to say "I want to show this" and the View to decide how to show it. The View registers to receive the required type of message and deals with the UI part of showing it - be it a MessageBox or other.
A purely XAML, and probably prettier way would be to build a custom message box.
As for part B: I would receive messages where I wanted to handle them.
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.
I try to avoid code behind in views, within my WPF MVVM project.
However I have some things that are very specific to the view. For example when a control gets focus I want the full text to be highlighted (even if a user clicks into the text box).
Here I have a choice to handle this in the view model (which would then need to know about the view, which I want to avoid).
I also have some other code like that does things to the UI when the user presses up down left or right on the keyboard (and they only make changes to the view, not the model or viewmodel) and again I'm thinking the best place for these is in the code behind of the view.
So I'm asking if the code only affects the view (e.g. things like cursor movement, selecting all text in a text box etc..., and not the model or view model, is it okay to put it in code behind, rather than elsewhere.
Wondering what is best practise here, or if anyone else has a better suggestion where to put this code.
So I'm asking if the code only affects the view (e.g. things like
cursor movement, selecting all text in a text box etc..., and not the
model or view model, is it okay to put it in code behind, rather than
elsewhere.
Not only it is OK, but it is strongly encouraged.
MVVM is not here for you to write thousands of ugly lines of code in ViewModels, it's here to make the code testable and to introduce a separation of concerns.
If it's purely related to the view (your "focus" example is a perfect example), then just write it in the code behind.
If the behavior is UI related only, then you should not put it in the ViewModel. The highlighting example you gave is a good example of such a case. Having said that, I would suggest you avoid repeating your code by (for example) creating a custom control that highlights the text when it has the focus. This way, you can reuse the control in as many views as you can, your views stay free of codebehind, and if you optimize your control, the optimizations happen across the board.
EDIT:
In light of Ravi's answer, Behaviors are also a way to introduce UI related logic while leaving the View free of codebehind. However, if you are finding yourself repeatedly declaring the same controls with the same behaviors, in my opinion it is better to create a control that incorporates the behavior.
That being said, if said UI logic is going to appear only once in one view, you may consider putting it in codebehind. Although it is quite rare to know in advance that you are not going to need that logic elsewhere.
EDIT:
I think #ken2k 's use of strong encouragement refers to not putting it in the ViewModel, which I also advocate. UI logic should be implemented in the View, as he says. Now, there are a few ways of doing that. One of these is coding it directly in your codebehind, which can lead to repetitious code and maintenance issues. Also, if you employ unit testing, it could put you in a difficult spot. The second is coding such logic into behaviors, which is a good way to encapsulate UI code. You can then unit test the behavior to make sure it works OK. However, you can find (as I did, in many projects) that you have started to pepper every TextBox in your XAML's with behavior tags. If that starts to happen, I would (and have) create a 'HighlightedTextBox' control and use that in my XAML. In summary, my suggestion does not contradict ken2k's, but is a pointer in the direction of resolving some issues you may have when placing logic for your View.
Using Custom controls as #Boluc Papuccuoglu suggested, is good option but before using that i want you to take look here Behaviors in WPF introduction
It is strongly recommended to have all your view stuff logic at one place. Instead of polluting ViewModel you should always keep View stuffs in XAML and code behind.
ViewModel responsibility is to contain only data part which can be unit tested. With UI stuff in ViewModel, you will make it hard to be unit tested.
As per link here at MSDN, definition of code behind:
Code-behind is a term used to describe the code that is joined with
markup-defined objects, when a XAML page is markup-compiled.
As you can see, code behind is partial class of your view. One half is declared via x:Class attribute at root element and other half in form of code behind. So, as per me all UI stuff should be at one place and you should not think twice before placing the view stuff in code behind. (that's what it is meant for). MVVM never meant design without any code behind.
Also ViewModel responsibility is to just provide data to your view via data binding. It should never be aware of UI stuff.
Read more about it here - Code behind and XAML in WPF.
How much of your code do you want to unit test? If your view can trigger a command when a control gets focus and your view model can programatically fire an event to highlight the text in that control then you have everything you need to unit test that behaviour with mocked objects. And even if you don't want to unit test (or can't because the bean-counters at your company won't give you the time/budget to do so) then placing that functionality in attached behaviours means they can be used elsewhere. I'm not quite the hard-core MVVM purist as some others on this site but I can honestly say that even in the largest enterprise applications I've worked on I've never once seen a case where WPF code-behind was absolutely required.
I'm using PRISM and MVVM in my modular Silverlight application. I'm still trying to figure out PROPER way to do interactions in MVVM fashion and 2 methods that PRISM and samples offer is not something I like for different reasons.
Method 1(PRISM): To use different region adapter. Basically, it involves attached properties on container and injecting view into region. This works almost 100% but negative of this method is that there is no good way to communicate results back. I can use EventAggregator but something doesn't feel right to raise event with data when interaction completed.
Method 2(PRISM): To use InteractionRequest. That involves trigger action and some big boilerplate XAML that I have to repeat on each view.
I'm thinking on creating something on my own which would require creating my own control which will have to be added to each view but with very little XAML and some kind of IPopupService that I can bind this control to. I can pass all needed data via PopupService but in order to actually make action of POPUP happen - I need to call method on this control and that falls apart in MVVM
I wonder how to call method on control in MVVM where view shouldn't be aware of VM ?
View has no option but be aware of VM, since it binds to it.
You could define some kind of a service indeed with a run-time implementation that would interact with the UI and design/test/debug implementation that does something else. You might also publish some events in your VM layer that the View layer would decide how to interpret.
First off, I don't think MVVM is a good choice if you are developing a UserControl that will be consumed by others. A lookless control is what you really should be developing. Jeremiah Morrill has a blog post about this subject.
With that said, you can set the datacontext with XAML if you have a default public constructor.
Inside ControlView.xaml put:
<UserControl.DataContext>
<local:ControlViewModel />
</UserControl.DataContext>