Databinding and property datatype - wpf

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.

Related

WPF MVVM - Binding DataGrid to ObservableCollection of Model

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.

How to make ViewModel aware of conversion error

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?

Sorting on Templated Column with converters

My datamodel is like this:
public class ModelA
{
public int ModelId{get;set;}
}
public class ModelB
{
public IEnumerable<ModelA> ChildObjects{get;set;}
}
Now in the Xaml, am using a DataGrid with the ItemSource as List(), and have a template column which binds to ChildObjects with a converter doing the job of getting the first element from ChildObjects and returning the value as that object's ModelId. Now all works fine till now. The issue is when I do sorting on this templated column.
I know one workaround is to have an extra property in ModelB which does the job of what converter is doing and make the sortmemberpath in xaml as that new property name, but that is not what I want as its against the model.
Is there any other perfect way to handle this scenario, as the SortMemberPath can't be made as expression as its just a contant.
You've tagged this MVVM, which I assume means your models are actually view models (or are at least wrapped by view models). That being the case, why wouldn't you add the extra property? After all, it's there to support the view. Your view needs the extra property, so your view model should provide it.

Numeric text box with MVVM Pattern

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.

Silverlight databinding question

Let's say I have a Class called ModelBase
public class ModelBase
{
public string Name
{
get { return "one"; }
}
}
and I have a property named Model of type ModelBase.
Now to the question how do I Bind to the Name property? The c# code would be this.Model.Name.
I've been trying to get this to work a long time, can some one enlighten me?
Not sure why you are having trouble with this.
You should be able to set the object that the Model property is on as the DataContext for your control, then simply bind using {Binding Model.Name}...
What have you tried to do so far?
(You can definitely bind to properties in Silverlight BTW)
You need to assign Model to the datacontext property before you can do any data binding, an example would be:
this.DataContext = Model;
In xaml, setup binding in this way:
<TextBlock Text={Binding Name}/>
Note: The way you declare the Name property only allows one time binding, to allow OneWay/TwoWay binding, look at dependencyproperty or INotifyPropertyChanged interface.
You can definitely databind to properties.
If you want more, you can use dependency properties of silverlight.
Check this URL.
Silverlight doesn't allow binding to properties. You'll need to expose a property on your viewmodel that returns the value of the models properties to bind correctly.

Resources