【问题标题】:Apply similar binding to multiple WPF controls将类似的绑定应用于多个 WPF 控件
【发布时间】:2016-01-07 03:45:38
【问题描述】:

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

我有一个 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}" />

而且它似乎有效......就像我说的那样 - 虽然不知道这种方法是否有任何问题。

【问题讨论】:

  • 听起来好像创建一个自定义文本框会起作用。
  • 您的方法非常好,您应该遵循它。这个绑定当然不是某种通用类(可以在很多项目中灵活复用),但至少是当前项目特有的。

标签: c# wpf validation data-binding


【解决方案1】:

即使您使用的是 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 );
    }
}

【讨论】:

  • 感谢您花时间发布答案。你会在 ViewModel 被设置为数据上下文之后做这样的事情吗?
  • @Jay 这不是必需的,您应该能够在没有实际源对象(即数据上下文)的情况下设置这些绑定。您需要更改它,以便绑定作用于父窗口/用户控件的数据上下文。但是现在是凌晨 2 点,我现在无法思考 :)
  • 我明白了,我刚刚用另一种方式添加了更新 - 但我也会尝试这种方式!
【解决方案2】:

如果您不希望视图的代码隐藏中有任何代码,您可以创建一个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}">

编辑:看起来这会产生运行时错误。将行 return binding; 更改为 return binding.ProvideValue(serviceProvider);。我想从Binding 派生一个类实际上更好,但无论如何我都会把它留在这里:)

【讨论】:

  • 赞成,这比我的建议干净得多:)
  • 如果您将ThePath 设为构造函数参数,则无需在标记中指定ThePath=,使其更简单。
  • 这与 OP 的方法几乎相同,但更受限制。如果某些特定的 TextBox 要求某些属性应该被覆盖(例如 UpdateSourceTrigger,...),该怎么办?从Binding继承更好。
  • @Dai,如果我将其设为构造函数参数,我将如何为 ThePath 赋值?
  • @Jay 啊,很好,使用他的方法,ProvideValue 方法应该返回一个字符串,而不是一个 Binding :) ,太混乱了。 Binding本身就是一个复杂的MarkupExtension,它的内部代码会做一些神奇的事情,而不是那么简单(看源码了解更多)
【解决方案3】:

为了后代 - 我所追求的答案是我自己的第一次更新。 这是因为子类化绑定似乎没有副作用,这让我可以使用直接 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}" />

而且它似乎工作......

【讨论】:

    猜你喜欢
    • 2011-06-08
    • 2011-08-25
    • 2014-08-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多