【问题标题】:Make WPF TextBox Margins Clickable/Selectable使 WPF 文本框边距可单击/可选择
【发布时间】:2017-10-29 02:51:57
【问题描述】:

我有一个白色背景的 WPF TextBox。我给了它一些 Padding 以便文本周围有一个“边距”(类似于 MS Word 中的边距)。

<TextBox x:Name="MyTextBox" Padding="25" />

然而,与 Word 不同的是,文本周围的这个空白区域不是“活动的”(参见下面的颜色编码插图)。在其中单击(红色部分)不会移动文本框的插入符号,也不会开始选择。但是请注意,整个绿色区域处于活动状态 - 甚至是文本下方的空白区域(这意味着您可以在其中单击以移动插入符号或开始选择)。 ..

所以,我的问题是:有没有办法在 aTextBox 周围添加空白但也是可编辑区域的一部分(这样它会对点击/选择做出反应,就像绿色部分呢)?

谢谢!

附言我在寻找答案的过程中最接近的是:How to set the margin on a internal TextBoxView in wpf... 但是,虽然增加内部 TextBoxViewMargin 确实会增加文本周围的空间,但该空间似乎仍然没有以任何方式“活跃”...而且似乎TextBoxView 没有Padding 属性,所以我不能尝试(尽管我想Padding 更有可能是解决方案比Margin)...

【问题讨论】:

  • 对此表示赞同。我正在尝试找出完全相同的事情!

标签: c# wpf textbox


【解决方案1】:

我真的很困惑为什么这不是一个受欢迎的问题。 TextBox 肯定有违反直觉的 Padding 行为。

查看了 Microsoft 参考源中的 TextBox 选择代码,但事实证明它太复杂而无法注入修复程序。所以 Behavior 附加属性似乎是实现这一目标的最简单方法。

xaml:

<TextBox Padding="24 0" local:TextBoxSelectionBehavior.IsEnabled="True"/>

c#:

public static class TextBoxSelectionBehavior
{
    public const double MAX_DISTANCE = 10;
    private static TextBox control;
    private static Point pos;
    private static int start;
    private static int cur;
    private static double right;
    private static bool drag;
    private const double MAXDRAG = 12;

    public static readonly DependencyProperty IsEnabledProperty = DependencyProperty.RegisterAttached("IsEnabled", typeof(bool), typeof(TextBoxSelectionBehavior), new UIPropertyMetadata(false, IsEnabledChanged));
    public static bool GetIsEnabled(FrameworkElement obj) => (bool)obj.GetValue(IsEnabledProperty);
    public static void SetIsEnabled(FrameworkElement obj, bool value) => obj.SetValue(IsEnabledProperty, value);
    private static void IsEnabledChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var v = (TextBox)d;
        if ((bool)e.NewValue)
        {
            v.PreviewMouseDown += V_PreviewMouseDown;
            v.PreviewMouseUp += V_PreviewMouseUp;
            v.PreviewMouseMove += V_PreviewMouseMove;
            v.LostFocus += V_LostFocus;
            v.IsKeyboardFocusedChanged += V_IsKeyboardFocusedChanged;
        }
        else
        {
            v.PreviewMouseDown -= V_PreviewMouseDown;
            v.PreviewMouseUp -= V_PreviewMouseUp;
            v.PreviewMouseMove -= V_PreviewMouseMove;
            v.LostFocus -= V_LostFocus;
            v.IsKeyboardFocusedChanged -= V_IsKeyboardFocusedChanged;
        }
    }

    public static readonly DependencyProperty ClickSelectsProperty = DependencyProperty.RegisterAttached("ClickSelects", typeof(bool), typeof(TextBoxSelectionBehavior), new UIPropertyMetadata(true));
    public static bool GetClickSelects(FrameworkElement obj) => (bool)obj.GetValue(ClickSelectsProperty);
    public static void SetClickSelects(FrameworkElement obj, bool value) => obj.SetValue(ClickSelectsProperty, value);

    private static void V_PreviewMouseDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
    {
        if (e.ChangedButton != MouseButton.Left) return;
        if (control != null) { control.ReleaseMouseCapture(); control = null; }
        if (e.OriginalSource is Grid g && (System.Windows.Media.VisualTreeHelper.GetParent(g) as FrameworkElement)?.Name == "PART_ContentHost")
        {
            control = (TextBox)sender;
            pos = e.GetPosition(control);
            var r = control.FindChild<ScrollContentPresenter>().Content as FrameworkElement;
            right = r.TranslatePoint(new Point(r.ActualWidth, 0), control).X;
            cur = start = control.GetCharacterIndexFromPoint(pos, true) + (pos.X >= right ? 1 : 0);
            control.SelectionStart = start;
            control.SelectionLength = 0;
            control.Focus();
            control.CaptureMouse();
            drag = false;
            e.Handled = true;
        }
    }
    private static void V_PreviewMouseMove(object sender, System.Windows.Input.MouseEventArgs e)
    {
        if (control == null) return;
        var p = e.GetPosition(control);
        cur = control.GetCharacterIndexFromPoint(p, true);
        control.SelectionStart = Math.Min(start, cur);
        control.SelectionLength = Math.Abs(cur - start) + (p.X >= right ? pos.X >= right ? -1 : 1 : 0);
        if (!drag) drag = Math.Max(Math.Abs(pos.X - p.X), Math.Abs(pos.Y - p.Y)) > MAXDRAG;
        e.Handled = true;
    }
    private static void V_PreviewMouseUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
    {
        if (control == null) return;
        control.ReleaseMouseCapture();
        if (!drag && GetClickSelects(control)) control.SelectAll();
        e.Handled = true;
        control = null;
    }
    private static void V_LostFocus(object sender, RoutedEventArgs e)
    {
        if (control != null && control != sender) return;
        if (control != null) control.ReleaseMouseCapture();
        control = null;
    }
    private static void V_IsKeyboardFocusedChanged(object sender, DependencyPropertyChangedEventArgs e)
    {
        if (control != null && control != sender) return;
        if ((bool)e.NewValue) return;
        if (control != null) control.ReleaseMouseCapture();
        control = null;
    }
}

这个附加的属性可以很容易地被一个通用的样式设置器全局分配给一个文本框。

【讨论】:

    猜你喜欢
    • 2021-08-27
    • 1970-01-01
    • 2015-07-03
    • 2010-10-12
    • 1970-01-01
    • 2017-02-11
    • 2011-04-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多