Проверка текстового поля WPF
у меня есть проверка подключена к модели, которая привязана к TextBox
контейнер. Когда окно впервые открыто ошибки проверки появляются, поскольку модель пуста, я не хочу видеть ошибки проверки до отправки окна или текста в TextBox
изменился или потерял фокус.
здесь TextBox
:
<TextBox Text="{Binding
Path=Firstname,
UpdateSourceTrigger=PropertyChanged,
ValidatesOnDataErrors=True}"
Width="124"
Height="24"/>
как этого можно добиться?
4 ответов
Это действительно зависит от вашей реализации IDataErrorInfo. Если вы основываете его вокруг словаря сообщений об ошибках, вы можете управлять при выполнении проверки, которая добавляет к этому списку. Обычно вы хотите сделать это из своих сеттеров свойств (например, когда вы вызываете PropertyChange), здесь вызывая CheckValidationState:
public string this[string columnName]
{
get
{
return ValidateProperty(columnName);
}
}
public Dictionary<string, string> Errors { get; private set; }
protected void SetError(string propertyName, string errorMessage)
{
Debug.Assert(!String.IsNullOrEmpty(propertyName), "propertyName is null or empty.");
if (String.IsNullOrEmpty(propertyName))
return;
if (!String.IsNullOrEmpty(errorMessage))
{
if (Errors.ContainsKey(propertyName))
Errors[propertyName] = errorMessage;
else
Errors.Add(propertyName, errorMessage);
}
else if (Errors.ContainsKey(propertyName))
Errors.Remove(propertyName);
NotifyPropertyChanged("Errors");
NotifyPropertyChanged("Error");
NotifyPropertyChanged("Item[]");
}
protected virtual string ValidateProperty(string propertyName)
{
return Errors.ContainsKey(propertyName) ? Errors[propertyName] : null;
}
protected virtual bool CheckValidationState<T>(string propertyName, T proposedValue)
{
// your validation logic here
}
вы также можете включить метод, который проверяет все ваши свойства (например, во время save):
protected bool Validate()
{
if (Errors.Count > 0)
return false;
bool result = true;
foreach (PropertyInfo propertyInfo in GetType().GetProperties())
{
if (!CheckValidationState(propertyInfo.Name, propertyInfo.GetValue(this, null)))
result = false;
NotifyPropertyChanged(propertyInfo.Name);
}
return result;
}
обновление:
Я бы рекомендовал поместить приведенный выше код в базовый класс ViewModel, чтобы вы могли его повторно использовать. Затем вы можете создать производный класс следующим образом:
public class SampleViewModel : ViewModelBase
{
private string _firstName;
public SampleViewModel()
{
Save = new DelegateCommand<object>(SaveExecuted);
}
public DelegateCommand<object> Save { get; private set; }
public string FirstName
{
get { return _firstName; }
set
{
if (_firstName == value)
return;
CheckValidationState("FirstName", value);
_firstName = value;
NotifyPropertyChanged("FirstName");
}
}
public void SaveExecuted(object obj)
{
bool isValid = Validate();
MessageBox.Show(isValid ? "Saved" : "Validation Error. Save canceled"); // TODO: do something appropriate to your app here
}
protected override bool CheckValidationState<T>(string propertyName, T proposedValue)
{
// your validation logic here
if (propertyName == "FirstName")
{
if (String.IsNullOrEmpty(proposedValue as String))
{
SetError(propertyName, "First Name is required.");
return false;
}
else if (proposedValue.Equals("John"))
{
SetError(propertyName, "\"John\" is not an allowed name.");
return false;
}
else
{
SetError(propertyName, String.Empty); // clear the error
return true;
}
}
return true;
}
}
в этом случае я использую DelegateCommand для запуска операции сохранения, но это может быть все, что делает вызов метода для сохранения. Эта настройка позволяет начальному пустому состоянию отображаться как допустимое в пользовательском интерфейсе, но либо изменение, либо вызов для сохранения обновлений состояние проверки. Вы также можете получить намного более общий и более сложный способ проверки, поэтому все это не заканчивается одним методом (здесь с некоторыми предположениями о типе), но это упрощается, чтобы сделать его проще начать.
Если вы реализуете IDataErrorInfo, я достиг этого, проверив значения null в реализации логики проверки. При создании нового окна проверка на null предотвратит запуск логики проверки. Например:
public partial class Product : IDataErrorInfo
{
#region IDataErrorInfo Members
public string Error
{
get { return null; }
}
public string this[string columnName]
{
get
{
if (columnName == "ProductName")
{
// Only apply validation if there is actually a value
if (this.ProductName != null)
{
if (this.ProductName.Length <= 0 || this.ProductName.Length > 25)
return "Product Name must be between 1 and 25 characters";
}
}
return null;
}
}
#endregion
}
кроме того, если вы хотите запустить проверку в текстовом поле.LostFocus, измените привязку на LostFocus следующим образом:
<TextBox Text="{Binding
Path=Firstname,
UpdateSourceTrigger=LostFocus,
ValidatesOnDataErrors=True}"
Width="124"
Height="24"/>
в вашем приложении.xaml-файл, вам нужно использовать пользовательский стиль текстового поля для проверки текстового поля без какого-либо стороннего компонента.
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TextBox}">
<Grid Name="test">
<Border Background="{StaticResource TextBackColor}"
BorderBrush="#FF888888"
x:Name="Bd"
CornerRadius="1"
BorderThickness="1">
<ScrollViewer Margin="0" x:Name="PART_ContentHost"/>
</Border>
<Image Name="ErrorImage"
Width="15"
Height="15"
Margin="0,0,4,0"
Source="Images/validate.png"
HorizontalAlignment="Right">
</Image>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
Что я делаю, я не знаю, правильно ли это (я был бы рад узнать, теперь есть шанс), но в инициализаторе сущности или модели я запускаю все валидаторы.