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.
Related
I'm adding a custom string DependencyProperty to a WPF UserControl that will be bound to a string property in my business object that contains rtf.
My PropertyChangedCallback works: it contains a snippet of code to use the e.NewValue rtf string to programmatically do a range.Load() on the RichTextBox nested in my UserControl, feeding it the rtf, when the DataContext changes or the business object's rtf string property changes (via INotifyPropertyChanged).
But what, or where, is the opposite callback to go back the other direction? When the inner RichTextBox loses focus after the user types/pastes their rich text, I need to run a mirror-image snippet of code to do the range.Save() to an rtf string, and that string needs to be written to the string property of the business object at that moment.
I am coming from Winforms, so I'm looking for the WPF analog of the Format/Parse pair that I'm accustomed to for round-tripping.
this.SetCurrentValue(MyDependencyProperty, range.Save());
this being the UserControl that owns the DP.
Also make sure your binding Mode=TwoWay.
I am pretty new to WPF MVVM, so pardon me if I understood MVVM concepts wrongly.
I have a DataGrid in my View, which I have bound the ItemsSource to an ObservableCollection<M> in the ViewModel. The M class is a Model class. However, the M class has bool properties, which are to be displayed in the DataGrid as "Yes/No" strings.
Currently, I am using a Converter to convert the bool value to string. But, it just feels wrong for the ViewModel to expose a list (ObservableCollection) of a Model to the View. I have also read that in MVVM, conversions should be done at ViewModel. So, what is the right way to implement this the MVVM way for a DataGrid?
In an ideal world, you would wrap your Model objects in their own ViewModel so that your ObservableCollection contains a ViewModel type with those bool Model properties converted to Yes/No string properties.
However, in a pragmatic world, if you are not editing those values, I wouldn't bother except to note that if you are exposing many of those bool properties and have many thousands of rows, you will take a performance hit on rendering the grid while the DataGrid instantiates a Converter per property and row.
Using converters is not a wrong way. As per my suggestion, you should bind the data as you're doing now and in the view you can create and use a BoolToStringConverter for converting the boolean value to yes or no.
I am designing a WPF application following MVVM. My ViewModel is exposing one Double property called DoubleValue, which is binding to a TextBox in the View. I have set "ValidatesOnDataErrors=True" for the binding. So if the user types a string which can't be converted to a Double, it display the red background.
In my ViewModel I also have a Command object, let's call SaveCommand, whose CanExecute delegate is depending on whether there is any error in the VM (my ViewModelBase class implements IDataErrorInfo, I have an overridable ValidatePropertyByName function and the validation errors are stored in a dictionary.) But now my problem is, if I give an invalid string in the TextBox, since the conversion fails, it never calls the setter of the binding property value. In another word, the ValidatePropertyByName is not called and the error dictionary remains the previous state, which normally is clean. So if now the user click the Save button (which is enabled since the error dictionary is clean), the SaveCommand executes with the previous valid double value to save. This is obviously not good.
So how can I make my ViewModel aware of such conversion errors?
UPDATE:
Some code example:
The binding property is like this:
Public Property DoubleValue As Double
Get
Return _doubleValue
End Get
Set(value As Double)
If value <> _doubleValue Then
_doubleValue = value
RaisePropertyChanged("DoubleValue")
End If
End Set
End Property
Private _doubleValue As Double
My binding is like this:
<TextBox Grid.Row="3" Text="{Binding DoubleValue, ValidatesOnDataErrors=True}" />
And now my problem is: if I give a string "XXX" in the text box, since it can't be converted to a double value, the setter of DoubleValue is never get called. And so the property value remains the previous(valid) value. Now if my SaveCommand gets executed, it will do the save operation with this previous valid value, which will make the user confused.
the most easy way is to just use string properties in your viewmodel. then you get all input from the user and can validate it in your viewmodel. the drawback is that you have to convert the values to the right type when you go to the model.
if you dont want this you have to create your own controls or better behaviors so that the use can just input values that your viewmodel expect. eg. NumericInputBehavior.
You cannot simply put these two things together. One is the regular validation inside the ViewModel. The other are control-specific problems, like unconvertible values.
So there are two possible ways to solve this:
1) Don't use a converter. Just bind the string. Inside the ViewModel you can then use the validation to check for a valid value. (More MVVM)
2) Store your ValidationErrors on the controlside and merge them with the viewmodel errors. This is not easy but a good way to create one source for binding against ALL problems within your UI. We are doing this for complex textboxes at work. This means manual code in the controls but for complex customcontrols this is OK, I believe.
edit: just to elaborate a little on the 2nd point. We are having a DependencyProperty of Type ObservableCollection inside the Control. Then you can bind this Collection to a ViewModel Property and as soon as your control moves an Error inside the collection it is available inside the viewModel. You can then use this collection inside your validation implementation. This works pretty well for larger controls.
Edit2: For the MarkInvalid Stuff I mentioned in the comment. It would look like this:
DataErrorValidationRule validationRule = new DataErrorValidationRule();
ValidationError validationError = new ValidationError(validationRule, myTextBox.GetBindingExpression(TextBox.TextProperty)) { ErrorContent = "My custom message" };
Validation.MarkInvalid(myTextBox.GetBindingExpression(TextBox.TextProperty), validationError);
You would call in from inside a TextChanged when you can't convert the new given value or
Validation.ClearInvalid(myTextBox.GetBindingExpression(TextBox.TextProperty))
Maybe that will help?
Quick question. I understand how properties work with the get and set methods, but how should I be using them when bound to textboxes.
Should all of my properties be strings and then validated from there to my fields which may be of different types? What would happen if a alpha character was put into a textbox bound to an int type field? does it throw exceptions at that time or If I validate it would it be alright?
thanks!
if all your viewmodel properties are strings then you have no trouble to bind and validate your properties. but of course you have to cast them for your model, but its the most easy way for viewmodel and binding :)
just do a litte test project.
viewmodel:
public string MyStringInt {get;set}
public int MyIntInt {get;set;}
just try to implement IDataErrorInfo for this easy viewmodel and you will see the problems when binding to an int property.
I am using WPF and the MVVM pattern in my user interface. In my ViewModel I have a List containing distances in millimetres, which I display in a ListView by binding ListView.ItemsSource to the List. However, I would like the values displayed to use a more natural unit - either metres or feet depending on the state of a "metric" checkbox.
I have written a couple of simple classes, MillimetresToMetresConverter and MillimetresToFeetConverter, both of which implement IValueConverter. Although I can set the Converter property on my data binding to one or the other, I am unsure how to change between these converters when the state of the checkbox changes.
My plan was to have a field "IValueConverter lengthConverter" on my ViewModel which I could set to one converter or the other, then in my XAML do ...="{Binding Converter={Binding Path=lengthConverter}}" - unfortunately this does not work since Converter is not a dependency property.
How can change the converter used by the data binding at runtime?
Most of the time when using the MVVM methodology, you can do the formatting task in the VM classes. In your case, you could add a Format property to the VM class, and based on the value of the Format property, return a well formated string.
See this discussion for more information.
If I may suggest a simple alternative solution: Create a small FormatMillimetresConverter in your ViewModel, whose UseMetric property is bound to the "metric" checkbox.