3

我想在用户输入时验证文本字段。最初文本为空。验证规则是: 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 不同的绑定模式,它仍然不起作用。

  1. 这里有人可以解释一下当我使用RelativeSource="{RelativeSource Mode=Self}"UpdateSourceTrigger="PropertyChanged"在一起时真正发生的事情。
  2. 我不明白为什么有效值会导致无限循环,但无效值不会。那是因为如果方法Validate返回new ValidationResult(false,xxx),那么.net框架内部的某个地方会抛出一个异常,停止程序运行,那么就不会发生无限循环。而有效值则相反。
  3. 为什么我得到一个堆栈溢出异常,而不是像保持调用方法一样继续调用 ValidateCanExecute方法。

非常感谢

我刚刚添加了调用堆栈:

>   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) 是否在某处触发了停止循环的事件?

4

1 回答 1

1

尝试使用此验证(您必须有一个事件)然后进行其他验证..如果大于 0 且小于 5

private bool AreAllValidNumericChars(string str)
{
  foreach (char c in str)
  {
    if (c != '.')
    {
      if (!Char.IsNumber(c))
        return false;
    }
  }
  return true;
}

private void textBoxMs_PreviewTextInput(object sender, TextCompositionEventArgs e)
{
  e.Handled = !AreAllValidNumericChars(e.Text) && isGreaterOrLess(e.Text);
}

public bool isGreaterOrLess(string text)
{
  int number = Convert.toInt32(text);
  if(number>0 && number<5)
  {
    return true;
  }
  else
  {
    return false
  }

}
于 2013-04-17T13:24:02.917 回答