I have an SL4 user control. It contains a DatePicker. The control exposes a DateTime dependency property (not nullable, because it's a required field). I've bound the SelectedDate of the DatePicker (which is a Nullable<DateTime>) to this DateTime property of {RelativeSource Self}, as two-way. This binding works except when I enter a null date in the DatePicker. The binding is set up with ValidatesOnExceptions, so the border of the DatePicker turns to red, but in the tooltip it says "input is not in a correct format". But it should say that the field is required.
I tried a custom IValueConverter which throwed an exception (ValidationException, FormatException, InvalidOperationException. etc.) with a custom text, but they all ended up unhandled.
I know my control could implement INotifyDataErrorInfo, but the problem is that the null value doesn't even make it into my control, since my DateTime is not nullable, so there's nothing to validate.
I could easily do this thing without any binding at all. Or by binding to a hidden Nullable<DateTime> property in my control, validating that this property is not null, and exposing another DateTime property. Or by providing a ValueConverter which converts a null to DateTime.MinValue or something.
But these methods all seem like workarounds and I'd love a better solution. What's the best way to handle this?
Submitted to Connect, votes appreciated.
https://connect.microsoft.com/VisualStudio/feedback/details/661318/the-binding-engine-doesnt-handle-exceptions-from-a-converter
You've basically got to make the value you're binding your DatePicker to a nullable DateTime even though null isn't a valid value.
Then you'll just have to rely on your validation logic to ensure that your application never allows the value to be processed/stored/whateverd while it's null.
Related
How is it possible to do multivalue binding in Silverlight?
I have to determine the Visibility of a Silverlight DataGrid column depending on the value present as part of Datacontext and other one from the QueryString.
I use MVVM Model of silverlight 5 and my plan is currently to define a property for querystring in code behind that can be binded to row visibility. But my problem clearly here is to pass multiple values for the IValueConverter implementation.
Can anyone provide a simple example to solve my problem?
Multi binding is not supported out of the box in Silverlight.
But with the introduction of customer markup extensions in Silverlight 5, this can be achieved.
There's a good example on code project: http://www.codeproject.com/Articles/286171/MultiBinding-in-Silverlight-5.
Alternatively, in this particular example you can have public boolean a property in your view model which uses the QueryString Value along with the other value you are concerned in DataContext and decides whether the column needs to be visible or not. You can then databind this property to your column's IsVisible property. (Along with a value converter which returns Visbility.Visble /Visibility.Collapsed depending on the value of the boolean property value)
I'm using IDataErrorInfo to validate my viewmodels as it allows me to use a clear xaml sintax and it's pretty straightforward once you get it.
My question is how to validate one property when another one changes because the validation does not consist only on the value on the cell but depends on others. I see that the validation method is only called when the value of the property changes.
Thanks in advance.
with IDataErrorInfo you can hook into
public string this[string columnName]
by overriding it, or writing your own.
in your case do a check that the columnName equals the property you are looking to validate and then either return a string with a value to represent a validation error, or null to say there was no error.
Also, to make sure it gets revalidated, when the dependent properties get updated, make sure you do a OnPropertyChanged for the main property
I have seen implementations of numeric TextBox with code behind in WPF. How do we do this in MVVM pattern?
In WPF if you bind the TextBox to a Decimal or a Int Property it will accept only that int or decimal otherwise it will show a red border that it does not have proper value in the binding. And if you are talking about the numeric updown textbox then it is readily available with WPF toolkit over here
honestly - what does MVVM and numeric textbox have in common?
if you want a numeric textbox you create a new TextBox or AttachedProperty or a Behaviour.
Here is an example for a MaskedTextbox behaviour to see what i mean.
now to your MVVM part. i assume that you want to validate your input to be just numeric. if your viewmodel has an Property of type int, then your binding just works if your view got input which is convertable to int. otherwise your viewmodel will never be informed. there are 2 ways now:
first: you make sure that your view just can take numeric input (with your numeric textbox) and the viewmodel property can be int.
or second: your viewmodel property type is typeof string and you use IDataErrorInfo to let the view know when the input is not numeric.
By the standard definition of MVVM you would not want a ViewModel behind a custom control. All you should do is extend the TextBox control and ensure only numeric input is entered. You should also add a DependencyProperty that returns the numeric input.
The ViewModel would come in when that control is used in a window or a composite control. You would bind the Text or Numeric DependencyProperty to a public property in your ViewModel.
Well... if you want to be notified in your viewmodel when the text property of the numeric textbox changes just bind to it. If the .Text property of the numeric textbox is not a dependency property slap the coder!
this one: http://wpftoolkit.codeplex.com/wikipage?title=DecimalUpDown&referringTitle=Home
I can recommend and you can bind to it from the viewmodel via:
<!-- View: -->
<NumericTextBox Text="{Binding MyViewModelTextStringProperty}" />
//ViewModel:
public string MyViewModelTextStringProperty
{
get/set with NotifyPropertyChanged....
}
If you really wanted to do this in the ViewModel, you'd have to make your bound property a string. Ensure that the binding updates at each keystroke (using the UpdateSourceTrigger).
In your setter, reject non-numeric values by either raising an exception or trimming out non-numerical characters. The latter approach has the benefit of working for copy/paste operations where the pasted text may contain a mix of digits and letters, but only the digits must be retained.
That being said, I would agree with other suggestions that having a specialized control that only exposes a numeric property is a cleaner approach.
Regards,
Eric.
I have a simple scenario and a issue with it which I just cant seem to resolve past few days.
OK, first of all I use MVVM to bind my View on a ViewModel. I have in my view several text boxes which binds to several properties (most strings) in ViewModel (binds actually to an Custom Object (type Person, name SelectedPerson) with strings properties , object which is a property of the viewmodel). This object implements INotifyPropertyChanged and IDataErrorInfo. It has also an int property named Age. I also have in my view a button which is bound to a command in my viewmodel, a command which inside CanExecute test the SelectedPerson's properties and return true if all are correct.
Now my issue is: if I put in my Age text box from my View something not int, a red tectagle will appear (is normal, because there is an exception to the conversion), but in that specific moment, to the object behind (SelectedPerson, type Person) there isn't sent the newValue (the setter to that property Age, or the IDataErrorInfo Members don't intercept the value .... I guess it is normal because there isn't any "new" value, because I put an incorrect format in the text box in the first place).
So, maybe I repeat myself, the issue is: if the new Age (new incorrect Age) isn't set, then the Object behind still hold last value, which if it was correct then the command itself it's correct (the can execute will return true) and the button is enabled
As you can imagine I want the submit button (it's a button which saves current person details in data storage module) to be disabled when current properties don't pass through conversions methods.
PS: I used a IValueConverter class , and on that text box binded to Age, I made use of my StringToIntConverter class....but on Convert Method I don't know how to pass the SelectedPerson binded object (I just pass the text value, and return the int value)
I guess one way to do it could be by using MultiBinding scenario , but I'm not sure.
If I could pass the SelectedPerson inside Convert method from that converter I could invalidate that command from the converter itself.
Sorry for my English, I know it's far from perfect :) and thanks in advance for your time.
I think the cleanest solution would be to bind the textbox to a string property instead, and update your view model so that your IDataErrorInfo implementation for that property name attempts a string to int conversion and returns the result of that. Your CanExecute test would also then include this conversion as part of the validation test.
I'm reasonably new to WPF, have developed a couple of apps with code-beinding files and have read up on MVVM (via Schifflett's 'in the box' introduction) prior to starting my current application.
The items I'm working with have a bunch of generic string properties, plus a Dictionary property called Hours which maps dates to hours worked.
My user interface has a DataGrid view of these items (bound to a collection in the ViewModel), and a combobox which allows the user to select a date (which binds the selected value to SelectedDate in the ViewModel). The DataGrid's Hours column needs to show the number of hours worked in the week (i.e., have the same effect as calling item.Hours[SelectedDate] or similar).
What is the best way to do this? Is it possible to put a variable within the binding expression like {Binding Hours[SelectedDate]}?
The two solutions that immediately come to mind are these:
1) Create an Hours property that is based on your SelectedDate:
public int Hours {get { return calculateHours(SelectedDate); } }
"calculateHours" could either be a method or you could put the calculation in the Setter itself. Make sure that whenever SelectedDate is Set that you raise PropertyChanged for "Hours" as well.
I would use this approach if this Hours calculation is only used in this View from this ViewModel.
2) Create a Value Converter that accepts a date and returns the calculated value. Then bind the Hours to the SelectedDate property:
<TextBlock Text="{Binding SelectedDate, Converter={StaticResource DateToHoursConverter}}"
I would use this approach if the calculation is required in multiple Views or in multiple ViewModels. Value Converters are great for this kind of reuse.
if your property you bind to has an indexer, you can bind to it. you just have to raise INotifyPropertyChanged for this indexer at the right time.
edit: a variable within the binding expression will not work, but you can bind to Hours and use a converter and the SelectedDate as convertparameter to get the value you want. you should have to raise INotifyPropertyChanged for "Hours" when "SeletedDate" changed.