我想使用IDataErrorInfo驗證我的MVVM應用程序中的數據,但我遇到了一些問題。使用MVVM實現驗證IDataErrorInfo的數據異常
當我設置我的文本框與無效值,驗證工作正常。但經過我設置TextBox爲有效值的價值,我得到這個異常:
A first chance exception of type 'System.ArgumentOutOfRangeException' occurred in mscorlib.dll
A first chance exception of type 'System.Reflection.TargetInvocationException' occurred in mscorlib.dll
System.Windows.Data Error: 16 : Cannot get 'Item[]' value (type 'ValidationError') from '(Validation.Errors)' (type 'ReadOnlyObservableCollection`1'). BindingExpression:Path=(0).[0].ErrorContent; DataItem='TextBox' (Name='txtRunAfter'); target element is 'TextBox' (Name='txtRunAfter'); target property is 'ToolTip' (type 'Object') TargetInvocationException:'System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.ArgumentOutOfRangeException: Index was out of range. Must be non-negative and less than the size of the collection.
Parameter name: index
at System.ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument argument, ExceptionResource resource)
at System.ThrowHelper.ThrowArgumentOutOfRangeException()
at System.Collections.Generic.List`1.get_Item(Int32 index)
at System.Collections.ObjectModel.Collection`1.get_Item(Int32 index)
at System.Collections.ObjectModel.ReadOnlyCollection`1.get_Item(Int32 index)
--- End of inner exception stack trace ---
at System.RuntimeMethodHandle._InvokeMethodFast(Object target, Object[] arguments, SignatureStruct& sig, MethodAttributes methodAttributes, RuntimeTypeHandle typeOwner)
at System.RuntimeMethodHandle.InvokeMethodFast(Object target, Object[] arguments, Signature sig, MethodAttributes methodAttributes, RuntimeTypeHandle typeOwner)
at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture, Boolean skipVisibilityChecks)
at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
at System.Reflection.RuntimePropertyInfo.GetValue(Object obj, BindingFlags invokeAttr, Binder binder, Object[] index, CultureInfo culture)
at MS.Internal.Data.PropertyPathWorker.GetValue(Object item, Int32 level)
at MS.Internal.Data.PropertyPathWorker.RawValue(Int32 k)'
下面是視圖代碼:
<UserControl x:Class="Telbit.TeStudio.View.Controls.TestStepListingStepView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Background="{Binding BackgroundColor}">
<UserControl.Resources>
<Style x:Key="TestStepTextBox" TargetType="{x:Type TextBox}">
<Setter Property="Background" Value="Transparent" />
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="BorderBrush" Value="Transparent"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
<Setter Property="HorizontalContentAlignment" Value="Left"/>
<Setter Property="TextElement.FontSize" Value="10"/>
<Setter Property="TextElement.FontWeight" Value="Regular"/>
<Setter Property="Validation.ErrorTemplate" Value="{x:Null}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TextBox}">
<Border x:Name="Bd" SnapsToDevicePixels="true" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}">
<ScrollViewer x:Name="PART_ContentHost" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="BorderBrush" Value="#3d62a9"/>
</Trigger>
<Trigger Property="IsFocused" Value="true">
<Setter Property="BorderBrush" Value="#3d62a9"/>
<Setter Property="Background" Value="White"/>
</Trigger>
<Trigger Property="Validation.HasError" Value="true">
<Setter Property="ToolTip"
Value="{Binding RelativeSource={RelativeSource Self},
Path=(Validation.Errors)[0].ErrorContent}"/>
<Setter Property="Background" Value="#33FF342D"/>
<Setter Property="BorderBrush" Value="#AAFF342D"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</UserControl.Resources>
...
<TextBox Name="txtRunAfter" Grid.Column="4" Text="{Binding RunAfter, ValidatesOnDataErrors=True, NotifyOnValidationError=True, UpdateSourceTrigger=PropertyChanged}" Style="{StaticResource TestStepTextBox}"
LostFocus="TextBoxLostFocus" PreviewKeyDown="TextBoxPreviewKeyDown" PreviewTextInput="TextBoxPreviewTextInput"/>
...
</UserControl>
這裏是代碼視圖模型:
class TestStepListingStepViewModel : ViewModelBase, IDataErrorInfo
{
private int _runAfter = 0;
public int RunAfter
{
get
{
return _runAfter;
}
set
{
if (_runAfter != value)
{
_runAfter = value;
OnPropertyChanged("RunAfter");
}
}
}
string IDataErrorInfo.Error
{
get { return null; }
}
string IDataErrorInfo.this[string columnName]
{
get
{
string message = null;
if (columnName == "RunAfter")
message = validateRunAfter();
return message;
}
}
private string validateRunAfter()
{
if (_runAfter >= _order)
return "Run After value must be less than its Step Order (#) value.";
return null;
}
}
我想弄清楚這兩天有什麼問題!可以用一雙清新的眼睛看出來嗎?
編輯: 這裏是TextBoxs處理程序的代碼:
public partial class TestStepListingStepView : UserControl
{
private string mInvalidCharPattern = "[^0-9]";
public TestStepListingStepView()
{
InitializeComponent();
DataObject.AddPastingHandler(this.txtRunAfter, new DataObjectPastingEventHandler(TextBoxPasting));
}
private void TextBoxLostFocus(object sender, RoutedEventArgs e)
{
TextBox txt = sender as TextBox;
if (txt != null && string.IsNullOrEmpty(txt.Text))
txt.Text = "0";
}
// Catch the space character, since it doesn't trigger PreviewTextInput
private void TextBoxPreviewKeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Space) { e.Handled = true; }
}
// Do most validation here
private void TextBoxPreviewTextInput(object sender, TextCompositionEventArgs e)
{
if (ValidateTextInput(e.Text) == false) { e.Handled = true; }
}
// Prevent pasting invalid characters
private void TextBoxPasting(object sender, DataObjectPastingEventArgs e)
{
string lPastingText = e.DataObject.GetData(DataFormats.Text) as string;
if (ValidateTextInput(lPastingText) == false) { e.CancelCommand(); }
}
// Do the validation in a separate function which can be reused
private bool ValidateTextInput(string aTextInput)
{
if (aTextInput == null) { return false; }
Match lInvalidMatch = Regex.Match(aTextInput, this.mInvalidCharPattern);
return (lInvalidMatch.Success == false);
}
}
另外,我使用.NET Framework 3.5版本。 我的應用程序非常複雜,所以我不能創建一個僅重建此部分的小項目。我的希望是,你們中的一些人已經有這個問題,並知道如何解決它。
再次感謝大家!
你可以在你的文本框(TextBoxLostFocus,TextBoxPreviewKeyDown,TextBoxPreviewTextInput)事件處理程序中發佈代碼嗎?我試着運行沒有這些處理程序的代碼,它對我來說工作得很好。 你還使用什麼.net版本? – Andrii 2010-06-21 19:22:45
添加了您要求的信息。感謝您的幫助 – jpsstavares 2010-06-22 11:03:08