Validação de dados do formulário WPF realmente simples - como?

Estou a ter uma aula muito simples, vamos chamar-lhe cliente. Parece isto:
namespace TestValidation
{
     class Customer
     {
        private string _name;
        public string Name
        {
            get { return _name; }
            set
            {
                _name = value;
                if (String.IsNullOrEmpty(value))
                {
                    throw new Exception("Customer name is mandatory.");
                }
            }
        }
    }
}
Agora, eu criei um formulário básico, onde o usuário pode adicionar clientes à base de dados. O formulário contém uma caixa de texto simples, limitada à propriedade Nome do cliente, e um botão" Adicionar".

o código XAML é:

<Window x:Class="TestValidation.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:TestValidation"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
<TextBox Margin="119,86,107,194" Name="CustomerName"
        Text="{Binding Path=Customer.Name, 
                ValidatesOnExceptions=True, 
                ValidatesOnDataErrors=True,
                UpdateSourceTrigger=PropertyChanged,
                NotifyOnValidationError=True}"
    />
        <Button Content="Add" HorizontalAlignment="Left" Margin="204,176,0,0" VerticalAlignment="Top" Width="74"/>
    </Grid>
</Window> 

a partir do setter da propriedade Nome, você pode entender que o nome é obrigatório para mim, então eu quero um evento de validação para subir se a caixa de texto Nome deixou em branco. Por regras de validação do WPF-uma vez que o foco do Usuário fora da caixa de texto, e não há nenhum valor lá - ele deve mudar a cor do contorno para vermelho. Por alguma razão, isto não está a acontecer, e não faço ideia porquê. O que está errado no meu processo?

Agora, eu li tantos bons artigos sobre validação em WPF (como impor regras complexas de dados de negócios com WPF, validation in WPF and Validation in Windows Presentation Foundation), but none of them help me a resolver o meu problema.

[[3] eventualmente, eu quero que o formulário se pareça com o formulário em Brian Noyes excelente artigo sobre o primeiro link (não tem 10 créditos, então eu não posso anexar uma foto... triste).

Agradecia que alguém me explicasse como funciona.

Nota importante-estou a trabalhar com o.NET framework 4, por isso preciso de uma solução que se adapte a esta versão.

Author: Flimzy, 2013-12-10

7 answers

Eu definitivamente recomendaria o uso de IDataErrorInfo para a validação do WPF, uma vez que o WPF já entende como usá-lo, e é fácil de implementar.

Para começar, adicione a interface à classe que contém os dados que deseja validar. Os métodos necessários serão provavelmente algo parecido com isto:

public class Customer : IDataErrorInfo
{
    ...

    #region IDataErrorInfo Members

    string IDataErrorInfo.Error
    {
        get { return null; }
    }

    string IDataErrorInfo.this[string columnName]
    {
        get
        {
            if (columnName == "Name")
            {
                // Validate property and return a string if there is an error
                if (string.IsNullOrEmpty(Name))
                    return "Name is Required";
            }

            // If there's no error, null gets returned
            return null;
        }
    }
    #endregion
}

A seguir, terá de definir ValidatesOnDataErrors=True na sua ligação à caixa de texto, para que esta execute a validação sempre que a propriedade Name mudar:

<TextBox Text="{Binding Path=Customer.Name, ValidatesOnDataErrors=True}" ... />
E finalmente, criar um modelo de validação no seu XAML para dizer ao WPF como desenhar um erro de validação. Aqui está o estilo/modelo que costumo usar:
<!-- ValidatingControl Style -->
<Style TargetType="{x:Type FrameworkElement}" x:Key="ValidatingControl">
    <Style.Triggers>
        <Trigger Property="Validation.HasError" Value="True">
            <Setter Property="ToolTip" Value="{Binding 
                Path=(Validation.Errors)[0].ErrorContent, 
                RelativeSource={x:Static RelativeSource.Self}}" />
        </Trigger>
    </Style.Triggers>
</Style>

Também, certifique-se de que a sua classe Customer implementa INotifyPropertyChanged para que responda correctamente às actualizações da IU. Não vejo isso no seu código, mas muitas vezes as pessoas deixam isso de fora por simplicidade:)

 29
Author: Rachel, 2013-12-11 03:23:17

