I'm building a WPF application which very simplified looks something like this:
I have an ApplicationView which holds the menu and a ContentControl.
The ContentControl binds to the property CurrentViewModel which is set by the menu and rendered by its related View (Views and ViewModels are coupled by DataTemplates defined in the App.xaml).
I found this approach on Rachel Lim's blog
So in this example my View contains a list of duties as well as a "Details" window of the currently selected duty.
This setup works fine, but I think my ViewModels are getting too fat!
The non-simplified version of this ViewModel is up at around 500 lines of code, for handling:
Initializing filters
Logic for filtering list
Displaying duty details
Add/Update/Cancel/Delete logic
Now I'm very new to WPF but that seems like too much code, yea?
And it will be even bigger before I'm finished with it.
Anyways, I was thinking that I could split the ViewModel into two separate ViewModels; one for holding list and filters and one for showing the details. But how is this best accomplished?
I have thought of two approaches, but don't know which is preferable:
Create a DutyMasterView whose sole purpose is to hold two ContentControls for the actual Views (ie DutyListView and DutyDetailView each with their own ViewModel)?
I'm using MVVM Light as my framework so I suppose I could use the messaging service to tell the DutyDetailViewModel which Duty to display, right?
Alternately create a DutyMasterViewModel which exposes the selected duty.
Ditch the DutyMasterView and nest the DutyDetailView in the DutyListView.
Does it make sense to split my ViewModel into two or should I just stick with my fat ViewModel?
If splitting the ViewModel is recommended which of my suggestions makes most sense?
Are there other approaches that I should consider?
If you're still looking for opinion, I'd do it almost like you mentioned in point 1 but you don't need any messaging.
You create two VMs. Let's say DutiesVM and DutyDetailVM. DutyDetailsVM contains just some string properties for ID and Name.
In DutiesVM you create two properties:
ObservableCollection<DutyDetailVM> DutiesList
DutyDetailVM SelectedDuty
Your DutiesView can look like this:
<DockPanel>
<v:DutyDetailV DockPanel.Dock="Right" DataContext="{Binding SelectedDuty}">
<ListBox ItemsSource="{Binding DutiesList}" SelectedItem="{Binding SelectedDuty}"/>
</DockPanel>
Now you can create ListView ItemTemplate that binds to DutyDetailVM Properties.
is usercontrol that defines the DutyDetail view. Selecting the item in the list updates the details control automatically.
That's just the sketch but I think you can get the point from it.
Related
My Main Window is a relatively simple DockPanel:
<DockPanel>
<!--Bottom row-->
<Border DockPanel.Dock="Bottom">
<DockPanel DockPanel.Dock="Bottom">
<!--Detector Indicator-->
<views:DetectorIndicatorView DataContext="{Binding DetectorViewModel}" DockPanel.Dock="Left"/>
<!--Logo-->
<Image DockPanel.Dock="Right" HorizontalAlignment="Right" Source="/Resources/Images/Logo.png"/>
</DockPanel>
</Border>
<!--Main display-->
<views:TabControlView DataContext="{Binding TabsViewModel}"/>
</DockPanel>
Inside the TabControl's SelectedContent there's a viewmodel for each tab, and each one of those can host a variety of viewmodels.
At one point, the tree basically looks like:
<MainWindow>
<TabControl>
<ExamTab>
<EditExam/>
</ExamTab>
</TabControl>
</MainWindow>
And on the EditExam page, I want a toolbar to appear in the Bottom row of the MainWindow. The toolbar buttons will be bound to commands ont he EditExamViewModel.
Is there a way I can "inject" an inner control like this into the "outer template" (i.e., the main window)?
The only way I can think of is to take the bottom row out of the MainWindow and paste it into each individual view, identical except for the one instance in EditExamView. Is that the only way?
Is there a way I can "inject" an inner control like this into the "outer template" (i.e., the main window)?
No, there is not, at least not in XAML.
You could it programmatically by for example getting a reference to the parent window in the view using the Window.GetWindow method, or by raising an event or send a message from the "tab" view model to the window view model or window using an event aggregator or a messenger.
What you describe is common in modern applications. Even menus are often swapped depending on the active view. However, there is no built-in way of doing this in XAML or WPF. The easiest way to solve this is
[...] to take the bottom row out of the MainWindow and paste it into each individual view, identical except for the one instance in EditExamView. [...]
The hardest way is to develop all that is needed for this scenario yourself including
Creating views and view models as data context dynamically
A concept to define areas where your views should be injected
Swapping in and out dependent views including their view models
Communication between views for synchronization or updating
Managing activation and deactivation of your exam tabs
Custom commands that you can wire accross views to your tab view
...
This is a lot of code that you might not be able to write on your own. But you are not alone, because there are application frameworks intended to bridge the gap between UI frameworks and your code like Caliburn Micro or Prism. These frameworks enable you to skip a lot of boilerplate code and provide services and mechanisms for various issues, but at the cost of learning them and some customization to fit your needs.
Prism as an example provides the following solutions to the issues above
A dependency injection container
Regions that define areas within your application
A rich region navigation service
An event aggregator for communication
Region adapters with active awareness
Composite Commands that can be used across views
...
This looks overwhelming at first, but the more you become familiar with a framework of your choice, the easier application development gets, as you will reuse concepts and components. At this point I recommend you not to re-invent the wheel. At first, you could use the easy solution and start getting familiar with any framework and gradually migrate your application.
So actually I’ve come up with a pretty good and simple solution, which is simply:
<ContentControl Content=“{Binding TabControlViewModel.Tabs[SelectedIndex].CurrentViewModel.ToolbarViewModel}”/>
If the current view model doesn’t have a toolbar view model then it’ll just evaluate to null and show nothing. Then I can define a data template for ToolbarViewModel and we’re all set.
If I wanted to enable various pages to have different things in the bottom bar, I could have ToolbarViewModel be some more general type (and probably a different name), possibly whatever my view model base is, and then any page’s VM could be any type of view model I want, and I could set the DataTemplate. The only caveat would be I don’t think I could have more than one template for any given VM, but I could get around that by creating simple subclasses for each way I’d want it to render so I could have different templates.
I have made a root AppView, a root AppViewModel for my application as a container for all the things. Within the application view, I have a TabControl that each tab has its own task to do. One tab for imoprting data, one tab for issuing, one tab for management and etc:
App_View[Model] // root
{
TabTask1_View[Model], TabTask2_View[Model], TabTask3_View[Model] // tab items
}
1) In MVVM, Is it standard that I have grouped my whole views and view-models into the main application-view and application-model-view ?
2) In MVVM, The model should be implemented for every view & vm ? Or is it standard if I implement the whole models into one or two class files and share the model between them? I personally think that model part is not specific to a certain view, like the class 'student' that can be used anywhere in the code and is not restricted to a certain view. Based on this, if the models are general and shared, yet, is it good to follow the naming convention Class + 'Model' for it? like StudentModel? Is it helpful/necessary to add 'Model' after the general or shared class name like the thing I said?
3) In WPF, What is the best way to implement the Views? I want to edit and design very easily and without any restriction, and it should be standard enough to cover future needs. There are 4 things to use: Window, Page, UserControl and DataTemplate. Which one is the best option that you go for? UserControl or Page?
4) In WPF, How can I load the UserControl/Page(View) inside a tabItem dynamically at run-time based on the MVVM approach?
You're cheating. That's 4 questions!
1)
In terms of how you group your Views and Viewmodels I've seen people put views and viewmodels in the same namespace/folder and others separate them out into different folders based on functionality. The best option for you is what suits you/your team. There is no "right" way.
2)
Keep it DRY - so don't repeat yourself. It is perfectly sensible to reuse code. If you have common classes keep them common. As for naming, the name of the class should be helpful in explaining what it does: I'm sure you'd be able to figure out what the classes NavigationService, NavigationMenuItem and NavigationMenuView did and probably could put together a good mental model of how they relate. So - if naming a class BlahViewModel or BlahModel is useful to you, do it.
3) Implementing views:
A Window is always shown independently. Pages are intended for use in Navigation applications (usually with Back and Forward buttons, e.g. Internet Explorer). Pages must be hosted in a NavigationWindow or a Frame. If you're looking at dynamically adding/removing content, adding content to ItemsControls (TabControl, etc) then you'll want to be creating user controls. You can put user controls in Page and Window object, into other controls, etc, and are really the workhorse for WPF developers.
4)
You have a number of options here:
1)The quick and dirty way is to create DataTemplate which, on being given a ViewModel of type X, load up and apply the ViewModel to their data context. This will allow you to inject a ViewModel directly into a control and have the correct View render.
An example:
View.xaml
<ContentControl Content="{Binding Error, Mode=OneWay}" />
ViewModel:
private void ReceiveError(ErrorViewModel errorModel)
{
//if (errorModel.AcceptCommand==null || errorModel.AcceptCommand is NoOpCommand)
errorModel.AcceptCommand = new DelegateCommand(ClearError);
Error = errorModel;
}
public ErrorViewModel Error
{
get { return _error; }
set
{
_error = value;
_propertyChangedHelper.NotifyPropertyChanged(this, () => Error);
}
}
Styles.Xaml (ResourceDictionary)
<DataTemplate DataType="{x:Type vm:ErrorViewModel}">
<DataTemplate.Resources>
<conv:CustomisableBooleanToVisibilityConverter x:Key="VisibilityConverter" TrueValue="Visible" FalseValue="Collapsed" />
</DataTemplate.Resources>
<Popup AllowsTransparency="True" PopupAnimation="Fade" Placement="Center" StaysOpen="True"
PlacementTarget="{Binding Mode=OneWay, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type v:ModuleView}}}"
IsOpen="True" Width="400" SnapsToDevicePixels="True"/>
So you can see I'm injecting my viewmodel directly into the content control and it's using the data template that is bound to the viewmodel's type to find a View for it.
2)
A better bet is to use a DataTemplateSelector. This basically allows you to specify which templates are available for a control and then uses logic you code to determine which datatemplate to use. You can find an example of this here.
3)
Use a framework that abstracts the UI controls away. Microsoft has a framework (free) that does this called Prism. Basically, instead of adding your usercontrols directly to a TabControl,ItemsControl, etc you add your control to a named "Region". This region is mapped to an underlying control and an adaptor is put in place to manage how that UserContorl is added/removed when you ask it to be. You can find an in-depth discussion of this here. Beware, though, Prism is an application framework so implementing this isn't 3 hours work.
Here is not an answer, it's my experience that i'll explain to you and how I handle with MVVM. I started with WPF 3 month ago and I handle with it.
For each new theme/menue/option I create a new project file wich contains the ViewModels and the Views. All Business classes are collected in one Project file because I may have to use it in more than one ViewModel.
Yes, it was helpful for me as beginner to name the the classes ...ViewModel and ..View. It maked it easy for me to separate the diffrences and also it was/is easier to explain other people your classes ( for example if u have a problem with your coding )
I am using UserControls for our different views and I load them into ContentControls and TabControls without any problems.
Have a look at Prism for MVVM-pattern.
Point 1:
It depends. There are two widely used approaches AFAIK. First is as you've said group all VM's that constitute the same Window with direct dependencies to form a class structure that shows your actual program structure. Second is where you use an EventAggregator(Prism) / Messenger(MVVM Light) to loosely link the VM's instead of direct dependency.
Now both approaches have their benefit's
With the first one It's pretty easy to identify your program structure cos your VM dependencies show it clearly, which is not so clearly visible from the second approach.
Second approach helps you a lot when unit testing VM's cos you are not forced to either mock / work-around all the dependent VM's, It also helps code re-factoring a bit when changing project structure(think of "Plug in" classes)
oh and these ^^ are by no means exclusive. You can mix these together well and fine.
Point 2:
Models do not have any recommended 1 <-> 1 relation with a View / VM like what Views have with VM. Models just hold your Business Logic. I've had apps that sometimes do not hold a Model at all. Something there is just 1 Model used by the entire Application(when the back-end is say a c++ library and you just interface with it with a C++/CLI Module). yes maintain the naming convention to append Model class names with "Model"
Point 3
How about all of them? use them where applicable. Do not take a partial preference to any. When a View composes multiple other sections that are by themselves a View with VM I'd have a DataTemplate with the Data a UserControl. Your app almost always uses a Window and Page is useful for navigation based apps I think. Think Page's are what I've used least tbh.
Point 4
This is a question of tutorial's. Take a bunch of examples, see how it's implemented, reason it and pick your approach. If your using VS2010 get MVVM In the box (It's great. no 2 ways about that. Really hope this could get to be updated for VS2012 if it's not already). For VS2012 check out Two Views MVVM CodeProject which shows the concept, you can then apply it to any ItemsControl of your choosing.
Finally atleast when you're starting up, PLEASE start off with using a MVVM helper library. I prefer MVVM Light <- that link has a couple videos by the author of the library showing some usages and you can find extensive help here on SO about it. If you want to do things yourself, learn the basics from it and then implement it yourself. if you take the high road from day-one it's just a much longer learning curve(Just my opinion)
I need to create an application that will take an .ini file which will contain
min
max
default
values for the elements, allows user to edit these values and save a new .ini file. Since .ini files can not contain different elements in the specified groups the GUI needs to be generated dynamically.
From what I have read about WPF it largely stands on data-binding and Notifying Property changes.
Since my view model needs to accommodate different numbers of variables I am not going to have the ability to bind to properties, i was planning to attach one event handler to all text boxes which will pick the corresponding validation rule when the TextBox loses focus or Enter is pressed. After that, it should update the model accordingly if it passes validation and update the View using the model for the corresponding value.
I was wondering whether this sounded like a valid idea, whether there is similar design pattern I should read about or should I just steer away from WPF altogether?
You can still use bindings - since WPF supports item templating, and since you are using an MVVM pattern you can just create a VM for each sub-item in the list (you don't even need to do this you can bind directly in the template of each list item to a DTO or business object)
I'm currently doing a similar thing now - I have a list of material tests for a client, they want to have a variable number and type of tests for each material, but also be able to tweak and change those tests per order for their customer
They actually have two test types, but to describe the simpler of the two cases (which doesn't require child VMs as such) I just created an ItemsControl that has an item template:
<ItemsControl ItemsSource="{SomeBinding}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{PropertyDescription}" />
<TextBox Text="{PropertyValue}" />
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
In this case the model just contains a list of property names/values and displays them in a stackpanel (you may need to set the ItemPanel using an ItemsPanelTemplate. Obviously you could have an extended ItemsControl that allows a DataTemplateSelector to display a different data template per type (in fact WPF already support per-type data templates).
I'm currently using Caliburn.Micro which actually does a lot of setting up child-templates for you - so if you create the bound items as a VM you can do something as simple as this:
<ItemsControl x:Name="SomeBinding" />
And CM takes care of the rest as long as the child items in the SomeBinding property are VMs themselves (though that's another story :P)
Wrap this library with a class that implements INotifyPropertyChanged so WPF can update itself once properties change. That way you can effectively databind to an INI file.
I have a C# project in WPF. I've worked with MVC before and I am now trying to get around with MVVM in combination with XAML.
I have multiple models, I have one GUI Window with Tabitems, and I have multiple ViewModels.
Each tab item is related to each model, therefore I have a ViewModel for each model.
Now I want to use binding (why else use WPF/XAML). How do I bind a button to a command in ViewModel X?
E.g.:
Two Models: house and person
View: Two TabItems in the GUI, one TabItem about all interaction with houses, and one TabItem for persons.
Two ViewModels, correlating with each TabItem.
I have a command to put a house for sale.
I see alot of code that just binding to the name of the command, but since I have multiple views, and not just 1, how do I do it? Should I create 1 ViewModel that will handle all other ViewModels?
I see alot of code that just binding to the name of the command, but since I have multiple views, and not just 1, how do I do it?
Make sure you understand how the binding system works. You're binding to a DataContext. So, if each individual tab has a separate DataContext value set, then you can bind using the name of the command.
Knowing this, you can proceed using the pattern you've established. In my humble opinion, I think it will get much too complicated. Majority of MVVM developers are applying a one-to-one relationship with the View to ViewModel (things get tricky when talking about UserControl objects though). Nothing is set in stone though, so ultimately it's up to you on how you want to proceed.
I guess you have limited number of viewmodels. So you have 2 choises: first, is to use DataTemplateSelector, and the second is to define in xaml each TabItem view and Bind each Content to necessary VM.
I've got what I think is a fairly simple problem in Silverlight, and I'd like to solve it using MVVM principles, largely as a way of enhancing my own understanding.
Let's say I have a simple LOB app that's designed to let me load up and edit a single Employee (just an example, for the sake of explanation). In my example, Employee is made up of a number of complex objects - an Employee has a ContactInfo, a Skillset, an EmploymentHistory, an AwardsEarned, etc. The idea is that I can have this app load up a single employee and get access to a number of different editor screens. Each component of an Employee has its own editor screen.
Visually, the app just ha a left-hand nav bar and a main view on the right side. The nav bar just lets me type in an employee number and load it into memory as the "active" employee. It has a simple list of links - clicking a link should load the appropriate editor screen on the right side.
There are a couple concepts that I don't think I understand well enough, and I'm having trouble proceeding. I know there's always more than one way to skin a cat, especially when it comes to WPF/Silverlight/XAML/MVVM, but I'm having trouble thinking through all the different concepts and their repurcussions.
View-First or ViewModel First
After much thinking about MVVM, what seems most natural to me is the concept of viewmodel composition that Josh Smith seems to promote in his often-quoted article. It seems like the idea here is that you literally model your UI by composing viewmodels together, and then you let the viewmodels render themselves via typed DataTemplates. This feels like a very good separation of concerns to me, and it also makes viewmodel communication very direct and easy to understand.
Of course, Silverlight doesn't have the DataType property on DataTemplates, to many complaints: one, two. Regardless, what I see promoted much more often than viewmodel composition is a more view-first design, where the viewmodel for the view is typically instantiated in the view's XAML or via a DI container, meaning that you can't hand it any parameters. I'm having a really hard time understanding this: how is a ViewModel supposed to serve a Model to a View if I never get to tell it what data is in the model? Reaching through a view to get to its viewmodel doesn't seem to make sense either. I'm very hazy in this area but it seems the accepted answer "use a mediator/lightweight messaging framework." I'm just going through some tutorials now on the messaging system in MVVMLight and I'll be looking at similar stuff, if for nothing else than simply to understand the concepts, but if anyone can shed some light on this I'd very much appreciate it. Anything involving Unity/Prism or MEF is valid, but I haven't gotten that far in my quest for knowledge yet :-)
Instantiating Views and Selecting Them
Theoretically (I say that because SL doesn't support DataTemplate DataType), the viewmodel composition approach could make this very simple. I could have the right side of the screen be a content control whose Content property is bound to a property called ActiveEditor. A parameterized command for the hyperlinks would set ActiveEditor to a given viewmodel.
With a more view-first approach, how would I proceed with this? The first thing that comes to mind is instantiating all of the controls in the XAML of the main view.
Is manipulating the Content property of a ContentControl a good way to go for this kind of situation, or am I better off doing something like setting visibility on each individual control?
The ViewModel (VM) is written so that it is 'wired up' to the Model but has no knowledge at all of the View - in fact, this is what makes it very good to unit test (see NUnit) as it has no idea, and less does it care, whether it is being used by a UI or a Test Framework.
The VM exposes public CLR properties which implement the ICommand interface, the View, having instantiated a VM using (generally speaking anyway) its default constructor, then binds its Buttons/Hyperlinks etc to these Command properties like. So, for example, you may have a VM that exposes a CloseCommand to exit the app, the View may contain a MenuItem that binds to that command, such as:
<MenuItem Header="E_xit" Command="{Binding Path=CloseCommand}" />
Now, the VM would also expose a public ObservableCollection of objects that you want to display in your UI. Whether you populate this ObservableCollection as part of the VM constructor, or whether you do it via a UI interaction (say another Command assigned to a Button click) is up to you but the end result is that you bind a View control to this exposed ObservableCollection in XAML like:
<y:DataGrid ItemsSource="{Binding Breakdown}"/>
or equivelant for whatever control you are using to display the data (not sure off the top of my head what elements a DataGrid has in Silverlight as opposed to WPF).
Meanwhile...: The Mediator pattern is used for VM's to interact with each other, not for the View to interact with the VM. For example, you might have a custom TreeView that has its own VM on the same View as the main chart screen. In this case you could use a Mediator for the TreeView's VM to communicate with the Charts VM.
As for the last bit of your question, I think set up a basic framework using Josh Smith way in the article you mentioned and use that method to add additional ViewModels to the right hand side of your silverlight app.
Hope that helps a bit at least.