在WPF項目中,我使用INotifyDataErrorInfo實現驗證了TextBox輸入。可能會發生多個錯誤。INotifyDataErrorInfo多個驗證錯誤,舊消息不會消失
當我輸入導致多個錯誤的內容時,顯示所有驗證錯誤。但是,當我修復一個錯誤時,驗證消息不會更改,這意味着會顯示錯誤的錯誤消息。只有當我修復所有錯誤時,消息纔會消失。
這是我的實現問題,還是WPF實現只重新獲取驗證消息,如果HasErrors更改?但是,通過調試器遍歷它,我可以看到GetErrors和HasErrors都被調用。
步驟來重現與附例如:
- 輸入333333. 2驗證消息被示出。
- 將前導3更改爲2.儘管第一個錯誤已修復,但仍會顯示兩條驗證消息。
- 將第二個3更改爲0.兩個消息都消失
- 將第二個數字再次更改爲3。顯示第二個驗證消息。
- 再次將前導數字更改爲3。只顯示第二條驗證消息,儘管它應該同時顯示。
是的,這個例子沒有多大意義,因爲我實際上可以擺脫第一次檢查,因爲它包含在第二次檢查中。
的視圖:
<Window x:Class="WeirdValidationTest.ValidationTestView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:WeirdValidationTest"
Height="60" Width="400">
<Window.DataContext>
<local:ValidationTestViewModel />
</Window.DataContext>
<Window.Resources>
<local:ValidationErrorsToStringConverter x:Key="ValErrToString" />
<ControlTemplate x:Key="ErrorTemplate">
<Border BorderBrush="Red" BorderThickness="1">
<StackPanel Orientation="Horizontal">
<AdornedElementPlaceholder />
<TextBlock Text="{Binding Converter={StaticResource ValErrToString}}" Background="White" />
</StackPanel>
</Border>
</ControlTemplate>
</Window.Resources>
<Grid>
<TextBox MaxLength="6" Validation.ErrorTemplate="{StaticResource ErrorTemplate}"
Text="{Binding InputValue, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Left"
VerticalAlignment="Top" Width="100" />
</Grid>
</Window>
(代碼隱藏在構造簡單InitializeComponent調用)
的視圖模型:
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Runtime.CompilerServices;
namespace WeirdValidationTest
{
internal class ValidationTestViewModel : INotifyPropertyChanged, INotifyDataErrorInfo
{
private readonly Dictionary<string, List<string>> errors = new Dictionary<string, List<string>>();
private uint inputValue;
public event PropertyChangedEventHandler PropertyChanged;
public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;
public uint InputValue
{
get
{
return inputValue;
}
set
{
if (inputValue != value)
{
if (value/100000 == 2)
{
RemoveError("InputValue",
String.Format("Must be in range {0}...{1}", "200000", "299999"));
}
else
{
AddError("InputValue",
String.Format("Must be in range {0}...{1}", "200000", "299999"));
}
uint testNumber = (uint) ((value)/1e4);
{
string msg = string.Format("Must start with value {0}", "20....");
if (testNumber != 20)
{
AddError("InputValue", msg);
}
else
{
RemoveError("InputValue", msg);
}
}
inputValue = value;
OnPropertyChanged();
}
}
}
public bool HasErrors
{
get
{
return errors.Count != 0;
}
}
public IEnumerable GetErrors(string propertyName)
{
List<string> val;
errors.TryGetValue(propertyName, out val);
return val;
}
void AddError(string propertyName, string messageText)
{
List<string> errList;
if (errors.TryGetValue(propertyName, out errList))
{
if (!errList.Contains(messageText))
{
errList.Add(messageText);
}
}
else
{
errList = new List<string> { messageText };
errors.Add(propertyName, errList);
}
OnErrorsChanged(propertyName);
}
void RemoveError(string propertyName, string messageText)
{
List<string> errList;
if (errors.TryGetValue(propertyName, out errList))
{
errList.Remove(messageText);
if (errList.Count == 0)
{
errors.Remove(propertyName);
}
}
OnErrorsChanged(propertyName);
}
private void OnErrorsChanged(string propertyName)
{
var handler = ErrorsChanged;
if (handler != null)
{
handler(this, new DataErrorsChangedEventArgs(propertyName));
}
}
private void OnPropertyChanged([CallerMemberName] string propertyName = "")
{
var handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
}
變換器:
using System;
using System.Collections.ObjectModel;
using System.Globalization;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
namespace WeirdValidationTest
{
[ValueConversion(typeof(ReadOnlyObservableCollection<ValidationError>), typeof(string))]
internal class ValidationErrorsToStringConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var errorCollection = value as ReadOnlyObservableCollection<ValidationError>;
if (errorCollection == null)
{
return DependencyProperty.UnsetValue;
}
return String.Join(", ", errorCollection.Select(e => e.ErrorContent.ToString()));
}
public object ConvertBack(object value, Type targetType, object parameter,
CultureInfo culture)
{
throw new NotImplementedException();
}
}
}
目標。淨版本4.5
編輯: 打一個類似的問題與IDataErrorInfo
,看到了這個問題: Validation Rule not updating correctly with 2 validation rules 更改轉換器有助於
適合我,謝謝。只有2個問題:爲什麼在這兩種方法中沒有最終的OnErrorsChanged(Works without,但我實際上會猜測它是需要的)?那麼errList!= null檢查方法的末尾是什麼(它應該是在方法的開始,我想我只是在我的例子中忘了它) –