Apologies in advance if this has already been asked; I have spent a while Googling and searching stack overflow - but can't find a similar question.
I have a WPF window which has many, many data entry controls. All the controls have two way bindings to the view model, and validate using IDataErrorInfo.
An example of one the bindings is given here:
<TextBox >
<TextBox.Text>
<Binding Path="Street" Mode="TwoWay" NotifyOnValidationError="True" UpdateSourceTrigger="PropertyChanged" ValidatesOnDataErrors="True">
<Binding.ValidationRules>
<ExceptionValidationRule />
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
The only difference between this binding an all the others is the Path.
All my bindings require the validation rule, and the instruction about when to update as there is a lot of cross field validation going on.
My question is - can I apply the same binding to a textbox without all the copy/pasting I am currently having to do for the above example?
I was thinking that maybe I should roll my own subclass of binding to take care of it - but I have no idea if this is good practice or not?
Update: I've just tried a subclass of the binding like so:
public class ExceptionValidationBinding : Binding
{
public ExceptionValidationBinding()
{
Mode = BindingMode.TwoWay;
NotifyOnValidationError = true;
UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
ValidatesOnDataErrors = true;
ValidationRules.Add(new ExceptionValidationRule());
}
}
which makes my xaml look like this:
<TextBox Text="{bindings:ExceptionValidationBinding Path=PostCode}" />
And it seems to work... like I said - no idea if there are any problems with this approach though.
If you don't want any code in your view's code-behind, you can create a MarkupExtension and use it in your XAML. Here's an example of the MarkupExtension:
public class MyBinding : MarkupExtension
{
public string ThePath { get; set; }
public override object ProvideValue(IServiceProvider serviceProvider)
{
Binding binding = new Binding(ThePath) {
Mode = BindingMode.TwoWay,
NotifyOnValidationError = true,
UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged,
ValidatesOnDataErrors = true
};
binding.ValidationRules.Add(new ExceptionValidationRule());
return binding;
}
}
Then you can do this in your XAML:
<TextBox Text="{local:MyBinding ThePath=Street}">
Edit:Looks like this gives a runtime error. Change the line return binding; to return binding.ProvideValue(serviceProvider);. I guess deriving a class from Binding is actually better, but I will leave this here anyway :)
Even if you're using MVVM, you can apply bindings from the code-behind (as it is still pure-view logic). "Templating" bindings from within XAML, as far as I know, is not possible.
To do it from your code-behind, like so:
void InitBinding() {
Address bindingSource = ...
String[] paths = new String[] { "Street", "City", etc... };
foreach(TextBox textBox in ...) {
String path = ... // get the path for this textbox
Binding binding = new Binding( path );
binding.Source = bindingSource;
binding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
BindingOperations.SetBinding( textBox, TextBox.TextProperty, binding );
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With