WPF 文本框不触发依赖项 属性 setter

WPF textbox doesn't trigger dependency property setter

我正在尝试创建一个基于 TextBox 的 UserControl,当它失去焦点时,如果文本与 Regex 不匹配,它就会被擦除。

我的问题如下:我已经将 TextBox 的 Text 属性 与我的 UserControl 中名为 Text 的 DependencyProperty 绑定在一起,但是当我在 TextBox 中写入错误的 Text 时,就会使其失去焦点,它什么都不做。

用户控件XAML:

<Grid>
        <TextBox VerticalContentAlignment="Center" Text="{Binding Text, UpdateSourceTrigger=LostFocus, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=UserControl}}" FontFamily="{Binding FontFamily, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=UserControl}}"  FontSize="{Binding FontSize, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=UserControl}}" />
</Grid>

CS 背后的用户控件代码(带有 DependencyProperty):

// Text of the FormatBox
public static readonly DependencyProperty CS_EXAMPLETEXT_PROPERTY = DependencyProperty.Register(nameof(Text), typeof(String), typeof(FormatBox));
public string Text
{
      get { return (string)GetValue(CS_EXAMPLETEXT_PROPERTY); }
      set {
          if (Regex.IsMatch(value ?? "", RegexString ?? "")) SetValue(CS_EXAMPLETEXT_PROPERTY, value);
          else SetValue(CS_EXAMPLETEXT_PROPERTY, "");
      }
}

主窗口XAML:

<!-- Test FormatBox -->
<controls:FormatBox Grid.Row="3" FontFamily="Calibri" FontSize="16" RegexString="^(?:[0-9]{1,3}\.){3}[0-9]{1,3}$" />

但是如果我尝试用普通的 属性 做同样的事情并实现 INotifyPropertyChanged 它就像一个魅力。

CS 背后的 UserControl 代码(正常 属性):

#region INotifyPropertyChanged

public event PropertyChangedEventHandler PropertyChanged;
private Dictionary<string, object> _propertyValues = new Dictionary<string, object>();

protected T GetProperty<T>([CallerMemberName] string propertyName = null)
{
        if (_propertyValues.ContainsKey(propertyName)) return (T)_propertyValues[propertyName];
        return default(T);
}

protected bool SetProperty<T>(T newValue, [CallerMemberName] string propertyName = null)
{
        T current = GetProperty<T>(propertyName);
        if (!EqualityComparer<T>.Default.Equals(current, newValue))
        {
            _propertyValues[propertyName] = newValue;
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
            return true;
         }
         return false;
}

#endregion

// Text of the FormatBox
public string Text
{
        get { return GetProperty<string>(); }
        set {
            if (Regex.IsMatch(value ?? "", RegexString ?? "")) SetProperty<string>(value);
            else SetProperty<string>("");
        }
}

你能帮我让它与 DependencyProperty 一起工作吗?

希望我能正确理解你的问题。通过“它什么都不做”,如果你的意思是 为什么 你包含在 Dependency 属性 的 .Net Wrapper 属性中的条件代码没有被执行,请注意.Net Wrapper Properties 将在运行时被绕过。

您可以在 Xaml Loading and Dependency Properties 上阅读更多相关信息。

回到您需要实施的自定义逻辑,这正是 CoerceValueCallback exist.The CoerceValueCallback is executed as one of the last steps in the Property Value Evaluation 非常适合此类值修正的原因。

例如,


public static readonly DependencyProperty TextProperty =
     DependencyProperty.Register(
         nameof(Text),
         typeof(string), 
         typeof(SampleControl),
         new PropertyMetadata(
             string.Empty, null, new CoerceValueCallback(OnTextValueCoerce)));

private static object OnTextValueCoerce(DependencyObject d, object baseValue)
{
  if(baseValue is string val && d is SampleControl ctrl)
  {
    if (Regex.IsMatch(val ?? string.Empty,  ctrl.RegexString ?? string.Empty)) 
          return baseValue;
    else 
          return string.Empty;
  }

  return string.Empty;
}