【问题标题】:ValidationRule ValidatesOnTargetUpdated NullReferenceException at Design TimeValidationRule ValidatesOnTargetUpdated NullReferenceException 在设计时
【发布时间】:2018-02-06 02:03:49
【问题描述】:

我正在尝试编写一个 ValidationRule 来检查字符串是否为空:

public class NotNullValidationRule : ValidationRule
{
  public override ValidationResult Validate(object value, CultureInfo cultureInfo)
  {
    string str = value as string;

    return string.IsNullOrEmpty(str) ? new ValidationResult(false, Application.Current.FindResource("EmptyStringNotAllowed")) : ValidationResult.ValidResult;
  }
}

在我的窗口中,我是这样使用它的:

<TextBox
    Name="TxtDescription"
    Width="Auto"
    controls:TextBoxHelper.Watermark="{DynamicResource Description}">
    <TextBox.Text>
        <Binding Path="MachineToEdit.Description">
            <Binding.ValidationRules>
                <validation:NotNullValidationRule ValidatesOnTargetUpdated="True"/>
            </Binding.ValidationRules>
        </Binding>
    </TextBox.Text>
</TextBox>

如果我启动 Designer,我会得到这个 NullReferenceException:

   at System.Windows.Data.BindingExpression.RunValidationRule(ValidationRule validationRule, Object value, CultureInfo culture)
   at System.Windows.Data.BindingExpression.ValidateOnTargetUpdated()
   at System.Windows.Data.BindingExpression.TransferValue(Object newValue, Boolean isASubPropertyChange)
   at System.Windows.Data.BindingExpression.Activate(Object item)
   at System.Windows.Data.BindingExpression.AttachToContext(AttachAttempt attempt)
   at System.Windows.Data.BindingExpression.MS.Internal.Data.IDataBindEngineClient.AttachToContext(Boolean lastChance)
   at MS.Internal.Data.DataBindEngine.Task.Run(Boolean lastChance)
   at MS.Internal.Data.DataBindEngine.Run(Object arg)
   at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)
   at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Int32 numArgs, Delegate catchHandler)
   at System.Windows.Threading.DispatcherOperation.InvokeImpl()
   at System.Windows.Threading.DispatcherOperation.InvokeInSecurityContext(Object state)
   at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
   at MS.Internal.CulturePreservingExecutionContext.Run(CulturePreservingExecutionContext executionContext, ContextCallback callback, Object state)
   at System.Windows.Threading.DispatcherOperation.Invoke()
   at System.Windows.Threading.Dispatcher.ProcessQueue()
   at System.Windows.Threading.Dispatcher.WndProcHook(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
   at MS.Win32.HwndWrapper.WndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
   at MS.Win32.HwndSubclass.DispatcherCallbackOperation(Object o)
   at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)
   at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Int32 numArgs, Delegate catchHandler)
   at System.Windows.Threading.Dispatcher.LegacyInvokeImpl(DispatcherPriority priority, TimeSpan timeout, Delegate method, Object args, Int32 numArgs)
   at MS.Win32.HwndSubclass.SubclassWndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam)
   at MS.Win32.UnsafeNativeMethods.DispatchMessage(MSG& msg)
   at System.Windows.Threading.Dispatcher.PushFrameImpl(DispatcherFrame frame)
   at System.Windows.Threading.Dispatcher.PushFrame(DispatcherFrame frame)
   at System.Windows.Application.RunDispatcher(Object ignore)
   at System.Windows.Application.RunInternal(Window window)
   at System.Windows.Application.Run(Window window)
   at Microsoft.VisualStudio.DesignTools.DesignerContract.Isolation.DesignerProcess.RunApplication()
   at Microsoft.VisualStudio.DesignTools.DesignerContract.Isolation.DesignerProcess.<>c__DisplayClass5_0.<Main>b__0()
   at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
   at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
   at System.Threading.ThreadHelper.ThreadStart()

为什么会这样?如果我不激活 ValidatesOnTargetUpdated 它正在工作。但我必须验证窗口何时加载。

感谢您的所有回答,祝您有愉快的一天。

【问题讨论】:

    标签: c# wpf xaml


    【解决方案1】:

    编辑:比代码隐藏更好的答案

    在 VS2017 中,在 XAML 编辑器中启用项目代码也为我修复了它。

    --- 上一个答案---

    我遇到了同样的问题,不幸的是,Thomas V 的回答没有奏效。通过将 ValidationRules 添加到代码隐藏中,我能够解决此问题。也许不是最理想的方法,但它确实解决了问题。

    您还可以查看在 Thomas V 的设计器检查中包装代码隐藏逻辑,但它对我来说没有它。

    XAML:

    <TextBox x:Name="FirstNameTextBox">
        <TextBox.Text>
            <Binding x:Name="FirstNameTextBoxBinding"
                     Path="TheNewUser.TheNewUser.GivenName"
                     UpdateSourceTrigger="PropertyChanged" 
                     Mode="TwoWay"
                     NotifyOnValidationError="True"
                     Delay="500" />
        </TextBox.Text>
    </TextBox>
    

    代码隐藏:

    public NewUserWizard_Info_View()
        {
            InitializeComponent();
    
            Loaded += TriggerValidationOnLoaded;
    
            FirstNameTextBoxBinding.ValidationRules.Add(new ValidateEmptyOrNull()
            {
                ValidatesOnTargetUpdated = true
            });            
        }
    
        private void TriggerValidationOnLoaded(object obj, RoutedEventArgs e)
        {
         // This is needed to trigger the validation on first load
            FirstNameTextBox.GetBindingExpression(TextBox.TextProperty).UpdateSource();
        }
    

    【讨论】:

    • 如果您使用的是 x64 配置,设计器将无法运行您的项目代码,并且该按钮将显示为灰色。
    【解决方案2】:

    警告未测试!

    我猜想在设计时方法 Validate 中的值为 null。所以你应该检查当前是否在设计时,然后返回像 ValidationResult.ValidResult 这样有效的东西。

    public class NotNullValidationRule : ValidationRule
    {
      public override ValidationResult Validate(object value, CultureInfo cultureInfo)
      {
    
       if ((bool)(DesignerProperties.IsInDesignModeProperty.GetMetadata(typeof(DependencyObject)).DefaultValue)) 
        {
            return ValidationResult.ValidResult;
        }
    
        string str = value as string;
    
        return string.IsNullOrEmpty(str) ? new ValidationResult(false, Application.Current.FindResource("EmptyStringNotAllowed")) : ValidationResult.ValidResult;
      }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-08-21
      • 2017-06-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-11-21
      • 1970-01-01
      相关资源
      最近更新 更多