If I wanted to hide(or change visibility, color, etc) of an element in WPF is it better to use DataTrigger or a binding with a converter?
Sounds like two ways to achieve the same goal. When is it better to user one over another?
I can tell you about my experience.
I use databinding with converters for the following cases:
For the Visibility property (there is the built-in converter in WPF).
In Silverlight applications (although there are silverlight-compatible data triggers in the Microsoft.Expression.Interactions library, they are not as convenient as WPF triggers).
If the source object contains many possible values. Enum to image converter, for example, it is easier to write 5 if-else clauses than 5 datatriggers.
Datatriggers:
If I want to change several different properties at once (background, visibility, thickness).
For brushes (It isn't easy to create brush in C# code by using the hex-number of the color).
If I want to apply static resources.
They can be used for displaying animation and running storyboards.
Sometimes I prefer the MVVM approach: I create additional properties of the necessary type in the viewmodel so that they can be bound directly without converting.
The short answer is it depends.
Data Triggers only offer equality operations against a single data source.
If you need to have parameters or multi-value binding you would need to use a converter.
Related
I have built a User Control composed, as usual, of a XAML part and a code-behind part. Now, I need to create another User Control which shares some of the functionalities of the former, but which has different looks and might also have additional features in the code-behind.
My first idea was to create an interface to gather the common functionalities of the two types of controls. Is this the right way to go? And how would I manage the different XAML parts I should have? Any advice is welcome.
I would like to add another contribution which I think might be useful to others encountering my same situation.
One other possible solution, which in my opinion is suitable if the controls you are going to create are not particularly complex, is to create a base User Control containing the common features that you want to share: such control will be written entirely in C#.
This, in fact, allows inheritance in User Controls composed of both XAML and code behind. In the XAML of the inherited control, rather than having
<UserControl> ... </UserControl>
You will have
<MyProject: MyBaseControl x:Class="MyProject.MyExtendedControl"> ... </MyProject: MyBaseControl>
and then in the code behind you will also need to specify the following:
class MyExtendedControl : MyBaseControl
Hope this helps.
User controls don't lend themselves well to inheritance in WPF, you can do some hacks to make it work, but overall you'll probably be better off using a Custom Control instead. It's easier to specify different XAML for inherited controls using this technique. The easiest way to get started with a custom control is to add a new item to your project of type "Custom Control (WPF)" and it will add the control and the XAML gets added to Themes/generic.xaml for you.
To inherit from this control, the easiest way is to add another new Custom Control (WPF) and then change the code behind to inherit from your parent control instead of Control.
There are a number of ways to split up the pieces to make them easier to work with.
MVVM, as mentioned in a comment, relies upon Data Binding to separate the input controls from logic. By setting the appropriate class which implements INotifyPropertyChanged into the DataContext of you control, you can change the behaviour. Your DataContext class or ViewModel could implement Visibility properties to show and hide different parts of the input if the differences are not too great between the uses.
Another way to break apart functionality is by Aggregation. See StackOverflow 269496
You could build smaller controls that implement common functionality and then build larger special purpose controls by combining the smaller controls (i.e. aggregating them) to make the larger control. Aggregation will work for both the code-behind and the Data Binding approaches.
I'm new to wpf and now I have a problem. I have a model class say Customer and I've created a DataTemplate with TargetType property set to Customer. It works good. But I actually want two different templates like one for just displaying the record and another for in-place editing. Is it possible to specify two different templates for same datatype based on some creteria?
And I want to switch this template based on some property on ViewModel like when IsEditmode is True.
Or am I doing it wrong? Should I use styles instead?
Your approach seems to be perfectly fine.
You can create a DataTemplateSelector which will allow you to choose a data template based on arbitrary criteria from code behind.
I often use these to decide which template to use based on a enum-type property.
There are two easy ways I can think of, ofcourse there are other ways based on the complexity and architecture you want to follow.
Define DataTemplate with 'Key' and specifically call that either using StaticResource/DynamicResource Binding.
You can have a DataTrigger inside the datatemplate which makes some parts of the template visible/collapsed based on your 'EditMode' property
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.
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?
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.