Não especificou uma regra de validação. A regra de validação seria invocada antes do Controle ser deixado e, em seguida, pode fazer o que você quiser para validar as entradas.

Um exemplo simples - e acho que é isso que você quer fazer - é fornecido aqui.

 2
Author: Thorsten Dittmar, 2013-12-10 13:21:54

Utilizar IDataErrorInfo para validação. este link vai ajudar-te.

 2
Author: Sampath, 2013-12-10 13:22:11
A questão pode ser que a tua turma não esteja a implementar a Inotipropertychanged, por isso não é vinculativa como esperavas.

Implemente a interface de substituição INotifyPropertyChanged, crie um evento quando a propriedade mudou e deve funcionar.

Ver http://msdn.microsoft.com/en-us/library/ms743695 aspx para uma passagem.

 0
Author: Dave, 2013-12-10 13:22:43
Eu sei que este post é antigo, mas aqui está algo que funcionou bem comigo. Sem atraso ou codificação longa, mas usei-o apenas em valores duplos. Pode mudá-lo como precisar.
 private void search_box_TextChanged(object sender, TextChangedEventArgs e)
    {
        //  box text and background to normal state if user types numbers
        search_box.Foreground = Brushes.Black;
        search_box.Background = Brushes.White;

          if (search_id.IsSelected == true)
        {
            try
            {
                //convert while user is typing
                if (string.IsNullOrEmpty(search_box.Text)==false)
              Convert.ToDouble(search_box.Text);
                search_error.Text = null;
            }

            //if user types a letter or a space or a symbol  ====>
            catch (Exception)
            {
          //  user cant type any value other than numbers as exception prevents it and clears the box text value <======
                search_box.Text = null;
                search_box.Foreground = Brushes.White;
                search_box.Background = Brushes.Red;
                search_error.Text="id is numberic value";
            }
        }

        }
Espero que ajude.
 0
Author: homa, 2018-09-06 18:07:05
<Binding Path=Name UpdateSourceTrigger="PropertyChanged">
  <Binding.ValidationRules>
    <ExceptionValidationRule />
  </Binding.ValidationRules>
</Binding>

Http://msdn.microsoft.com/en-us/library/ms752347%28v=vs.110%29.aspx#what_is_data_binding

Por favor, use este blog : prasadcsharp.blogspot.com

 -1
Author: user3510437, 2014-04-08 10:14:28
<ControlTemplate x:Key="TextBoxErrorTemplate">
    <StackPanel>
        <StackPanel Orientation="Horizontal">
            <Image Height="16" Margin="0,0,5,0" 
                    Source="Assets/warning_48.png"/>
            <AdornedElementPlaceholder x:Name="Holder"/>
        </StackPanel>
        <Label Foreground="Red" Content="{Binding ElementName=Holder, 
               Path=AdornedElement.(Validation.Errors)[0].ErrorContent}"/>
    </StackPanel>
</ControlTemplate> 


<TextBox x:Name="Box" 
         Validation.ErrorTemplate="{StaticResource TextBoxErrorTemplate}">
    <TextBox.Text>
        <Binding Path="ValueInBox" UpdateSourceTrigger="PropertyChanged">
            <Binding.ValidationRules>
                <ValidationExpamples:DoubleRangeRule Min="0.5" Max="10"/>
            </Binding.ValidationRules>
        </Binding>
    </TextBox.Text>           
</TextBox>

Classe IntRangeRule:

public class IntRangeRule : ValidationRule
{
    private int _min;
    private int _max;
    public IntRangeRule()
    {
    }
    public int Min
    {
        get { return _min; }
        set { _min = value; }
    }

    public int Max
    {
        get { return _max; }
        set { _max = value; }
    }
    public override ValidationResult Validate(object value, CultureInfo cultureInfo)
    {
        int l_input = 0;
        try
        {
            if (((string)value).Length > 0)
            {
                l_input = Int32.Parse((String)value);
            }
        }
        catch (Exception e)
        {
            return new ValidationResult(false, "Illegal characters or " + e.Message);
        }

        if ((l_input < Min) || (l_input > Max))
        {
            return new ValidationResult(false, "Please enter an value in the range: " + Min + " - " + Max + ".");
        }

        return new ValidationResult(true, null);
    }
}
 -1
Author: Amir Twito, 2018-03-13 16:30:13