当TextBox为空时,WPF TextBox绑定验证规则不会在LostFocus上触发

时间:2009-06-25 18:03:08

标签: wpf validation textbox

我们都知道糟糕的WPF验证是开箱即用的。我正在尝试一个非常简单的事情,由于某种原因,它总是失败。我有一个TextBox,我唯一的要求是验证用户在TextBox中输入的内容。 TextBox绑定到具有FirstName和LastName属性的Customer对象。

以下是XAML代码:

            <TextBox Style="{StaticResource TextBoxStyle}" Grid.Column="1"  Grid.Row="0" Height="20" Width="100" Margin="10">
                <TextBox.Text>
                    <Binding Path="FirstName" >
                        <Binding.ValidationRules>
                            <ExceptionValidationRule />
                        </Binding.ValidationRules>
                    </Binding>
                </TextBox.Text>

            </TextBox>

这是Customer类的FirstName属性:

public string FirstName
        {
            get { return _firstName;}
            set
            {
                if(String.IsNullOrEmpty(value))
                    throw new ApplicationException("FirstName cannot be null or empty!");
                _firstName = value; 

                OnPropertyChanged("FirstName");
            }
        }

即使我在FirstName(value)为null或为空时抛出异常,只有在TextBox中键入内容然后将其删除然后将其关闭时才会处理。原因是它依赖于属性改变事件。但即使我将这个TextBox绑定放在Focus上,它也不会触发验证。

更新:

处理此问题的最丑陋方法之一是将String.Empty分配给Window.Loaded事件上的TextBox:

 void AddCustomerWindow_Loaded(object sender, RoutedEventArgs e)
        {
            // get all the textboxes and set the property to empty strings! 

            txtFirstName.Text = String.Empty;
            txtLastName.Text = String.Empty; 
        }

以下是绑定代码:

 public AddCustomerWindow()
        {
            InitializeComponent();

            this.Loaded += new RoutedEventHandler(AddCustomerWindow_Loaded);

            gvAddCustomer.DataContext = new Customer();  
        }

5 个答案:

答案 0 :(得分:0)

在您的示例XAML代码中,我没有看到任何绑定。我假设TextBox的Text属性绑定到FirstName?

其次:首先初始化FirstName,还是在TextBox检索时返回null?绑定到null值总是会产生奇怪的行为......

尝试在财产中说明这一点:

   public string FirstName
    {
        get
        {
            if (_firstName == null)
            {
                _firstName = String.Empty;
            }
            return _firstName;
        }
        set
        {
            if (String.IsNullOrEmpty(value))
                throw new ApplicationException("FirstName cannot be null or empty!");
            _firstName = value;

            OnPropertyChanged("FirstName");
        }
    }

答案 1 :(得分:0)

我认为你只需要指定UpdateSourceTrigger就可以了(注意:我通常也会添加ValidatesOnDataErrors = true):

答案 2 :(得分:0)

您最初可以设置私有变量,而不必在开始时设置所有值,或者使用if语句:

private string _FirstName = String.Empty;
public string FirstName
{
    get { return _FirstName; }
    set
    {
        // Probably check for null and handle it here first
        _FirstName = value;
        OnPropertyChanged("FirstName");
    }
 }

答案 3 :(得分:0)

我使用的解决方案是连接控件,以便在失去焦点时更新自己的绑定源。这使控件在用户选中或点击一次后验证。

public AddCustomerWindow()
{
    InitializeComponent();
    this.Loaded += AddCustomerWindow_Loaded;
    gvAddCustomer.DataContext = new Customer();  
}

void AddCustomerWindow_Loaded(object sender, RoutedEventArgs e)
{
    // Manually wire up textboxes of specific interest.
    UpdateSourceOnLostFocus(new TextBox[] {txtFirstName, txtLastName},
                            TextBox.TextProperty);

    // Or, wire up ALL controls of a given type with the help of Telerik's
    // ChildrenOfType extension, using Linq to filter the list where appropriate.
    UpdateSourceOnLostFocus(this.ChildrenOfType<RadDatePicker>()
                                .Where(picker => !picker.IsReadOnly), 
                            RadDatePicker.SelectedValueProperty);
}

void UpdateSourceOnLostFocus<T>(IEnumerable<T> controls, DependencyProperty prop) where T : Control
{
    controls.ToList()
        .ForEach(ctrl =>
        {
            var binding = BindingOperations.GetBindingExpression(ctrl, prop);
            if (binding != null)
                ctrl.LostFocus += (sender, args) => binding.UpdateSource();
        });
}

如果您还希望控件在加载时验证 - 即之前用户选项卡/点击它们 - 那么您可以编写类似于上面的UpdateSourceNow方法,并从AddCustomerWindow_Loaded调用它代替。

但是,我宁愿等到访问每个控件,因为当用户想要输入新的Model对象实例时,如果他们立即看到一个装满红色框的屏幕,对用户来说可能会有些警觉。

答案 4 :(得分:0)