I'm having trouble deciding what to think about this piece of code:
public SolidColorBrush Brush
{
get { return IsValid ? _validItemBrush : _invalidItemBrush; }
}
It is part of a view model in my current project and as you can imagine, the Brush will be bound to some text elements in the UI, to indicate (in-)validity of other pieces of data, in an otherwise fairly simple and straightforward dialog.
The proponents of this piece of code say that since we're using WPF, we might as well allow for some simple WPF specific constructs in the view model.
The opponents say that this violates Separation of Concerns, as it clearly dictates style which should be taken care of solely by the view.
Please share your arguments, and if you're not happy with the code above, please share your ideas around alternative solutions. (I'm particularly interested in what you have to say about using DataTemplates).
Is it possible that there is one solution that could be considered best practice?
Personally, I would have the two brushes be defined in XAML, and have the controls that use them switch brushes (in xaml) based on the IsValid property. This could be done very easily with DataTriggers, or even a single IValueConverter - the converter could take 2 brushes and a boolean and swap between them fairly easily.
This keeps the business logic presentation-neutral - a "Brush" is very specific to a specific form of presentation, and a pure View choice. Hard-coding this into the ViewModel violates the single responsibility principle as well as is not a clean separation of concerns.
I would very much keep this in the View, and switch based on the IsValid (bound) property that is ViewModel specific.
While there are circumstances where I might use WPF constructs in the view model, this isn't one of them. Here's why:
It's harder to change. If you define brushes as resources and use them in styles, changing your application's color scheme can simply be a matter of loading a different resource dictionary. If you hard-code color values in your view models, you have a lot of different things to change if it turns out your end users need different colors.
It's harder to test. If you want to write a unit test that checks to see if a property is returning the right brush, you have to create a brush in your unit test and compare the values of the two, since it's a reference type.
In many, maybe even most cases, it doesn't make the code simpler or easier to maintain. You're pretty likely to already be using a style (assuming that you are conversant with styles), since they make just about everything in WPF easier. Binding IsValid to brush colors is just a matter of adding a DataTrigger to a style. Which is where anyone maintaining this code would expect to find it.
There are certainly times when I do use WPF constructs in the view model - for instance, long ago stopped wondering if it was problem if a view model exposed a property of type Visibility. Note that none of the above concerns apply to that case.
In cases like yours where it's purely aesthetic I use Triggers or the Visual State Manager to change colors.
Sometimes I do use colors in my ViewModels, but only if its part of my software spec (e.g., the color of the chart displaying a patient's CO2 depends on localization). In that case, I use a Color struct bound property, allowing the View to use the Color for a SolidColorBrush, a GradientStop, or whatever it wants. I initially used a string in #AARRGGBB format to completely remove the WPF dependency but my more seasoned co-workers didn't like that.
Related
I've seen many data binding frameworks, such as WPF, AngularJS(Javascript), JSTL(JSP).
They are trying to separate UI and Data completely.
However, one main problem is that it adds complexity. Sometime, you have to write a lot of extra code (for example to extend a view class) just for one line of UI code.
In modern applications, there are many transition animations when changing one UI element from one state to another state. When use data binding framework, it seems not easy.
Are there any other cons of using a data binding framework?
For example, to set focus on a text input, so complex in AngularJS, See:
How to set focus on input field?
All of the following refers to the WPF.
You have to write a lot of extra code (for example to extend a view class) just for one line of UI code.
With regard to the WPF, this is rare situation, you can give an example?
There are many transition animations when changing one UI element from one state to another state.
In WPF since version .NET 3.5 appeared VisualStateManager:
The VisualStateManager enables you to specify states for a control, the appearance of a control when it is in a certain state, and when a control changes states.
His goal - is to define the application state, and each state to do an action, such as an animation. In this situation Binding is not used as such.
When use data binding framework, it seems not easy.
I do not think it's disadvantage. Data Binding needed as you mentioned: separate UI and Data completely. In fact, the whole MVVM pattern is based on a powerful technology as Data Binding. This feature allows you to create an abstract connection between Model and View via ViewModel. And the key word is Data, everywhere where there is work with the data, it is better to use Data Binding.
Binding allows you to do many interesting things, such as Validation, Converters and much more. It is typically used for Binding properties, and nothing more. To work with the UI using other features like VisualStateManager, Triggers, DataTriggers, etc. and it is not difficult when you use it to its destination, just need to get used to.
The only downside - is that Binding can be used for other purposes, such as use of the Converter when you can not do without it. And yes, at first it may seem unusual, but I do not think that this a drawback, the same can be said about other technologies.
Even as a drawback can be said about the performance. If you assign a value directly or via Binding, assigning a value directly will be faster. But I think that the advantages of Bindings allow not pay much attention to it.
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.
If I had a label on a view that I wanted to have the width equal to the width of two columns in one of my grids on the same view, how would I set up the binding without using a converter? Should I use properties to preform my calculation and store a value? It is my intention that if the view's grid size changes then this label's size will also change to match the new width of the two columns.
And where should I put this logic? I am trying to follow MVVM pattern but I see that a lot of threads about "converters in MVVM" say to put the logic into the viewmodel.
I tried to implement this behavior with dependency properties on my view since my viewmodel technically has no knowledge of my view (so how would my viewmodel know how wide my columns currently are?). This goes against what I have read online though. When implementing this behavior I noticed that I cannot reference my columns by name unless my property is not static, but dependency properties are static so I am not sure how to shuffle my values around without creating yet more properties to hold values.
Can someone provide help here? I feel like i'm overcomplicating this. I just need this label to sit over these two columns however they stretch. It just provides a visual grouping of related fields in the grid. Once I can do this first one, the other two should be equally similar.
My rule of thumb is if it's "View" related then keep it away from the ViewModel. From your description this sounds like it's purely view related, so I would just use logic in either the codebehind or a converter.
Now what I don't understand is why you are reluctant to use Converters. With converters you certainly don't want to store business logic that is going to lead to confusion or pain points for refactoring, but if you have some value that needs to be converted for a specific view operation then Converters are exactly what you should be using.
So my advice is Converters ... if it's View related then feel free to use Converters and Codebehind ... in fact you should use them and not the ViewModel.
Does that help?
I often hear a Model must be wrapped by a ViewModel that the View is not coupled to the Model/not aware of it.
With MVC it is common to bind the View to the Model... nobody complains so what ?
I am frightened of creating all that wrappers and doing nearly only duplicating property stuff.
In some cases you don't need to, just as you don't need properties in many cases but can get away with public fields.
But your model should mirror the domain structure and logic, while a view model mirrors the UI structure and logic. At least, as far as I understood it. Those two are not necessarily the same and each one can change independently from the other.
You should always apply a pattern to your individual problem, and modify it in areas where it does not apply. Just because the pattern implies the usage of a view-model, doesn't mean you necessarily need a view-model in every scenario. In the case that your model exposes all of the needed properties and no further abstraction is needed, maybe a view-model is unnecessary.
However, in many cases the view-model will eventually be of great use and far easier to maintain than adding extra properties to the model. Consider this carefully before binding directly to the model.
The ViewModel is used to only pass the data that you really need to a view.
When you use the model, instead of the viewmodel it is possible that you use data that came directly from the database.
When using the model the wrong way, it is possible to edit data in the database that you don't want to edit.
It is safer to use a ViewModel.
One point which didn't seem to come up (directly) yet is that ViewModel can easily support data that should never even be in the model such as the text typed in the search text box or selected list items in case these values are needed in commands or further data bindings and passing them as parameters every time seems like too much trouble.
But as stated already, if you are confident that all the data you need is already available in the Model, go ahead and do away with the ViewModel.
One common scenario where ViewModels come in very handy is when Enum values should be displayed. In my eyes, a ViewModel is the perfect place to convert Enum values to user-friendly representations. You could even introduce a localization step in your ViewModel.
Furthermore, ViewModels can simplify some other scenarios. However, as you said, they can also duplicate a lot of code. That said, you could create a ViewModel with a Model property which allows to bind directly to the properties of the Model class. Now if you later realize that you need some conversion step, you can still add that property to the ViewModel and bind to that property.
But I think in most cases it makes sense to use a ViewModel from the beginning because it might be hard to introduce it in a later development stage.
There is no problem binding directly to a Model from your View where possible.
What you will find though is very quickly you run into a situation where you need to model things your view needs that aren't in your Model.
Given you never want to corrupt your Model with View concerns, you are left with no choice but to create a ViewModel.
It depends on may indicators: e.g. if your model is provided by EF there's no point in exposing it to your View - why the heck the View would need all model's method/properties and tons of stuff (not mentioning data security) But if your model is really simple and you feel, that you're not going to expand/change it much by and VM, there's nothing on the way to use it just like that :)
You might as well ask, "What's wrong with putting all the functionality of my program into one giant class?" On the one hand, there's nothing wrong; it can be made to work. On the other hand, everything is wrong: if your program is one big ball of wire, you have to straighten all of it out in order to change any of it.
Look at a Windows Forms programmer written by a beginner. You'll find all of the business logic in the buttons' Click event handlers. What's wrong with that? Don't you want that logic to be executed when the user clicks the button?
This is essentially what you're proposing doing within the world of WPF. Will it work? Sure. For trivial projects, it may even work well. You're accumulating technical debt, though, and when the time comes, you'll have to pay it off by refactoring your code into something manageable.
Over at the StackOverflow question How can WPF Converters be used in an MVVM pattern? I've learned that Value Converters should not be used in the MVVM pattern since the functionality of a Value Converter should be handled by the ViewModel itself.
This makes sense.
But I remember reading that you should not expose XAML elements to the View, but instead expose only collections of data which the View then binds and displays using DataTemplates.
However, converters seem quite powerful (e.g. as they are used in the MVVM Template demo, see the "Messenger Sample" after unpacking it) in that they can convert objects to objects, e.g. Message objects to FlowDocument objects, or Customer objects into Visibility objects, or custom Status objects into Images, etc.
So if a ViewModel is going to take on the functionality of a Value Converter, it is going to have to expose XAML elements and properties such as StackPanel, Visibility, Color, FlowDocument, etc., right?
Does anyone see any reason why a ViewModel should not expose these rich XAML objects as Value Converters do?
Because then that limits the ViewModel to be used only with a specific visual representation.
Once you have the ViewModel emitting XAML, it puts design content into a developer's domain.
This means that the designer using Expression Blend cannot edit design assets - and the designer/developer workflow is broken.
Keeping the XAML on the page and using Value converters with data templating keeps the design separated from the code.
When your ViewModel exposes specific XAML it also limits that ViewModel to be used only in that specific instance and makes it less reusable.
Don't forget that you can use DataTemplates too. I can see some sense in keeping ValueConverters out of MVVM, but DataTemplates are all about transforming objects into GUI.
Your ViewModel can expose other objects (e.g. nested ViewModels) to the GUI, and the GUI can use <DataTemplate DataType="{x:Type SubViewModel}">... to map those objects to GUI.
Does anyone see any reason why a ViewModel should not expose these rich XAML objects as Value Converters do?
Absolutely, because it undermines all the goals of MVVM:
You're no longer unit testable, at least not easily.
You no longer have separation between logic (view model) and presentation (view). Thus, designers and developers cannot easily collaborate.
Code maintenance is more difficult because you've mixed the concerns together.
If I saw a view model returning a view, I wouldn't even classify it as MVVM.
I think one idea of mvvm/mvc/mvp etc. is to isolate the GUI code to one file/class.
If you do this can you change to some other UI without rewriting the other objects?
I think if you're passing around WPF specific objects the answer is no.
It's a value judgment you'll have to make for your self.
There is no absolute 100% rule that works for this or many other concepts when you discuss them without the perspective of why the community's mind has shifted as it has in this direction. There is no 'assumed' truth or science in 'conventional wisdom' regardless of how new or compelling it is at the time.
In other words - just do the best with your team as if your good, your already getting pulled down far more in human concerns than anything as real as this.