我想在用户输入时验证文本字段。最初文本为空。验证规则是: 1 它只是数字。2 大于0小于5。下面是xmal中的代码。
<TextBox Grid.Column="1" HorizontalAlignment="Left" Style="{StaticResource textBoxInError}" Name="txtQuantity" Margin="70,0,0,0" Width="70">
<TextBox.Text>
<Binding RelativeSource="{RelativeSource Mode=Self}" Path="Text" UpdateSourceTrigger="PropertyChanged">
<Binding.ValidationRules>
<ValidationRules:PositiveIntegerRule Min="1" Max="5"></ValidationRules:PositiveIntegerRule>
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
我的验证类如下(请忽略汉字,这是错误信息。):
class PositiveIntegerRule : ValidationRule
{
public ushort Max { get; set; }
public ushort Min { get; set; }
public override ValidationResult Validate(object value, System.Globalization.CultureInfo cultureInfo)
{
ushort tmp = 0;
try
{
if (value != null && !String.IsNullOrEmpty(value.ToString()))
{
tmp = ushort.Parse(value.ToString());
}
else
{
return new ValidationResult(false,"数值不能为空");
}
}
catch (Exception e)
{
return new ValidationResult(false, "含有不合法字符");
}
if(tmp < Min || tmp > Max)
{
return new ValidationResult(false,string.Format("超出数值范围:最大值为{0},最小值为{1}",Max,Min));
}
else
{
return new ValidationResult(true,null);
}
}
}
问题是当我运行这个 wpf 应用程序时,只要我输入了一个有效的值,它就会抛出堆栈溢出异常。方法 ValidationResult 被无限调用。而如果我输入了一个无效的值,ValidationResult 方法只会被调用一次。但是不会应用资源中定义的无效值的样式。
我认为这个问题的原因是RelativeSource="{RelativeSource Mode=Self and UpdateSourceTrigger="PropertyChanged"
同时使用。源和目标指向同一事物。所以他们会无限地互相更新。我什至尝试了与 OneWayToSource 不同的绑定模式,它仍然不起作用。
- 这里有人可以解释一下当我使用
RelativeSource="{RelativeSource Mode=Self}"
和UpdateSourceTrigger="PropertyChanged"
在一起时真正发生的事情。 - 我不明白为什么有效值会导致无限循环,但无效值不会。那是因为如果方法
Validate
返回new ValidationResult(false,xxx)
,那么.net框架内部的某个地方会抛出一个异常,停止程序运行,那么就不会发生无限循环。而有效值则相反。 - 为什么我得到一个堆栈溢出异常,而不是像保持调用方法一样继续调用 Validate
CanExecute
方法。
非常感谢
我刚刚添加了调用堆栈:
> JieMeiTaoInventoryManager.exe!JieMeiTaoInventoryManager.ValidationRules.PositiveIntegerRule.Validate(object value, System.Globalization.CultureInfo cultureInfo) Line 16 C#
PresentationFramework.dll!System.Windows.Data.BindingExpressionBase.Validate(object value, System.Windows.Controls.ValidationStep validationStep) + 0x19a bytes
PresentationFramework.dll!System.Windows.Data.BindingExpression.Validate(object value, System.Windows.Controls.ValidationStep validationStep) + 0x18 bytes
PresentationFramework.dll!System.Windows.Data.BindingExpressionBase.UpdateValue() + 0x2e bytes
PresentationFramework.dll!System.Windows.Data.BindingExpression.Update(bool synchronous) + 0x4f bytes
PresentationFramework.dll!System.Windows.Data.BindingExpressionBase.Dirty() + 0x30 bytes
PresentationFramework.dll!System.Windows.Data.BindingExpression.SetValue(System.Windows.DependencyObject d, System.Windows.DependencyProperty dp, object value) + 0x27 bytes
WindowsBase.dll!System.Windows.DependencyObject.SetValueCommon(System.Windows.DependencyProperty dp, object value, System.Windows.PropertyMetadata metadata, bool coerceWithDeferredReference, bool coerceWithCurrentValue, System.Windows.OperationType operationType, bool isInternal) + 0x3c7 bytes
PresentationFramework.dll!MS.Internal.Data.PropertyPathWorker.SetValue(object item, object value) + 0x171 bytes
PresentationFramework.dll!MS.Internal.Data.ClrBindingWorker.UpdateValue(object value) + 0xa3 bytes
PresentationFramework.dll!System.Windows.Data.BindingExpression.UpdateSource(object value) + 0x99 bytes
PresentationFramework.dll!System.Windows.Data.BindingExpressionBase.UpdateValue() + 0x66 bytes
PresentationFramework.dll!System.Windows.Data.BindingExpression.Update(bool synchronous) + 0x4f bytes
PresentationFramework.dll!System.Windows.Data.BindingExpressionBase.Dirty() + 0x30 bytes
PresentationFramework.dll!System.Windows.Data.BindingExpression.SetValue(System.Windows.DependencyObject d, System.Windows.DependencyProperty dp, object value) + 0x27 bytes
WindowsBase.dll!System.Windows.DependencyObject.SetValueCommon(System.Windows.DependencyProperty dp, object value, System.Windows.PropertyMetadata metadata, bool coerceWithDeferredReference, bool coerceWithCurrentValue, System.Windows.OperationType operationType, bool isInternal) + 0x3c7 bytes
WindowsBase.dll!System.Windows.DependencyObject.SetCurrentDeferredValue(System.Windows.DependencyProperty dp, System.Windows.DeferredReference deferredReference) + 0x29 bytes
PresentationFramework.dll!System.Windows.Controls.TextBox.OnTextContainerChanged(object sender, System.Windows.Documents.TextContainerChangedEventArgs e) + 0xa7 bytes
PresentationFramework.dll!System.Windows.Documents.TextContainer.EndChange(bool skipEvents) + 0xd9 bytes
PresentationFramework.dll!System.Windows.Documents.TextContainer.System.Windows.Documents.ITextContainer.EndChange(bool skipEvents) + 0xb bytes
PresentationFramework.dll!System.Windows.Documents.TextRangeBase.EndChange(System.Windows.Documents.ITextRange thisRange, bool disableScroll, bool skipEvents) + 0x77 bytes
PresentationFramework.dll!System.Windows.Documents.TextRange.System.Windows.Documents.ITextRange.EndChange(bool disableScroll, bool skipEvents) + 0x15 bytes
PresentationFramework.dll!System.Windows.Documents.TextRange.ChangeBlock.System.IDisposable.Dispose() + 0x15 bytes
PresentationFramework.dll!System.Windows.Documents.TextEditorTyping.DoTextInput(System.Windows.Documents.TextEditor This, string textData, bool isInsertKeyToggled, bool acceptControlCharacters) + 0x1b2 bytes
PresentationFramework.dll!System.Windows.Documents.TextEditorTyping.TextInputItem.Do() + 0x20 bytes
PresentationFramework.dll!System.Windows.Documents.TextEditorTyping.ScheduleInput(System.Windows.Documents.TextEditor This, System.Windows.Documents.TextEditorTyping.InputItem item) + 0x2f bytes
PresentationFramework.dll!System.Windows.Documents.TextEditorTyping.OnTextInput(object sender, System.Windows.Input.TextCompositionEventArgs e) + 0x16c bytes
PresentationFramework.dll!System.Windows.Controls.Primitives.TextBoxBase.OnTextInput(System.Windows.Input.TextCompositionEventArgs e) + 0x35 bytes
PresentationCore.dll!System.Windows.UIElement.OnTextInputThunk(object sender, System.Windows.Input.TextCompositionEventArgs e) + 0x6f bytes
PresentationCore.dll!System.Windows.Input.TextCompositionEventArgs.InvokeEventHandler(System.Delegate genericHandler, object genericTarget) + 0x31 bytes
PresentationCore.dll!System.Windows.RoutedEventArgs.InvokeHandler(System.Delegate handler, object target) + 0x29 bytes
PresentationCore.dll!System.Windows.RoutedEventHandlerInfo.InvokeHandler(object target, System.Windows.RoutedEventArgs routedEventArgs) + 0x3e bytes
PresentationCore.dll!System.Windows.EventRoute.InvokeHandlersImpl(object source, System.Windows.RoutedEventArgs args, bool reRaised) + 0xbe bytes
PresentationCore.dll!System.Windows.UIElement.RaiseEventImpl(System.Windows.DependencyObject sender, System.Windows.RoutedEventArgs args) + 0x79 bytes
PresentationCore.dll!System.Windows.UIElement.RaiseTrustedEvent(System.Windows.RoutedEventArgs args) + 0x41 bytes
PresentationCore.dll!System.Windows.UIElement.RaiseEvent(System.Windows.RoutedEventArgs args, bool trusted) + 0x2c bytes
PresentationCore.dll!System.Windows.Input.InputManager.ProcessStagingArea() + 0x1ff bytes
PresentationCore.dll!System.Windows.Input.InputManager.ProcessInput(System.Windows.Input.InputEventArgs input) + 0x45 bytes
PresentationCore.dll!System.Windows.Input.TextCompositionManager.UnsafeCompleteComposition(System.Windows.Input.TextComposition composition) + 0x7e bytes
PresentationCore.dll!System.Windows.Input.TextCompositionManager.PostProcessInput(object sender, System.Windows.Input.ProcessInputEventArgs e) + 0x41d bytes
PresentationCore.dll!System.Windows.Input.InputManager.RaiseProcessInputEventHandlers(System.Windows.Input.ProcessInputEventHandler postProcessInput, System.Windows.Input.ProcessInputEventArgs processInputEventArgs) + 0x9d bytes
PresentationCore.dll!System.Windows.Input.InputManager.ProcessStagingArea() + 0x23b bytes
PresentationCore.dll!System.Windows.Input.InputManager.ProcessInput(System.Windows.Input.InputEventArgs input) + 0x45 bytes
PresentationCore.dll!System.Windows.Input.TextCompositionManager.UnsafeStartComposition(System.Windows.Input.TextComposition composition) + 0x74 bytes
PresentationCore.dll!System.Windows.Input.TextCompositionManager.PostProcessInput(object sender, System.Windows.Input.ProcessInputEventArgs e) + 0x6ca bytes
PresentationCore.dll!System.Windows.Input.InputManager.RaiseProcessInputEventHandlers(System.Windows.Input.ProcessInputEventHandler postProcessInput, System.Windows.Input.ProcessInputEventArgs processInputEventArgs) + 0x9d bytes
PresentationCore.dll!System.Windows.Input.InputManager.ProcessStagingArea() + 0x23b bytes
PresentationCore.dll!System.Windows.Input.InputManager.ProcessInput(System.Windows.Input.InputEventArgs input) + 0x45 bytes
PresentationCore.dll!System.Windows.Input.InputProviderSite.ReportInput(System.Windows.Input.InputReport inputReport) + 0x62 bytes
PresentationCore.dll!System.Windows.Interop.HwndKeyboardInputProvider.ProcessTextInputAction(System.IntPtr hwnd, MS.Internal.Interop.WindowMessage msg, System.IntPtr wParam, System.IntPtr lParam, ref bool handled) + 0x189 bytes
PresentationCore.dll!System.Windows.Interop.HwndSource.OnPreprocessMessage(object param) + 0x2c6 bytes
WindowsBase.dll!System.Windows.Threading.ExceptionWrapper.InternalRealCall(System.Delegate callback, object args, int numArgs) + 0x53 bytes
WindowsBase.dll!MS.Internal.Threading.ExceptionFilterHelper.TryCatchWhen(object source, System.Delegate method, object args, int numArgs, System.Delegate catchHandler) + 0x42 bytes
WindowsBase.dll!System.Windows.Threading.Dispatcher.InvokeImpl(System.Windows.Threading.DispatcherPriority priority, System.TimeSpan timeout, System.Delegate method, object args, int numArgs) + 0xb4 bytes
PresentationCore.dll!System.Windows.Interop.HwndSource.OnPreprocessMessageThunk(ref System.Windows.Interop.MSG msg, ref bool handled) + 0xc6 bytes
PresentationCore.dll!System.Windows.Interop.HwndSource.WeakEventPreprocessMessage.OnPreprocessMessage(ref System.Windows.Interop.MSG msg, ref bool handled) + 0x35 bytes
WindowsBase.dll!System.Windows.Interop.ComponentDispatcherThread.RaiseThreadMessage(ref System.Windows.Interop.MSG msg) + 0x3d bytes
WindowsBase.dll!System.Windows.Threading.Dispatcher.PushFrameImpl(System.Windows.Threading.DispatcherFrame frame) + 0xaa bytes
WindowsBase.dll!System.Windows.Threading.Dispatcher.PushFrame(System.Windows.Threading.DispatcherFrame frame) + 0x49 bytes
PresentationFramework.dll!System.Windows.Window.ShowHelper(object booleanBox) + 0x181 bytes
PresentationFramework.dll!System.Windows.Window.Show() + 0x61 bytes
PresentationFramework.dll!System.Windows.Window.ShowDialog() + 0x2d0 bytes
JieMeiTaoInventoryManager.exe!JieMeiTaoInventoryManager.MainWindow.NewItemCommandBinding_Executed(object sender, System.Windows.Input.ExecutedRoutedEventArgs e) Line 291 + 0xd bytes C#
PresentationCore.dll!System.Windows.Input.CommandBinding.OnExecuted(object sender, System.Windows.Input.ExecutedRoutedEventArgs e) + 0x63 bytes
PresentationCore.dll!System.Windows.Input.CommandManager.ExecuteCommandBinding(object sender, System.Windows.Input.ExecutedRoutedEventArgs e, System.Windows.Input.CommandBinding commandBinding) + 0x98 bytes
PresentationCore.dll!System.Windows.Input.CommandManager.FindCommandBinding(System.Windows.Input.CommandBindingCollection commandBindings, object sender, System.Windows.RoutedEventArgs e, System.Windows.Input.ICommand command, bool execute) + 0x10a bytes
PresentationCore.dll!System.Windows.Input.CommandManager.FindCommandBinding(object sender, System.Windows.RoutedEventArgs e, System.Windows.Input.ICommand command, bool execute) + 0x1a0 bytes
PresentationCore.dll!System.Windows.Input.CommandManager.OnExecuted(object sender, System.Windows.Input.ExecutedRoutedEventArgs e) + 0x26 bytes
PresentationCore.dll!System.Windows.UIElement.OnExecutedThunk(object sender, System.Windows.Input.ExecutedRoutedEventArgs e) + 0x59 bytes
PresentationCore.dll!System.Windows.Input.ExecutedRoutedEventArgs.InvokeEventHandler(System.Delegate genericHandler, object target) + 0x3e bytes
PresentationCore.dll!System.Windows.RoutedEventArgs.InvokeHandler(System.Delegate handler, object target) + 0x29 bytes
PresentationCore.dll!System.Windows.RoutedEventHandlerInfo.InvokeHandler(object target, System.Windows.RoutedEventArgs routedEventArgs) + 0x3e bytes
PresentationCore.dll!System.Windows.EventRoute.InvokeHandlersImpl(object source, System.Windows.RoutedEventArgs args, bool reRaised) + 0xbe bytes
PresentationCore.dll!System.Windows.UIElement.RaiseEventImpl(System.Windows.DependencyObject sender, System.Windows.RoutedEventArgs args) + 0x79 bytes
PresentationCore.dll!System.Windows.UIElement.RaiseTrustedEvent(System.Windows.RoutedEventArgs args) + 0x41 bytes
PresentationCore.dll!System.Windows.UIElement.RaiseEvent(System.Windows.RoutedEventArgs args, bool trusted) + 0x2c bytes
PresentationCore.dll!System.Windows.Input.RoutedCommand.ExecuteImpl(object parameter, System.Windows.IInputElement target, bool userInitiated) + 0x111 bytes
PresentationCore.dll!System.Windows.Input.RoutedCommand.ExecuteCore(object parameter, System.Windows.IInputElement target, bool userInitiated) + 0x5b bytes
PresentationCore.dll!System.Windows.Input.CommandManager.TranslateInput(System.Windows.IInputElement targetElement, System.Windows.Input.InputEventArgs inputEventArgs) + 0x3df bytes
PresentationCore.dll!System.Windows.UIElement.OnKeyDownThunk(object sender, System.Windows.Input.KeyEventArgs e) + 0x67 bytes
PresentationCore.dll!System.Windows.Input.KeyEventArgs.InvokeEventHandler(System.Delegate genericHandler, object genericTarget) + 0x34 bytes
PresentationCore.dll!System.Windows.RoutedEventArgs.InvokeHandler(System.Delegate handler, object target) + 0x29 bytes
PresentationCore.dll!System.Windows.RoutedEventHandlerInfo.InvokeHandler(object target, System.Windows.RoutedEventArgs routedEventArgs) + 0x3e bytes
PresentationCore.dll!System.Windows.EventRoute.InvokeHandlersImpl(object source, System.Windows.RoutedEventArgs args, bool reRaised) + 0xbe bytes
PresentationCore.dll!System.Windows.UIElement.RaiseEventImpl(System.Windows.DependencyObject sender, System.Windows.RoutedEventArgs args) + 0x79 bytes
PresentationCore.dll!System.Windows.UIElement.RaiseTrustedEvent(System.Windows.RoutedEventArgs args) + 0x41 bytes
PresentationCore.dll!System.Windows.UIElement.RaiseEvent(System.Windows.RoutedEventArgs args, bool trusted) + 0x2c bytes
PresentationCore.dll!System.Windows.Input.InputManager.ProcessStagingArea() + 0x1ff bytes
PresentationCore.dll!System.Windows.Input.InputManager.ProcessInput(System.Windows.Input.InputEventArgs input) + 0x45 bytes
PresentationCore.dll!System.Windows.Input.InputProviderSite.ReportInput(System.Windows.Input.InputReport inputReport) + 0x62 bytes
PresentationCore.dll!System.Windows.Interop.HwndKeyboardInputProvider.ReportInput(System.IntPtr hwnd, System.Windows.Input.InputMode mode, int timestamp, System.Windows.Input.RawKeyboardActions actions, int scanCode, bool isExtendedKey, bool isSystemKey, int virtualKey) + 0x101 bytes
PresentationCore.dll!System.Windows.Interop.HwndKeyboardInputProvider.ProcessKeyAction(ref System.Windows.Interop.MSG msg, ref bool handled) + 0xf4 bytes
PresentationCore.dll!System.Windows.Interop.HwndSource.CriticalTranslateAccelerator(ref System.Windows.Interop.MSG msg, System.Windows.Input.ModifierKeys modifiers) + 0x8f bytes
PresentationCore.dll!System.Windows.Interop.HwndSource.OnPreprocessMessage(object param) + 0x106 bytes
WindowsBase.dll!System.Windows.Threading.ExceptionWrapper.InternalRealCall(System.Delegate callback, object args, int numArgs) + 0x53 bytes
WindowsBase.dll!MS.Internal.Threading.ExceptionFilterHelper.TryCatchWhen(object source, System.Delegate method, object args, int numArgs, System.Delegate catchHandler) + 0x42 bytes
WindowsBase.dll!System.Windows.Threading.Dispatcher.InvokeImpl(System.Windows.Threading.DispatcherPriority priority, System.TimeSpan timeout, System.Delegate method, object args, int numArgs) + 0xb4 bytes
PresentationCore.dll!System.Windows.Interop.HwndSource.OnPreprocessMessageThunk(ref System.Windows.Interop.MSG msg, ref bool handled) + 0xc6 bytes
PresentationCore.dll!System.Windows.Interop.HwndSource.WeakEventPreprocessMessage.OnPreprocessMessage(ref System.Windows.Interop.MSG msg, ref bool handled) + 0x35 bytes
WindowsBase.dll!System.Windows.Interop.ComponentDispatcherThread.RaiseThreadMessage(ref System.Windows.Interop.MSG msg) + 0x3d bytes
WindowsBase.dll!System.Windows.Threading.Dispatcher.PushFrameImpl(System.Windows.Threading.DispatcherFrame frame) + 0xaa bytes
WindowsBase.dll!System.Windows.Threading.Dispatcher.PushFrame(System.Windows.Threading.DispatcherFrame frame) + 0x49 bytes
PresentationFramework.dll!System.Windows.Application.RunDispatcher(object ignore) + 0x5b bytes
PresentationFramework.dll!System.Windows.Application.RunInternal(System.Windows.Window window) + 0x74 bytes
PresentationFramework.dll!System.Windows.Application.Run(System.Windows.Window window) + 0x2b bytes
PresentationFramework.dll!System.Windows.Application.Run() + 0x1b bytes
JieMeiTaoInventoryManager.exe!JieMeiTaoInventoryManager.App.Main() + 0x5e bytes C#
[Native to Managed Transition]
[Managed to Native Transition]
mscorlib.dll!System.AppDomain.ExecuteAssembly(string assemblyFile, System.Security.Policy.Evidence assemblySecurity, string[] args) + 0x6d bytes
Microsoft.VisualStudio.HostingProcess.Utilities.dll!Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly() + 0x2a bytes
mscorlib.dll!System.Threading.ThreadHelper.ThreadStart_Context(object state) + 0x63 bytes
mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state, bool ignoreSyncCtx) + 0xb0 bytes
mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state) + 0x2c bytes
mscorlib.dll!System.Threading.ThreadHelper.ThreadStart() + 0x44 bytes
[Native to Managed Transition]
更新: 我注意到每次我的程序点击 Validate 方法时都会重复调用以下行。
PresentationFramework.dll!MS.Internal.Data.PropertyPathWorker.SetValue(object item, object value) + 0x171 bytes
PresentationFramework.dll!MS.Internal.Data.ClrBindingWorker.UpdateValue(object value) + 0xa3 bytes
PresentationFramework.dll!System.Windows.Data.BindingExpression.UpdateSource(object value) + 0x99 bytes
PresentationFramework.dll!System.Windows.Data.BindingExpressionBase.UpdateValue() + 0x66 bytes
PresentationFramework.dll!System.Windows.Data.BindingExpression.Update(bool synchronous) + 0x4f bytes
PresentationFramework.dll!System.Windows.Data.BindingExpressionBase.Dirty() + 0x30 bytes
PresentationFramework.dll!System.Windows.Data.BindingExpression.SetValue(System.Windows.DependencyObject d, System.Windows.DependencyProperty dp, object value) + 0x27 bytes
WindowsBase.dll!System.Windows.DependencyObject.SetValueCommon(System.Windows.DependencyProperty dp, object value, System.Windows.PropertyMetadata metadata, bool coerceWithDeferredReference, bool coerceWithCurrentValue, System.Windows.OperationType operationType, bool isInternal) + 0x3c7 bytes
更新 2 如果我的 Validate 方法返回 new ValidationResult(false,xxx),则不会发生无限循环。我想知道 ValidationResult(false,xxx) 是否在某处触发了停止循环的事件?