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"??
Set the outer margin to -2,0,-2,0 to compensate for the padding.
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);
}
}
}
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.