BindingGroup CancelEdit不适用于UpdateSourceTrigger =“PropertyChanged”

时间:2016-11-03 20:11:41

标签: c# wpf

我的问题似乎很简单,但我找不到解决这个问题的方法。所以,我在这里。

这是我的代码。

<TextBox CharacterCasing="Upper">
    <TextBox.Text>
        <Binding Path="nome" UpdateSourceTrigger="PropertyChanged" Mode="TwoWay">
            <Binding.ValidationRules>
                <ValidationRules:IsNotNull/>
                <ValidationRules:MyStringLengthValidationRule Length="45"/>
            </Binding.ValidationRules>
        </Binding>
    </TextBox.Text>
</TextBox>

我正在使用bindgroup进行提交并取消我的编辑。但是,当我使用UpdateSourceTrigger="PropertyChanged"时,命令BindingGroup.CancelEdit()不起作用。为什么呢?

我无法删除UpdateSourceTrigger="PropertyChanged",因为ValidationRules可以在文本更改时发挥作用。

1 个答案:

答案 0 :(得分:2)

当将目标值(在这种情况下为TextBox.Text)分配给源(在本例中为viewmodel属性)时,将应用验证规则。 BindingGroup.CancelEdit()清除错误状态并将源值复制到目标属性。

当您在UpdateSourceTrigger="PropertyChanged" TextBox.Text上设置Binding时,在文本框中的每次击键时,Binding都会在TextBox.Text上运行验证,如果它通过验证,它将目标值复制到source属性。这意味着它会将TextBox.Text复制到yourViewModel.nome

例如,假设yourViewModel.nome最初为空。

用户在文本框中单击并键入“Arnold”。用户输入时yourViewModel.nome更新六次,每个字符一次。

用户点击Cancel按钮,这会导致BindingGroup.CancelEdit()被调用。

BindingGroup.CancelEdit()按照设计行事,将yourViewModel.nome当前值(字符串"Arnold")复制到TextBox.Text

这就是你所看到的问题。

使用BindingGroup,验证提交。如果字段经过验证并通过验证,则会提交。一旦你承诺,取消就太晚了。

如果您想要阻止验证并一起验证/提交一组字段,那么您使用BindingGroupUpdateSourceTrigger="Explicit",这会导致验证/提交仅在BindingGroup.CommitEdit()上发生,或当你打电话给UpdateSource() on the Binding`时:

myTextBox.GetBindingExpression(TextBox.TextProperty).UpdateSource();

讲座结束,答案开始

如果您想要在没有提交的情况下进行验证,那么您将不得不做一些不同的事情。

最简单,最直接的事情是在绑定上设置UpdateSourceTrigger="Explicit",并在文本框上处理TextChanged

XAML

<TextBox CharacterCasing="Upper" TextChanged="anyValidatedTextBox_TextChanged">
    <TextBox.Text>
        <Binding Path="nome" UpdateSourceTrigger="Explicit" Mode="TwoWay">
            <Binding.ValidationRules>
                <ValidationRules:IsNotNull/>
                <ValidationRules:MyStringLengthValidationRule Length="45"/>
            </Binding.ValidationRules>
        </Binding>
    </TextBox.Text>
</TextBox>

代码隐藏

private void anyValidatedTextBox_TextChanged(object sender, TextChangedEventArgs e)
{
    (sender as TextBox)
        .GetBindingExpression(TextBox.TextProperty)
        .ValidateWithoutUpdate();
}

或者您可以在不更新的情况下进行整个BindingGroup验证:

private void anyValidatedTextBox_TextChanged(object sender, TextChangedEventArgs e)
{
    myFormStackPanel.BindingGroup.ValidateWithoutUpdate();
}

另一个答案

更普遍的做法,即更正统的MVVM,就是编写一个执行相同操作的行为。

using System;
using System.ComponentModel;
using System.Windows;

namespace HollowEarth.Behaviors
{
    public static class Validation
    {
        #region Validation.OnPropertyChanged Attached Property
        public static DependencyProperty GetOnPropertyChanged(FrameworkElement obj)
        {
            return (DependencyProperty)obj.GetValue(OnPropertyChangedProperty);
        }

        public static void SetOnPropertyChanged(FrameworkElement obj, DependencyProperty value)
        {
            obj.SetValue(OnPropertyChangedProperty, value);
        }

        public static readonly DependencyProperty OnPropertyChangedProperty =
            DependencyProperty.RegisterAttached("OnPropertyChanged", typeof(DependencyProperty), typeof(Validation),
                new PropertyMetadata(null, OnPropertyChanged_PropertyChanged));

        private static void OnPropertyChanged_PropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var obj = d as FrameworkElement;

            if (e.OldValue != null)
            {
                DependencyPropertyDescriptor.
                    FromProperty(e.OldValue as DependencyProperty, obj.GetType())
                    .RemoveValueChanged(obj, ValidateHandler);
            }

            if (e.NewValue != null)
            {
                DependencyPropertyDescriptor.
                    FromProperty(e.NewValue as DependencyProperty, obj.GetType())
                    .AddValueChanged(obj, ValidateHandler);
            }
        }

        static void ValidateHandler(object sender, EventArgs args)
        {
            var fe = (FrameworkElement)sender;
            var dprop = GetOnPropertyChanged(fe);
            fe.GetBindingExpression(dprop).ValidateWithoutUpdate();
        }
        #endregion Validation.OnPropertyChanged Attached Property
    }
}

XAML:

<TextBox 
    xmlns:hb="clr-namespace:HollowEarth.Behaviors"
    CharacterCasing="Upper" 
    hb:Validation.OnPropertyChanged="{x:Static TextBox.TextProperty}"
    >
    <TextBox.Text>
        <Binding Path="nome" UpdateSourceTrigger="Explicit" Mode="TwoWay">
            <Binding.ValidationRules>
                <ValidationRules:IsNotNull/>
                <ValidationRules:MyStringLengthValidationRule Length="45"/>
            </Binding.ValidationRules>
        </Binding>
    </TextBox.Text>
</TextBox>

我宁愿将此行为应用于BindingGroupBindingGroup的所有者,而不是应用于单个字段,但当我尝试使用BindingGroup.BindingExpressionsBindingGroup.Items时在应用它们时都是空的。 BindingGroup没有事件,其集合没有事件。我打赌你可以对BindingGroup所有者的行为采取行动,你可以在LayoutUpdated上挂钩,但我的注意力开始徘徊。我会把它作为学生的练习。

作为进一步的练习,您可以复制并粘贴我的代码,甚至无需阅读。这就是我的工作,十分之九。