I would like to validate a text field when the user is typing. Initially the text is empty. The validation rules are: 1 It's number only. 2 It's greater than 0 and less than 5. Following is the code in 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>
My validation class is as follows(Please ignore the Chinese characters, it's the error message.):
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);
}
}
}
The problem is when I run this wpf application, as long as the I type in a valid value, then it throw stack overflow exception. Method ValidationResult was called infinitely. While if the I type in a invalid value, the ValidationResult method would be called only once. But the style which for the invalidate value defined in resource wouldn't be applied.
I think the cause of this problem is using RelativeSource="{RelativeSource Mode=Self and UpdateSourceTrigger="PropertyChanged" at the same time. Source and destination are point to the same thing. So they will update each other infinitely. I even tried different binding mode to OneWayToSource, it still doesn't work.
- Could anybody here explain me what really happen when I use
RelativeSource="{RelativeSource Mode=Self}"andUpdateSourceTrigger="PropertyChanged"together. - I don't understand why the valid value cause infinite loop, but invalid value doesn't. Is that because if the method
Validatereturnsnew ValidationResult(false,xxx), then somewhere inside .net framework will throw an exception which stops the program running, then no infinite loop happen. While the valid value is on the opposite. - Why I got an stack overflow exception rather than keep calling Validate method like keeping call
CanExecutemethod.
Many thanks
I just added the call stack:
> 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]
Update: I noticed that following lines are repeatedly called every time my program hit Validate method.
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
Update 2 If my Validate method return new ValidationResult(false,xxx), then infinite loop wouldn't happen. I am wondering if ValidationResult(false,xxx) trigger an event somewhere which stop the loop?
RelativeSourcefromBindingelement, move the validation rules into view model (more maintainable), useushort.TryParsr, do more debugging. - Karel FrajtákTextBox.Textproperty to itself, so changing theTextis causing an infinite loop as it triggers a change notification, which re-evaluates the binding, which updates the values, which triggers a change notification, which re-evaluates the binding, etc. - Rachel