0

I created program to check ability of FrameworkElement to contain TextBox.

namespace MyControls
{
    public class FooButton : FrameworkElement
    {
        public FooButton()
        {
            Width = 100;
            Height = 100;
            VisualCollection = new VisualCollection(this);
            VisualCollection.Add(new TextBox() { Text = "Meows" });
        }
        protected override int VisualChildrenCount => VisualCollection.Count;
        protected override Visual GetVisualChild(int index) => VisualCollection[index];
        public VisualCollection VisualCollection { get; }
    }
}
namespace bitmap_test_example
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }
    }
}

Here is XAML file for program:

<Window x:Class="bitmap_test_example.MainWindow"
        xmlns:MyControls = "clr-namespace:MyControls" 
        ......
        Title="MainWindow" Height="450" Width="800">
    <DockPanel>
        <MyControls:FooButton></MyControls:FooButton>
        <Button>yeah</Button>
    </DockPanel>
</Window>

But unfortunately program does not show TextBox. (By the way I checked visual tree, TextBox is indeed contained within custom FooButton)What's the problem with code? Maybe additional methods should be redefined for FrameworkElement? enter image description here

Alex Aparin
  • 4,393
  • 5
  • 25
  • 51
  • Can you try naming the DockPanel and add the textbox to its children? – Emanuele Jun 24 '21 at 13:50
  • @Emanuele I want to use exactly subclass of `FrameworkElement`. In near future `FooButton` will contain own rendering logic – Alex Aparin Jun 24 '21 at 13:51
  • The lowest class to use should be [Control](https://learn.microsoft.com/en-us/dotnet/api/system.windows.controls.control) class: it has control template, which can be customized. Stripping this away will defeat the huge benefit of WPF - customization. [Related](https://stackoverflow.com/q/5956880/1997232). – Sinatr Jun 24 '21 at 14:08
  • @Sinatr the original problem was I missed layout logic. FrameworkElement is also good choice for customization – Alex Aparin Jun 24 '21 at 14:09
  • 2
    "*FrameworkElement is also good choice for customization*" - not at all in any general way. – Clemens Jun 24 '21 at 14:11
  • @Clemens I agree with you. Just to clarify - I am just porting application written from qt. It originally contained widget with fully custom rendering logic, custom events, custom hit test logic, custom selection etc. That's why I decided to use lightweight object to represent it (FrameworkElement class) – Alex Aparin Jun 24 '21 at 14:16

1 Answers1

3

You should implement the MeasureOverride and ArrangeOverride methods of your custom element. The implementations should measure and arrange the visual children, e.g.:

public class FooButton : FrameworkElement
{
    private readonly UIElement _child = new TextBox() { Text = "Meows" };

    public FooButton()
    {
        AddVisualChild(_child);
    }

    protected override int VisualChildrenCount => 1;

    protected override Visual GetVisualChild(int index) => index == 0 ? 
        _child : throw new ArgumentOutOfRangeException();

    protected override Size MeasureOverride(Size availableSize)
    {
        _child.Measure(availableSize);
        return _child.DesiredSize;

    }
    protected override Size ArrangeOverride(Size finalSize)
    {
        _child.Arrange(new Rect(finalSize));
        return finalSize;
    }
}
Clemens
  • 123,504
  • 12
  • 155
  • 268
mm8
  • 163,881
  • 10
  • 57
  • 88