Someone suggested in another question that they, at some point, were able to bind a value to a field in WPF.
I know that this is not a supported scenario (and personally I have only seen binding work with properties), but is it even technically possible?
No. Binding in WPF uses either a PropertyDescriptor or the Dependency Property mechanism, which only works on Properties.
(Technical note here: A Dependency Property is technically sort of a field - it's defined as a field, then registered with the DP system, though, and treated more like a property, so I would still call it a property... The field itself doesn't actually store the data in the case of a DP.)
Related
I struggle to understand the purpose of the ViewModel sometimes, especially with respect to what it should and shouldn't do.
So... I find myself wanting to expose a display string from my ViewModel. Ok, actually it's a Date string, where I want to display something like "Unknown" if the date isn't set. Really I want a solution to cover the general case, so I don't want a discussion about using null and fallback values. It could equally be a status message like "Awaiting Dispatch" or "Launch Aborted".
So the quesion is, how should the ViewModel expose display strings to the View. The App will need to be localized, so we can't have hard coded strings in the ViewModel.
Is it ok to access the app's resources from the ViewModel, and return the display string?
As an aside, should I be using a resx string resource, or a Xaml resource dictionary? I'm leaning toward the Xaml. Advantages/Disadvantages?
Thanks,
Mark
As mentioned in the other answers, this is clearly the view's responsibility. The view model should expose the data property (a status enum or something similar) for the view to inspect in order to determine the particulars of the display message. From a purist's perspective, generating display properties from the VM or code behind is right out.
I'm surprised to hear no suggestions of datatriggers, though. Use them in your TextBlock to bind to the exposed status enum value and update the text appropriately. This question compares their performance against binding to a converter and suggests that triggers will perform better in this scenario. I haven't done any testing myself, so I'm not sure, but it seems intuitively reasonable to me, provided you aren't listening for an outrageous number of different enum values. I also think it's the more appropriate method in this case, and I'll cite this question asking for a comparison of VC vs. DT use cases, though I don't think it's terribly contentious. To put it another way, if one holds that a VM is a value converter on steroids (a statement which I'm very leery of and will not agree or disagree with at the moment), then this argument holds: a VM shouldn't be exposing display properties; a VM's purpose and abilities are a super-set of those of a VC; therefore, a VC should not be exposing display properties.
I'm doing my best to give the purist's answer (or what I think it is, at least), but there are certainly easier ways to code it than writing a lot of datatriggers, especially if you have many different values to address.
Regarding your resource question, have a look at this MSDN article on resource files, which is, in certain ways, easier to work with than a resx file. Which approach you should use depends on your use cases.
What you are doing is taking data that is inside the system and converting it to a format that makes it more useful and clear to the user. This is the responsibility of the view. It would be the responsibility of the view to format a valid date into the correct culture and it has the same responsibility for any text that you wish to display.
In the same respect the status examples you give would probably be stored as an enum in the viewmodel (since that would make it easier to apply business logic to them, which is the role of the viewmodel) and it would be the responsibility of the view to display the values in a way that works for the user in all respects. This would include size, colour, font, position and culture.
That being said though I have been known to put display logic in my viewmodel (concatenating firstname and surname for example) simply because it is easier. I've even been known to use code-behind (shock, horror!) where it suits my purpose. There is a sliding scale between purity and pragmatism, and it is up to you where you sit on that line.
To display the string Unknown when the date is not set is a display issue and therefore has to be solved in the view. Even "Awaiting dispatch" is a presentation of a value.
So the answer is: The view model should never expose display strings. The view model has to expose a value that leads the view/a converter/whatever object from the presentation layer to choose a display string.
Even if this answer is not the answer you want to read, it is the answer an MVVM purist has to give. And as you asked for MMVM purists, here it is.
For the date, I would have the ViewModel export a nullable DateTimeOffset, where the null value means "not set". The in the View (via a converter or similar), the null value is displayed as whatever you need.
As to the aside: I would use resx. The reason is that there is a defined fallback mechanism when strings aren't available in the language.
An approach I have taken was creating Culture specific Resources and adding instances (singletons?) of these to the ViewModel.
Then the View can simply Bind to the ViewModel.Resource.DisplayString
See this article for Windows Phone 7 which easily translates to WPF.
If you dislike this because you do not want to tie the culture specific resource to the ViewModel and want the View to solve it you could use/write a ValueConverter that turns a value from a VM property into a display string.
Advance apologies for the event-style explanation; there's a lot of factors that I feel all play a role of their own. WPF is not my native framework of choice, and it probably shows. :)
Old situation: I had a window with several controls. Depending on their selections, I used multibindings and a converter to determine whether certain controls needed to be shown that inform the user about the implications of their changes before they'd eventually confirm them by OK (or simply dismissed by using Cancel). This worked perfectly.
Problem: Too many controls as time went by, too much clutter.
Solution: Put stuff in different Pages so it becomes easier to browse for the user. In order to have changes-to-be persist as a user arbitrarily browses between the pages, I create these dynamically and put them in a cache (Dictionary<string, BasePage>, see below), from which they will be pulled as the user chooses them.
Consequence: I need to decouple the bindings to the notification controls as the different options are now on different pages.
Solution? I put a BasePage class in that exposes certain abstract read-only properties that define the various aspects that the window needs to know about in order to do its notifications. For example, a bool requiresReboot property defines whether the current state of things on that page requires a reboot to take (full) effect. A specific page implements the property based on its controls.
Problem: I do not know how to keep create a proper binding that properly gets updated as the pages are changed. I tried giving my notification controls a binding to the Dictionary<string, BasePage> with a converter that checks all pages and the relevant property.
Questions:
1) How do I create a proper property for this purpose? I presume I need a DependancyProperty as I did a fair bit of reading on MSDN, but I can't figure out how this fits together.
2) How do I make a link between my custom property so that it allows (multiple) control(s) on a page to change that property? Do I use INotifyPropertyChanged somehow? My old example bound against several CheckBox.IsChecked properties in XAML. I am trying to avoid putting tons of events (OnChange, etc) on the controls as the original code did not need it and I have been told it makes for a messy solution for as far WPF is concerned.
3) Finally, I suspect I may need to change my Dictionary<string, BasePage> class to a custom implementation that implements some sort of INotifyPropertyChanged but for Collections? Observable Collection is the term I am looking for, I believe.
I hope someone is able to bridge the gap in my understanding of WPF (property) internals; I would very much appreciate it. A basic sample would be even better, but if it is too complicated, just a nudge in the right direction will do. Thank you. :)
It's been a while since I solved this, and while I cannot remember the exact cause of the problems, there were a few different issues that made up the bulk of the trouble I ran into.
I ended up making the Property in question a non-abstract DependencyProperty in the base class; it was the only way in which I could properly delegate the change notifications to the interface. Derived classes simply ended up binding it to their controls (with a proper Converter in the case extra logic was necessitated).
As Dictionary<string, BasePage> does not support any sort of change notification, I made an extra collection of ObservableCollection<BasePage> which I used for binding purposes.
However, such a collection does not propagate a change event when items inside of it has a property changed. Since this situation required that, and I was binding to the collection itself in the context of a property that does not have a Master<->Detail relationship like a DataGrid (which basically add their own OnPropertyChanged handlers to the binded object), I ended up subclassing a VeryObservableCollecton<>. This one listens to its own items, and throws a proper change event (I think it was an OnPropertyChanged from the INotifyPropertyChanged interface) so that the binding (or in this case a multi-binding) would refresh properly and allow my interface to update.
It is hardly the prettiest code, and it feels over-engineered, but at least it allows me to properly bind the UI to the data in this manner.
I'm looking for a SL4 equivalent to .NET 4's SetCurrentValue API, which would appear to be exactly what I need for my scenario.
In short, I'm writing an attached behavior that updates the value of a given property at appropriate times. However, I don't want it to overwrite any bindings that are set on that dependency property. I merely want to push that value to the property (and therefore have any bindings refresh based on that value).
From what I can tell, there's no easy way to do this yet in SL4.
Thanks
Silverlight does not provide direct access to this level of dependency value. However its this level of value that Animations in storyboards set when they manipulate a property.
Hence a Storyboard with a 0 length duration containing a single DiscreteObjectKeyFrame might achieve your desired result.
I've managed to simulate what I'm after by detecting bindings and injecting a surrogate object between the source and target. I can then manipulate the surrogate and have both sides of the original binding refresh.
It's ugly and more work than I'd like, but it seems to work.
Kent
I am having a hard time figuring out good reasons for the dependency property. Why the System.Controls.TextBox "Text" property a dependency property and not a normal property? What benefits does it serve being a dependency property?
One of the things I am trying to accomplish is to add a ValidationRules property to my UserControl which will contain other validation rules. Like here:
<customControls:RequiredTextBox.ValidationRules>
<validators:NotNullOrEmptyValidationRule ErrorMessage="FirstName cannot be null or empty"/>
</customControls:RequiredTextBox.ValidationRules>
The problem is that I am not sure if ValidationRules property should be DependencyProperty or just a normal property.
The above code gives the following error:
{"Cannot add element to 'ValidationRules'; the property value is null. Error at object 'LearningWPF.ValidationRules.NotNullOrEmptyValidationRule' in markup file 'LearningWPF;component/addcustomerwindow.xaml' Line 35 Position 66."}
Here is the ValidationRules property:
public static readonly DependencyProperty ValidationRulesProperty =
DependencyProperty.Register("ValidationRules",
typeof (Collection<ValidationRule>), typeof (RequiredTextBox),
new FrameworkPropertyMetadata(null));
public Collection<ValidationRule> ValidationRules
{
get { return (Collection<ValidationRule>)GetValue(ValidationRulesProperty); }
set { SetValue(ValidationRulesProperty, value); }
}
The benefits are primarily two fold:
Firstly a dependency property is only created when it is used, this means the TextBox class can be very efficient, with a low memory footprint since it has a minimal number of real properties taking up space on the heap. This is especially important in WPF where all controls are just collections of more and more specific types. If each of those inner types declared tens of properties to define behaviour and look then a high level control like a button would end up having the size of a class with something in the ballpark of a hundred properties.
Secondly dependency properties can be tied to an object other than the type that they are created for. This allows the case where a control can set a Grid.Column property, which the Grid control can read and use for layout. This means that we don't hundreds of decorator classes supplying tiny pieces of functionality required by other controls. This means that xmal is far more intuitive and readable.
Edited to address the example in your revised question:
While your validation property won't gain much benefit from being a dependency property (basically out of the reasons in all the answers so far I can only really see my comment of memory footprint coming in to play), and it certainly isn't advantageous as it is in the case of the Text property of a text box where you may want to bind it, or change it based on some other input, I would still implement it as a dependency property. My reasoning for this is simple; you don't gain much, but it also doesn't cost you anything - I have never wished I had used a basic property in a custom control whereas when I first started writing them I was constantly upgrading my basic properties to dependencies because I wanted some extra functionality.
Simply put, while the dependency property is more complex to define that a normal property I would still use it as the de facto standard for WPF controls unless there was some good reason to do otherwise. In much the same way as a property is the standard for classes, even though a field is easier to implement.
The primary benefits I would say are:
First-class data binding support.
Clean Attached Property semantics
Property values which "depend".
That last point is key
Before Dependency Properties, having a value have a local value, an animatable value, an overridable value, a styleable value, a templatable value would require the declaration of multiple Properties/Fields/Dictionary entries, as well as complex state+precedence management.
Dependency Properties give you all these features out of the box, while declaring just ONE property.
That being said, in your case, you may not want to declare your ValidationRules as a DependencyProperty if you won't need to take advantage of these features.
If you do, you'll want to have different handling for your collections (non-empty collections for example). In this particular example, I would use Reflector and see how the .NET TextBox implements their validation collections, and see if you can reuse or copy the code.
There's no point re-inventing the wheel unless you're certain your wheel will be better. My personal experience is that my reinvented wheels tend to be missing things ;).
As Martin Harris already pointed out, DependencyProperties can limit the memory footprint by throwing the property values into a dictionary, however this can (and I believe was?) done by MSFT before the advent of DependencyProperties.
Martin also mentions Attached Properties, but those were also available (at least in designer) before the advent of DependencyProperties. The Attached Property implementation using DependencyProperties is much cleaner.
Dependency Properties are required if you want to use binding to populate the value of a property. If it was just a normal property, you wouldn't be able to bind the Text property to a property of your View Model object, for example.
When creating a WPF user control, is it possible to make a property required via an attribute or other mechanism?
Assign the property to an initial value which can be distinguished from any other value that it might be set to (i.e., null for reference types).
At the point when you need the property, if it has not been set (this.Property == UnsetValue), throw an InvalidOperationException with a description of the issue.
Also, make sure this is prominently described in the documentation on the class, on the property, and on any methods that will throw the exception if the property is not set.
**edit
Alternatively, you could create an XSD schema for your control that identified the property as required, however I don't know how to go about doing this.
A quicker solution might be to implement ISupportInitialize, which would allow you to check the property during deserialization, at which time you can throw an exception. Here's a post on it at Relyea's blog about it.