Правила проверки привязки TextBox WPF не запускаются на LostFocus, когда TextBox пуст - PullRequest
2 голосов
/ 25 июня 2009

Мы все знаем, насколько бесполезна валидация WPF из коробки. Я пробую очень простую вещь, и по какой-то причине она всегда терпит неудачу. У меня есть TextBox, и мое единственное требование - подтвердить, что пользователь вводит что-то в TextBox. TextBox привязан к объекту Customer со свойствами FirstName и LastName.

Вот код 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>

Вот свойство FirstName класса Customer:

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 (значение) является нулевым или пустым, оно обрабатывается только в том случае, если я что-то наберу в TextBox, а затем удалю, а затем уберу вкладку. Причина в том, что это зависит от свойства измененного события. Но даже если я наложу эту привязку TextBox на Focus, она не сработает.

ОБНОВЛЕНИЕ:

Одним из самых уродливых способов решения этой проблемы является назначение String.Empty для TextBoxes в событии Window.Loaded:

 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 голосов
/ 16 апреля 2014

Используйте интерфейс INotifyDataError для управления проверкой.

Некоторые полезные ссылки:

http://codeblitz.wordpress.com/2009/05/08/wpf-validation-made-easy-with-idataerrorinfo/ http://www.jonathanantoine.com/2011/09/18/wpf-4-5-asynchronous-data-validation/

0 голосов
/ 18 июля 2012

Решением, которое я использую, является подключение элементов управления для обновления их собственных источников привязки всякий раз, когда они теряют фокус. Это делает элементы управления действительными после того, как пользователь один раз нажал на вкладку или нажал на них.

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.

0 голосов
/ 15 февраля 2010

Я думаю, вам просто нужно указать UpdateSourceTrigger, и вы должны быть готовы (примечание: я также обычно добавляю ValidatesOnDataErrors = true):

0 голосов
/ 05 ноября 2011

Вместо того, чтобы устанавливать все значения в начале, или использовать оператор 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");
    }
 }
0 голосов
/ 26 июня 2009

В вашем примере кода XAML я не вижу привязки. Я предполагаю, что свойство Text TextBox связано с FirstName?

Во-вторых: FirstName инициализируется сначала или он возвращает null при получении TextBox? Привязка к значению 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");
        }
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...