AvaloniaUI How to inherit from TextBox

1.6k views Asked by At

So I am trying to create a custom TextBox control with support for SecureString (basically I want to override OnTextInput()) using the Avalonia UI framework.

The obvious approach for me is to directly inherit from TextBox. Like this

namespace myProject.UI.Controls
{
    public class ProtectedTextBox : TextBox
    {
    }
}

To my understanding of inheritance the ProtectedTextBox should now act exactly like the TextBox it derives from.

However when using my ProtectedTextBox it doesn't seem to get rendered at all. I'm certain that I'm just doing some silly mistake here, but for the life of me I can't figure out why it wouldn't work.

Expected behaviour:

This is the axaml code I use for testing:

<Frame xmlns="https://github.com/avaloniaui"
       xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
       xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
       xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
       xmlns:lControls="clr-namespace:myProject.UI.Controls;assembly=myProject"
       mc:Ignorable="d" d:DesignWidth="1440" d:DesignHeight="900"
       x:Class="myProject.UI.Frames.TestFrame">
  <DockPanel Width="1440" Height="900">
      <Panel DockPanel.Dock="Top" Background="Aqua">
        <TextBox Width="200" Height="100" Background="Red"/>
      </Panel>
    <Panel/>
  </DockPanel>
</Frame>

It produced the following perfectly fine output: (We have an ugly but correctly working TextBox) expected

Actual behaviour:

I wouldn't expect any differences when I use my ProtectedTextBox (directly deriving from TextBox)

<Frame xmlns="https://github.com/avaloniaui"
       xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
       xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
       xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
       xmlns:lControls="clr-namespace:myProject.UI.Controls;assembly=myProject"
       mc:Ignorable="d" d:DesignWidth="1440" d:DesignHeight="900"
       x:Class="myProject.UI.Frames.TestFrame">
  <DockPanel Width="1440" Height="900">
      <Panel DockPanel.Dock="Top" Background="Aqua">
        <lControls:ProtectedTextBox Width="200" Height="100" Background="Red"/>
      </Panel>
    <Panel/>
  </DockPanel>
</Frame>

However it's just invisible and doesn't get rendered. (The Avalonia DevTools seem to know that it exists though and when selecting it in the LogicalTree the spot where my ProtectedTextBox should be get's highlighted). actual

So a few questions arise:

  1. Why does my child class behave different than it's parent. Surely it should behave the same?
  2. Is this just some Avalonia specific weirdness (i.e. maybe Avalonia's rendering uses reflection and GetType() which would return different things for these different classes)?
  3. How would I create a custom TextBox control? Is it possible at all (without painfully recreating all of it's functionality myself)?
2

There are 2 answers

0
DB1ADE On BEST ANSWER

Just use StyleKey and implement IStyleable like this:

public class MyTextBox : TextBox, IStyleable
{
    Type IStyleable.StyleKey => typeof(TextBox);
    ...

See https://stackoverflow.com/a/51761372

0
Jorge Fernandez Herrero On

This is just an update because IStyleable will be obsolete in version 0.12.0

For current and future versions the correct approach would be to override

StyleKeyOverride

public class MyTextBox : TextBox
{
    protected override Type StyleKeyOverride { get { return typeof(TextBox); } }
    .....
}