I'm developing a fairly simple WPF application to display an object hierarchy plus detail of the selected object, with a UserControl wrapping a TreeView in the left pane (the tree control), and another UserControl wrapping a ListView/GridView on the right (the details control).
The tree control uses MVVM following this Josh Smith article reasonably closely, and has a number of ViewModel types all derived from the same base type, TreeViewModel. The main window is set up using a MainWindowViewModel as in this Josh Smith article and exposes the TreeViewModel used to populate the first generation of the tree control.
However, when I want to populate the details pane on the right, I have the problem that the SelectedItem of the tree control is derived from TreeViewModel when I need a completely different type of ViewModel for the details pane which will expand the object into a table of properties/values using reflection.
So, questions:
Is it appropriate for the MainWindowViewModel to expose the TreeViewModel for the tree control? I believe that the answer here is yes, but am open to suggestions to the contrary.
How should the selected item in the tree control be adapted to the right ViewModel type for the details pane? One option seems to be that the MainWindowViewModel tracks the selected item in the tree and does the adaption, exposing it as another property, but I'm not sure if there is a better solution.
I'm new to WPF and the MVVM pattern, so please excuse the fairly basic nature of the question. I've done a fair bit of reading around the background of the pattern, looked at some sample apps etc. but I can't quite find anything specific enough to make me confident of the answer. I also realise that MVVM may be overkill for an app this simple, but I'm using it partly as a learning exercise.
1.Is it appropriate for the MainWindowViewModel to expose the
TreeViewModel for the tree control?
I belive yes. The model should hide the look from teh logic FOR THE LOOK, but it can not hide thigns like logical structure.
2.How should the selected item in the tree control be adapted to the right
ViewModel type for the details pane?
One option seems to be that the
MainWindowViewModel tracks the
selected item in the tree and does the
adaption, exposing it as another
property, but I'm not sure if there is
a better solution.
IMHO not.
Working on the similar problem I came to the conclusion that
object Tag { get; set; }
property is inevitable :( except maybe for some rare situations (only 1 type of objects in the entire treeview).
However, when I want to populate the details pane on the right, I have the problem that the SelectedItem of the tree control is derived from TreeViewModel when I need a completely different type of ViewModel for the details pane which will expand the object into a table of properties/values using reflection.
If you're really, really concerned about this, you can build a higher-order view model class that exposes two different properties - one of type TreeViewModel and one of type DetailsViewModel. Then the main window's view model will expose the same object to both the tree control and the details control, but the logical structure of the two view types will be decoupled from one another.
Logically, the selected item in the tree control and the item that's appearing in the details control are the same thing. While the details control doesn't present information about the thing's parent/child relationships, and the tree control doesn't present information about the thing's name/value pairs, it's still the same thing. There's probably not really any need to be too concerned over the fact that a single object representing a thing exposes a property that only one view of that thing uses.
Related
I'm kind of a beginner with the WPF platform. I've done a few Windows Forms apps that were very basic and now I'm working on a much more complex app for my current work.
I'd like to implement an MVVM model, but I'm getting lost in the different articles on how to do so.
Here's a screenshot of the app interface:
The section on the left is a ListView containing 6 sections that correspond to different UserControl. I would like the section on the right to display the UserControl that corresponds to the selected Item.
Each UserControl is stored in a separate XAML file.
By looking online, I found that I should use a ContentControl in my MainWindow, but every attempt I've made has been unfruitful. I know there's more than one way to skin a cat.
Which method would you use? Do you have any concrete examples or sources where I can find how to make it work?
The only difference between UserControl and ContentControl is the OnCreateAutomationPeer method. This method is responsible for UI automation.
Although this method is rarely used in practice, it is customary to use UserControl to represent some complex data types.
A typical use for a UserControl is to retrieve data (in normal CLR types) through the data context.
And the Content property specifies (using XAML) a visual tree to represent that context.
And each such UserControl is declared as a derived type (just like a Window).
If necessary, additional properties (CLR and DP) and other members (event handler methods, for example) are added to such a UserControl.
The base class ContentControl itself and others of its successor are used somewhat differently.
The data in them goes directly to the Content property.
And their visualization is set by the data template in the ContentTemplate property.
While DataTemplate's can be quite complex, they are usually much simpler than the XAML markup of the UserControl.
And, besides the task of visualization, you cannot add additional logic (properties, fields, methods).
Here's a photo of the app interface: ...
In this UI, I don't see where the ContentControl can be applied.
On the left is a navigation bar consisting of buttons.
It is usually implemented directly in the Window from an ItemsControl or ListBox.
On the right (while an empty area) is the region for the page content.
Usually, when you click on a button in the navigation bar, the corresponding UserControl is set to this region.
At a lower level, deeper in the visual tree, for smaller elements, it is quite possible that a ContentControl is needed.
P.S. Just in case, I will clarify, in view of the comment below.
By area for pages, I do not in any way mean the use of Frame + Page.
This is a very specific pair and it is extremely rarely justified to use it.
In combination with MVVM, its use is even more difficult, since this pair does not support DataContext inheritance.
And this is the main way for the View to interact with the ViewModel.
I am new to MVVM and I've decided to move on and start adopting it in my upcoming projects.
I have read this related question and answer, but I don't know how this would be implemented with MVVM.
I want all the views in my project to have 2 modes, Edit Mode and View Mode.
I don't want the user by default to see TextBoxes for all the fields, I rather want them to see TextBlocks (or set all the TextBoxes' as IsReadOnly property to true (via style etc. you tell me..).
When the user opens up the entity it should usually be TextBlocks, Labels (or readonly TextBoxes) etc., and if he clicks "Edit" (if he has permission to), it should go Edit Mode, and all the fields' labels should be inverted to TextBoxes (RichTextBoxes etc., ComboBoxes or any other editable fields that are not just labels).
I am pretty sure I am not the only one having this issue, I would like to hear from the experts what is the most efficient way to switch between these modes in pure MVVM, and whether it's is common to declare two separate views for it.
Please refer me to a good article that explains how to do it (maybe it is done by Visual State?? IDK).
UPDATE
I want to know WHAT rather than HOW, my question is about the pattern, and is should I separate Edit Mode
from View Mode at either the V or the VM?
So please emphasize this detail in your answer.
Thanks in advance.
Use the IsReadOnly property for your text boxes and bind that to the "edit mode" property:
<TextBox .... IsReadOnly={Binding IsViewMode} ... />
Then in your view model:
public bool IsViewMode
{
get { return _IsViewMode; }
set
{
_IsViewMode= value;
// Call NotifyPropertyChanged when the source property is updated.
NotifyPropertyChanged("IsViewMode");
}
}
IsViewMode defaults to true and is switched to false when the user clicks "edit". The binding will instantly make all the text boxes editable.
You could do the same for the other controls - though it will be the IsEnabled property you need to bind to in these cases - though you'd have greyed out controls.
To swap out text blocks and your controls you'll need to have both controls sharing the same location in a grid and their visibility controlled by the IsViewMode property via a pair of converters:
<TextBlock Grid.Row="1" Grid.Column="2" ...
Visiblity={Binding IsViewMode, Converter=DirectConverter} ... />
<ComboBox Grid.Row="1" Grid.Column="2" ...
Visiblity={Binding IsViewMode, Converter=InvertedConverter} ... />
The direct converter is:
return IsViewMode ? Visibility.Visible : Visibility.Collapsed;
The inverted converter is:
return IsViewMode ? Visibility.Collapsed : Visibility.Visible;
I think about it this way: the View is what it looks like, and the ViewModel is how it interacts with the user. Since a readonly interface has substantially different behavior than a read/write interface, then there should be two different ViewModels.
Now I did created an edit ViewModel that inherited from a display ViewModel because I considered the editing functionality to be an extension of the display functionality. This works for simple CRUD type applications where the user is directly editing fields without a lot of business logic.
On the other hand, if you have a more complicated business process (or workflow) that you're modelling, then typically the way you manipulate information is very different from the way you want to view it. Therefore, I would generally separate the two ViewModels unless it was just CRUD.
ChrisF's answer is fine if you want to go the IsReadOnly route. If you want to go the TextBlock-to-TextBox route, though, the most efficient way is have a Control which switches its Template, via triggers, based on the value of an IsInEditMode or IsInViewModel property.
Viewmodel: I would definitely keep just one viewmodel with a ViewMode property much as described in ChrisF's answer. Separate ViewModels would just be inelegant.
View: As I see it, you have at least three options, with various pros and cons.
Just readonly-ing all the controls, as suggested in the ChrisF's answer. Pros: Simplest thing to do. Cons: That is an ugly UI in my humble opinion.
Create seaparate display and edit controls in separate containers. Bind visibility of the containers to ViewMode. Pros: A more pleasing ui experience can be afforded here. You can even animate the transitions from one to the other. Cons: Doubles the number of controls (could hurt performance for very large windows). Positioning the controls inside the two containers at exactly the same pixel positions can become a bit non-trivial in a fluid ui.
For every edit control in the xaml, position a display control right on top of it. Bind visibility to the ViewMode property. Pros: No duplication of label controls at least, so slightly faster. Cons: Harder to get animation stuff and other view tweaks right.
Edit: In view of the clarification provided, I chose to replace the previous answer as it pretty much largely dealt with the how and not the what.
First, I'd implement an abstract base class for my view models that implemented IEditableObject and exposed appropriate commands for BeginEdit, EndEdit, and CancelEdit. It might be that the actual implementations for those three methods would have to be up to the derived classes, but the commands could live in the base class.
In this approach, EndEdit updates the model with the current values of properties in the view model.
I'd also implement a boolean IsEditing property in the base class, for use in data triggers, so that if I want to switch between modes without (say) opening a modal dialog, I can just do it in a style.
As far as the visual design of the front-end goes, I find the idea that a read-only view is just an edit view with read-only controls is one that appeals primarily to programmers. Generally speaking, if you're simply presenting an object to a user, the goal of that presentation is to provide the user with an informative, clear, and intuitive representation of the information in that object. If you're letting the user edit an object, the goal of that presentation is to make the task of modifying all of the editable properties of the object as easy and clear as possible.
Those are two very different sets of goals. For instance, while a person's sex, height, and weight might be important pieces of information for an application to collect, it's probably not all that important for the system to present that information to the user in most contexts. It seems like a very natural thing to do if what you have in your head is that edit mode is just like display mode. But if you're placing the needs of the user, and not the programmer, front and center, it may not be the right thing to do at all.
Long title, hope it makes sense. Can't seem to figure out how I would implement this. Or if my approach is even somewhat on track with best practices for this kinda stuff b/c i'm still working on mvvm and probably not using it correctly yet.
I have a simple viewmodel in an application i'm working on and it contains two properties which point to datamodel collections.
public ChuteGroupsModel Groups { get; set; }
public WaveStatusModel Waves { get; set; }
Each one of these datamodels contains all the data I need for a tabpage in my tabcontrol of my MainWindow. One tabpage is a grid of statistic data and the other page is a custom user control that visualizes a physical "working" area.
I decided today that I would like to display some of the statistic values from the grid (# of items, # remaining, etc) inside of the tooltips of my custom user controls. My two collections are only connected by an ID# field.
So, basically I need to figure out a way to filter/bind to my "Waves" collection according to the ID# property of the current element that is bound to "Groups".
The obvious easy answer here is to modify my sql view to include the additional fields which would make them immediately available for me to bind to in my application.
Since all of the data I wish to visualize already exists, I can't help but feel that changes to sql are a bit unnecessary and that some easy solution exists to help me gather these values out of my other collection.
Can anyone provide any suggestions of what I could attempt to do? If my question does not make sense I can try to re-state it with more code snippets and hopefully that will help.
Perhaps some more information about your ViewModel / View binding would be helpful. As given, if your ViewModel exposes properties of both Groups and Waves to your View, and the View containing the TabControl is bound to your ViewModel, I see no reason why controls on either TabPage couldn't be bound to properties sourced from either data model.
To put it another way, the ViewModel can abstract away the separate data-model collections from the View, building, for example, its own collection of objects which expose the properties of both a ChuteGroup and its associated WaveStatus. The View can then be bound to that collection, and access the properties of both objects.
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.
In my WPF MVVM application my model is a complex tree of Model objects wich constantly changes at runtime. Model instances come and go at runtime, change their position within the tree and of course change their many properties. My View is almost a one-to-one visual representation of that tree. Every Model instance is in 80% of the cases also a node in the tree.
My question is now how I would design the ViewModel around this? My problem is that there are quite a lot of different Model types with each quite a lot of properties. If I understood MVVM corretcly the view should not communicate with the Model directly so this would mean that I would have to create a ViewModel type for each Model type and have to rewrap each property of the Model type in the ViewModel.
Also the ViewModel would need to "bind" to the propertychanges of the Model to pass it along to the view (using wpf datatbinding). I would need some factory that creates and introduces a ViewModel instance for each Model that appears anew and I would habe to dispose each ViewModel instance when the corresponding Model disappears. I end up keeping track of all instances I created. It is unbelievable how much bloat code is generated dues to this double wrapping.
Is this really a good approach? Each entity and each property more ore less exists twice and I have a lot of extra code keeping Model and View in sync. How do you handle this? Is there a more clever way to solve this?
Does anyone have a reference/sample implementation for this that does it better than I do?
I think you may run into trap of paradigm if you follow this path. MVVM is nothing more than a pattern, which simplifies development in WPF world. If it doesn't - don't use it or revise your approach. I wouldn't spend 80% of my time just to check the "Using MVVM" field.
Now back to your question. Correct me if I'm wrong, but it sounds like you are looking at MVVM from opposite direction: you don't need Model to ViewModel one-to-one correspondence. Usually you create ViewModels based on your View first, and only then on a Model.
Generally you look on a screen mockup from graphic designers, and create corresponding ViewModel, which takes all necessary fields from the Model, wraps/modify/format/combine them to make View development as easy as possible.
You said that your View is almost one-to-one visual representation of the Model. In this case it may have sense to create a very simple ViewModel which exposes root object of your model-tree, and let View consume model directly via that property. Then if you need some View customizations or commands processing you can delegate that to ViewModel.
Sorry for very vague answer. Maybe if you ask more specific question we could dispel the confusion :)...