0

我正在制作一个文本框以在添加文本时自动滚动到末尾。但是,当鼠标悬停在文本框上时,我希望选择不滚动文本框。我已经完成了所有这些,但是当用户选择文本并且文本框接收到更新文本的事件时,一切都变得混乱了。

这是我正在使用的:


<TextBox Text="{Binding ConsoleContents, Mode=OneWay}" TextWrapping="Wrap" 
    IsReadOnly="True" ScrollViewer.VerticalScrollBarVisibility="Visible" 
    TextChanged="TextBox_TextChanged" MouseEnter="TextBox_MouseEnterLeave"
    MouseLeave="TextBox_MouseEnterLeave" AllowDrop="False" Focusable="True" 
    IsUndoEnabled="False"></TextBox>

private void TextBox_TextChanged(object sender, TextChangedEventArgs e)
    {
        TextBox textBox = sender as TextBox;
        if (textBox == null) return;

        // ensure we can scroll
        if (_canScroll)
        {
            textBox.Select(textBox.Text.Length, 0); //This was an attempt to fix the issue
            textBox.ScrollToEnd();
        }
    }

private void TextBox_MouseEnterLeave(object sender, MouseEventArgs e)
    {
        TextBox textBox = sender as TextBox;

        // Don't scroll if the mouse is in the box
        if (e.RoutedEvent.Name == "MouseEnter")
        {
            _canScroll = false;
        }
        else if (e.RoutedEvent.Name == "MouseLeave") 
        {
            _canScroll = true;
        }
    }

为了进一步解释 haywire 的含义,当文本框接收到 propertychanged 事件时,它会设置文本并在鼠标未悬停在其上时向下滚动到末尾。如果鼠标悬停在它上面不会滚动。但是,如果我选择文本并且文本框接收到 propertychanged 事件,则内容会更新,但该框不会向下滚动。这是意料之中的。问题是我的选择然后从光标当前所在的位置转到文本的顶部。如果我从框中删除光标,它会继续正常,但是一旦光标返回,框就会卡在顶部并且无法向下滚动。我认为它可能是光标,所以我尝试将它移到最后,但这没有解决任何问题。

有任何想法吗?!

我一直在扯头发!谢谢!

4

2 回答 2

0

您将需要处理额外的 PropertyChanged 事件。因为文本已更改,所以控件已更新。因为它更新它会重置某些值,例如光标位置和选定的文本等。

您可以尝试暂时保存这些设置CaretIndex,例如SelectionStartSelectionLength。虽然我没有这方面的经验,所以你必须自己找出你想要保持什么样的价值观。

_canScroll当为 TextBox 触发 PropertyChanged 事件时,您也可以应用相同的检查。这使您可以处理文本。但如果鼠标离开文本框,您必须等待新事件才能显示最新文本。

您可能还想研究使用IsFocused属性。在我看来,它提供了比 MouseEnter 和 MouseLeave 事件更好的解决方案。但这当然取决于你。

于 2012-10-23T19:10:12.713 回答
0

好吧,它花了整个上午,但这里是如何做到的:

<TextBox Text="{Binding ConsoleContents, Mode=OneWay}" 
         TextWrapping="Wrap" IsReadOnly="True" ScrollViewer.VerticalScrollBarVisibility="Visible" TextChanged="TextBox_TextChanged" 
         MouseEnter="TextBox_MouseEnterLeave" MouseLeave="TextBox_MouseEnterLeave" SelectionChanged="TextBox_SelectionChanged" AllowDrop="False" Focusable="True" 
         IsUndoEnabled="False"></TextBox>

public partial class ConsoleView : UserControl
{
    private bool _canScroll;

    // saves
    private int _selectionStart;
    private int _selectionLength;
    private string _selectedText;

    public ConsoleView(ConsoleViewModel vm)
    {
        InitializeComponent();
        this.DataContext = vm;

        _canScroll = true;
    }


    private void TextBox_TextChanged(object sender, TextChangedEventArgs e)
    {
        TextBox textBox = sender as TextBox;
        if (textBox == null) return;

        // ensure we can scroll
        if (_canScroll)
        {
            // set the cursor to the end and scroll down
            textBox.Select(textBox.Text.Length, 0);
            textBox.ScrollToEnd();

            // save these so the box doesn't jump around if the user goes back in
            _selectionLength = textBox.SelectionLength;
            _selectionStart = textBox.SelectionStart;
        }
        else if (!_canScroll)
        {

            // move the cursor to where the mouse is if we're not selecting anything (for if we are selecting something the cursor has already moved to where it needs to be)
            if (string.IsNullOrEmpty(_selectedText))
            //if (textBox.SelectionLength > 0)
            {
                textBox.CaretIndex = textBox.GetCharacterIndexFromPoint(Mouse.GetPosition(textBox), true);
            }
            else
            {
                textBox.Select(_selectionStart, _selectionLength); // restore what was saved
            }

        }
    }


    private void TextBox_MouseEnterLeave(object sender, MouseEventArgs e)
    {
        TextBox textBox = sender as TextBox;
        if (textBox == null) return;

        // Don't scroll if the mouse is in the box
        if (e.RoutedEvent.Name == "MouseEnter")
        {
            _canScroll = false;
        }
        else if (e.RoutedEvent.Name == "MouseLeave")
        {
            _canScroll = true;
        }

    }


    private void TextBox_SelectionChanged(object sender, RoutedEventArgs e)
    {
        TextBox textBox = sender as TextBox;
        if (textBox == null) return;

        // save all of the things
        _selectionLength = textBox.SelectionLength;
        _selectionStart = textBox.SelectionStart;
        _selectedText = textBox.SelectedText; // save the selected text because it gets destroyed on text update before the TexChanged event.

    }

}
于 2012-10-24T16:08:55.170 回答