对多个WPF控件应用类似的绑定

本文关键字:绑定 应用 控件 WPF | 更新日期: 2023-09-27 18:16:57

如果已经被问到,请提前道歉;我花了一段时间谷歌和搜索堆栈溢出-但找不到类似的问题。

我有一个WPF窗口,里面有很多很多的数据输入控件。所有控件都有到视图模型的双向绑定,并使用IDataErrorInfo进行验证。

这里给出了一个绑定的例子:

<TextBox >
  <TextBox.Text>
    <Binding Path="Street"  Mode="TwoWay" NotifyOnValidationError="True" UpdateSourceTrigger="PropertyChanged" ValidatesOnDataErrors="True">
        <Binding.ValidationRules>
            <ExceptionValidationRule />
        </Binding.ValidationRules>
    </Binding>
  </TextBox.Text>
</TextBox>

这个绑定和其他所有绑定的唯一区别是路径。

我所有的绑定都需要验证规则,以及关于何时更新的指令,因为有很多跨域验证正在进行。

我的问题是-我可以应用相同的绑定到一个文本框没有所有的复制/粘贴,我目前必须做上述的例子?

我在想,也许我应该滚动我自己的绑定子类来照顾它-但我不知道这是不是一个好的做法?

更新:我刚刚尝试了一个绑定的子类,像这样:

 public class ExceptionValidationBinding : Binding
{
    public ExceptionValidationBinding()
    {
        Mode = BindingMode.TwoWay;
        NotifyOnValidationError = true;
        UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
        ValidatesOnDataErrors = true;
        ValidationRules.Add(new ExceptionValidationRule());
    }
}

使我的xaml看起来像这样:

<TextBox Text="{bindings:ExceptionValidationBinding Path=PostCode}" />

它似乎有效…就像我说的,不知道这种方法是否有问题。

对多个WPF控件应用类似的绑定

如果您不希望视图的代码隐藏中有任何代码,您可以创建一个MarkupExtension并在XAML中使用它。下面是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;
    }
}
然后你可以在XAML: 中这样做
<TextBox Text="{local:MyBinding ThePath=Street}">

Edit:看起来这给出了一个运行时错误。将行return binding;改为return binding.ProvideValue(serviceProvider);。我想从Binding派生类实际上是更好的,但我将留在这里无论如何:)

即使您正在使用MVVM,您也可以从代码后面应用绑定(因为它仍然是纯视图逻辑)。据我所知,从XAML内部"模板化"绑定是不可能的。

在你的代码后面做,像这样:

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

为了后代——我想要的答案是我自己的第一次更新。这是因为子类化绑定似乎没有副作用,这让我可以直接使用XAML覆盖我在绑定上设置的任何默认值,这是我使用标记扩展思想无法做到的(没有大量的工作)。

感谢大家花时间帮我解决这个问题。

我的答案

我刚刚尝试了一个绑定的子类,像这样:

 public class ExceptionValidationBinding : Binding
{
    public ExceptionValidationBinding()
    {
        Mode = BindingMode.TwoWay;
        NotifyOnValidationError = true;
        UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
        ValidatesOnDataErrors = true;
        ValidationRules.Add(new ExceptionValidationRule());
    }
}

使我的xaml看起来像这样:

<TextBox Text="{bindings:ExceptionValidationBinding Path=PostCode}" />

它似乎有效…