Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to set the margin on a internal TextBoxView in wpf

I have a case where I want to minimize the horizontal padding of a textbox.

Using snoop I found that the textbox consists of a multiple sub-controls. One of them is a TextBoxView with a margin of 2,0,2,0

The TextBoxView is an internal wpf component and has no public API.

How would you approach getting rid of the "internal padding"??

like image 782
Sjors Miltenburg Avatar asked Nov 14 '13 13:11

Sjors Miltenburg


People also ask

How do I set margins in WPF?

The Margin property of UIElement, which is parent class of all WPF controls is used to set the margin of a control. Margin property takes four numbers - Left, Top, Right and Bottom, that is margin to the left top and right bottom.

How do you use margin in XAML?

XAML Values Margin="20,50" will be interpreted to mean a Thickness with Left and Right set to 20, and Top and Bottom set to 50. The default unit for a Thickness measure is device-independent unit (1/96th inch). You can also specify other units by appending the unit type strings cm , in , or pt to any measure.

What is padding in WPF?

Padding represents the distance between the side of the control (which can be the margin) and its content. The content depends on the type of the control. Margin is outside the UI element, while Padding is inside it.

What is padding in XAML?

The Padding property represents the distance between an element and its child elements, and is used to separate the control from its own content. Padding values can be specified on layout classes.


3 Answers

Set the outer margin to -2,0,-2,0 to compensate for the padding.

like image 109
Bas Avatar answered Oct 02 '22 16:10

Bas


I created a custom control that removes that internal padding.

public class MyTextBox : TextBox
{
    public MyTextBox()
    {
        Loaded += OnLoaded;
    }                 

    void OnLoaded(object sender, RoutedEventArgs e)
    {
        // the internal TextBoxView has a margin of 2,0,2,0 that needs to be removed
        var contentHost = Template.FindName("PART_ContentHost", this) as ScrollViewer;
        if (contentHost != null && contentHost.Content != null && contentHost.Content is FrameworkElement)
        {
            var textBoxView = contentHost.Content as FrameworkElement;
            textBoxView.Margin = new Thickness(0,0,0,0);
        }
    }       
}
like image 23
Robert Avatar answered Oct 02 '22 16:10

Robert


Here is a dirty way of doing it:

public static class TextBoxView
{
    public static readonly DependencyProperty MarginProperty = DependencyProperty.RegisterAttached(
        "Margin",
        typeof(Thickness?),
        typeof(TextBoxView),
        new PropertyMetadata(null, OnTextBoxViewMarginChanged));

    public static void SetMargin(TextBox element, Thickness? value)
    {
        element.SetValue(MarginProperty, value);
    }

    [AttachedPropertyBrowsableForChildren(IncludeDescendants = false)]
    [AttachedPropertyBrowsableForType(typeof(TextBox))]
    public static Thickness? GetMargin(TextBox element)
    {
        return (Thickness?)element.GetValue(MarginProperty);
    }

    private static void OnTextBoxViewMarginChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var textBox = (TextBox)d;
        OnTextBoxViewMarginChanged(textBox, (Thickness?)e.NewValue);
    }

    private static void OnTextBoxViewMarginChanged(TextBox textBox, Thickness? margin)
    {
        if (!textBox.IsLoaded)
        {
            textBox.Dispatcher.BeginInvoke(
                DispatcherPriority.Loaded,
                new Action(() => OnTextBoxViewMarginChanged(textBox, margin)));
            return;
        }

        var textBoxView = textBox.NestedChildren()
                                 .SingleOrDefault(x => x.GetType().Name == "TextBoxView");
        if (margin == null)
        {
            textBoxView?.ClearValue(FrameworkElement.MarginProperty);
        }
        else
        {
            textBoxView?.SetValue(FrameworkElement.MarginProperty, margin);
        }
    }

    private static IEnumerable<DependencyObject> NestedChildren(this DependencyObject parent)
    {
        for (int i = 0; i < VisualTreeHelper.GetChildrenCount(parent); i++)
        {
            var child = VisualTreeHelper.GetChild(parent, i);
            yield return child;
            if (VisualTreeHelper.GetChildrenCount(child) == 0)
            {
                continue;
            }

            foreach (var nestedChild in NestedChildren(child))
            {
                yield return nestedChild;
            }
        }
    }
}

It allows setting the margin on textboxes:

<Style TargetType="{x:Type TextBox}">
    <Setter Property="demo:TextBoxView.Margin" Value="1,0" />
</Style>

Not optimized for performance at all.

like image 33
Johan Larsson Avatar answered Oct 02 '22 17:10

Johan Larsson