3
votes

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.

3
Sounds like creating a Custom TextBox would work. - cscmh99
your approach is really good and you should follow that. That binding is of course not some kind of general class (that you can reuse in many projects flexibly) but at least it's specific to the current project. - Hopeless

3 Answers

2
votes

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 :)

1
votes

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 );
    }
}
0
votes

For posterity - the answer I've gone for was my own first update. This is because there appear to be no side effects to subclassing a binding, and this lets me over-ride any defaults I set on the binding using straight XAML which is something I can't do (without a hell of a lot of work) using the mark up extension idea.

Thank you all who took the time to help me out with this.

My Answer

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...