简体   繁体   中英

Hiding base class dependency property in derived control

I am writing a set of custom TextBox controls for different data types. I do not only want the text to be validated (which I do) but also store the input in a property of adequate type.

So for example I have an UnsignedIntegerBox which inherits from TextBox, should store the input in an "uint UnsignedInteger" property, whith default set in xaml. It validates the input in the OnPreviewTextInput event. The OnTextChanged is used to update the UnsignedInteger from Text.

Question: Is there any way to hide the TextBox.Text property so that it is not exposed (and cannot be used) in XAML?

I would suggest to create new CustomTextbox class that could inherit from UserControl / Control class, create a DP property on it as you want and bind it to a TextBox in Control template / Content of your new control. So that you still use TextBox for input/visuals but from code point it is hidden behind your new CustomTextBox class

When you extend a superclass, then the subclass is the superclass. You can never remove any members of the superclass. You can change the behavior by overriding virtual members or hiding accessible members. Maybe you should revisit the inheritance rules of OO languages like C# to understand the concept.

This is what you can do, where 3, 4, 5 are the only clean and useful solutions:

  1. When you hide the Text property to declare it private , then you would get a XAML error, due to the type inference of the XAML engine. This way the Text property is available via Intellisense, but you can't set it. But in C# the next accessible member is chosen. The member lookup behavior will automatically exclude the new hiding private Text property and will then find the public superclass member.
class MyTextBox : TextBox
{
  // Only has an effect in XAML
  new private string Text { get; set; }
}

Even if this would work, you could always set the static DependencyProperty using the DependencyObject.SetValue method. Hiding is also only hiding and not removing. You can always cast to the superclass to get access to the original Text property.

  1. You can override the DependencyProperty meta data to disallow data binding
public class MyTextBox : TextBox
{
  static MyTextBox()
  {
    TextBox.TextProperty.OverrideMetadata(
      typeof(MyTextBox), 
      new FrameworkPropertyMetadata(default, FrameworkPropertyMetadataOptions.NotDataBindable));
  }
}

This will throw an exception if you try to bind to the Text property.
But you can still set the value via assignment.

  1. Use composition over inheritance. You can the design the class API to your requirements and delegate the functionality to the inaccessible composition type.
class MyTextBox : TextBox
{
  private TextBox TextBox { get; }

  public int Number
  { 
     get => return this.TextBox.Text;
     set
     {
       if ( IsValid(value))
       {
         this.TextBox.Text = value;
       }
     }
}
  1. Extend the class in the type hierarchy that does not declare the unwanted members. In your case this would be TextBoxBase .
// Will not have a Text property
class MyTextBox : TextBoxBase
{
}
  1. Throw a NotSupportedException exception to make using the inherited members impossible. The developer is immediately notified that eg, the Text property is not availble. May not be the best solution for public libraries.
public class MyTextBox : TextBox
{
  static MyTextBox()
  {
    TextBox.TextProperty.OverrideMetadata(
      typeof(MyTextBoxl), 
      new FrameworkPropertyMetadata(null, OnCoerceText));
  }

  private static object OnCoerceText(DependencyObject d, object baseValue) 
    => throw new NotSupportedException();
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM