多行文本框:在状态栏中显示当前行/字符索引

发布于 2024-11-27 10:14:45 字数 135 浏览 0 评论 0原文

我有一个多行文本框,用户可以在其中编辑文本。 在状态栏中,我想显示当前行/字符索引。 我知道我可以获取 CaretIndex,并使用 GetLineIndexFromCharacterIndex 获取行索引。

但我该如何将其绑定到状态栏呢?

I have a multiline textbox where the user can edit text.
In a statusbar I'd like to show the current line / character index.
I know I can get the CaretIndex, and use GetLineIndexFromCharacterIndex to get the line-index.

But how would I go about binding that into the statusbar ?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

白芷 2024-12-04 10:14:45

我会为此使用附加行为。该行为可以使用 SelectionChanged 侦听更改,并相应地更新两个附加属性 CaretIndexLineIndex

<TextBox Name="textBox"
         AcceptsReturn="True"
         local:CaretBehavior.ObserveCaret="True"/>

<TextBlock Text="{Binding ElementName=textBox,
                          Path=(local:CaretBehavior.LineIndex)}"/>
<TextBlock Text="{Binding ElementName=textBox,
                          Path=(local:CaretBehavior.CaretIndex)}"/>

插入符行为

public static class CaretBehavior 
{
    public static readonly DependencyProperty ObserveCaretProperty = 
        DependencyProperty.RegisterAttached 
        (
            "ObserveCaret",
            typeof(bool),
            typeof(CaretBehavior),
            new UIPropertyMetadata(false, OnObserveCaretPropertyChanged) 
        );
    public static bool GetObserveCaret(DependencyObject obj) 
    {
        return (bool)obj.GetValue(ObserveCaretProperty); 
    }
    public static void SetObserveCaret(DependencyObject obj, bool value) 
    {
        obj.SetValue(ObserveCaretProperty, value); 
    }
    private static void OnObserveCaretPropertyChanged(DependencyObject dpo, 
                                                   DependencyPropertyChangedEventArgs e) 
    {
        TextBox textBox = dpo as TextBox;
        if (textBox != null) 
        { 
            if ((bool)e.NewValue == true) 
            {
                textBox.SelectionChanged += textBox_SelectionChanged;
            } 
            else 
            {
                textBox.SelectionChanged -= textBox_SelectionChanged; 
            } 
        } 
    }

    static void textBox_SelectionChanged(object sender, RoutedEventArgs e)
    {
        TextBox textBox = sender as TextBox;
        int caretIndex = textBox.CaretIndex;
        SetCaretIndex(textBox, caretIndex);
        SetLineIndex(textBox, textBox.GetLineIndexFromCharacterIndex(caretIndex));
    }

    private static readonly DependencyProperty CaretIndexProperty =
        DependencyProperty.RegisterAttached("CaretIndex", typeof(int), typeof(CaretBehavior));
    public static void SetCaretIndex(DependencyObject element, int value)
    {
        element.SetValue(CaretIndexProperty, value);
    }
    public static int GetCaretIndex(DependencyObject element)
    {
        return (int)element.GetValue(CaretIndexProperty);
    }

    private static readonly DependencyProperty LineIndexProperty =
        DependencyProperty.RegisterAttached("LineIndex", typeof(int), typeof(CaretBehavior));
    public static void SetLineIndex(DependencyObject element, int value)
    {
        element.SetValue(LineIndexProperty, value);
    }
    public static int GetLineIndex(DependencyObject element)
    {
        return (int)element.GetValue(LineIndexProperty);
    }
}

I'd use an attached behavior for that. The behavior can listens to changes with SelectionChanged and update two attached properties CaretIndex and LineIndex accordingly.

<TextBox Name="textBox"
         AcceptsReturn="True"
         local:CaretBehavior.ObserveCaret="True"/>

<TextBlock Text="{Binding ElementName=textBox,
                          Path=(local:CaretBehavior.LineIndex)}"/>
<TextBlock Text="{Binding ElementName=textBox,
                          Path=(local:CaretBehavior.CaretIndex)}"/>

CaretBehavior

public static class CaretBehavior 
{
    public static readonly DependencyProperty ObserveCaretProperty = 
        DependencyProperty.RegisterAttached 
        (
            "ObserveCaret",
            typeof(bool),
            typeof(CaretBehavior),
            new UIPropertyMetadata(false, OnObserveCaretPropertyChanged) 
        );
    public static bool GetObserveCaret(DependencyObject obj) 
    {
        return (bool)obj.GetValue(ObserveCaretProperty); 
    }
    public static void SetObserveCaret(DependencyObject obj, bool value) 
    {
        obj.SetValue(ObserveCaretProperty, value); 
    }
    private static void OnObserveCaretPropertyChanged(DependencyObject dpo, 
                                                   DependencyPropertyChangedEventArgs e) 
    {
        TextBox textBox = dpo as TextBox;
        if (textBox != null) 
        { 
            if ((bool)e.NewValue == true) 
            {
                textBox.SelectionChanged += textBox_SelectionChanged;
            } 
            else 
            {
                textBox.SelectionChanged -= textBox_SelectionChanged; 
            } 
        } 
    }

    static void textBox_SelectionChanged(object sender, RoutedEventArgs e)
    {
        TextBox textBox = sender as TextBox;
        int caretIndex = textBox.CaretIndex;
        SetCaretIndex(textBox, caretIndex);
        SetLineIndex(textBox, textBox.GetLineIndexFromCharacterIndex(caretIndex));
    }

    private static readonly DependencyProperty CaretIndexProperty =
        DependencyProperty.RegisterAttached("CaretIndex", typeof(int), typeof(CaretBehavior));
    public static void SetCaretIndex(DependencyObject element, int value)
    {
        element.SetValue(CaretIndexProperty, value);
    }
    public static int GetCaretIndex(DependencyObject element)
    {
        return (int)element.GetValue(CaretIndexProperty);
    }

    private static readonly DependencyProperty LineIndexProperty =
        DependencyProperty.RegisterAttached("LineIndex", typeof(int), typeof(CaretBehavior));
    public static void SetLineIndex(DependencyObject element, int value)
    {
        element.SetValue(LineIndexProperty, value);
    }
    public static int GetLineIndex(DependencyObject element)
    {
        return (int)element.GetValue(LineIndexProperty);
    }
}
神也荒唐 2024-12-04 10:14:45
RichTextBox rtb = new RichTextBox();
int offset = 0;
rtb.CaretPosition.GetOffsetToPosition(rtb.Document.ContentStart);
rtb.CaretPosition.GetPositionAtOffset(offset).GetCharacterRect(LogicalDirection.Forward);
RichTextBox rtb = new RichTextBox();
int offset = 0;
rtb.CaretPosition.GetOffsetToPosition(rtb.Document.ContentStart);
rtb.CaretPosition.GetPositionAtOffset(offset).GetCharacterRect(LogicalDirection.Forward);
余厌 2024-12-04 10:14:45

恕我直言,最简单可靠的方法是使用 DispatcherTimer 对 CarteIndex 和 GetLineIndexFromCharacterIndex 成员进行采样。然后公开状态栏绑定的几个 DP 上的值。

IMHO, the simplest and reliable way is to sample both the CarteIndex and the GetLineIndexFromCharacterIndex members using a DispatcherTimer. Then exposing the values on a couple of DP for the status bar bindings.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文