XAML 当输入的文本到达TextBox的右侧时,自动将文本滚动到TextBox内的左侧,C#、WPF、MVVM

yhqotfr8  于 2023-08-01  发布在  C#
关注(0)|答案(1)|浏览(164)

我正在使用MVVM开发一个WPF应用程序,其中用户需要将文本从TextBlock元素输入到TextBox中。TextBox的占位符被“填充”并直接定位在TextBlock的上方。它有一个透明的背景。当用户输入文本时,他们到达TextBlock的右侧,下一个单词将被隐藏。
我希望TextBox能够自动滚动,以便最后输入的字符在TextBox的左侧可见,从而允许用户查看下一步需要输入的内容。
下面是我使用的XAML代码:

<ScrollViewer
                x:Name="scroll"
                Grid.Row="1"
                HorizontalAlignment="Stretch"
                VerticalAlignment="Stretch"
                CanContentScroll="True"
                HorizontalScrollBarVisibility="Visible"
                VerticalScrollBarVisibility="Disabled">
                <Grid>
                    <Grid.RowDefinitions>
                        <RowDefinition />
                    </Grid.RowDefinitions>

                    <Border
                        Grid.Row="0"
                        HorizontalAlignment="Stretch"
                        VerticalAlignment="Stretch"
                        Background="#8EABAF">
                        <TextBlock
                            x:Name="tblTextToType"
                            Margin="2,0,0,0"
                            VerticalAlignment="Center"
                            AllowDrop="False"
                            FontFamily="/Fonts/Nunito_Sans/#NunitoSans"
                            FontSize="28"
                            Foreground="Gray"
                            TextAlignment="Center" />
                    </Border>

                    <TextBox
                        x:Name="tbTypedText"
                        Grid.Row="0"
                        HorizontalAlignment="Stretch"
                        VerticalAlignment="Stretch"
                        AllowDrop="False"
                        Background="Transparent"
                        FontFamily="/Fonts/Nunito_Sans/#NunitoSans"
                        FontSize="28"
                        Foreground="Black"
                        IsInactiveSelectionHighlightEnabled="True"
                        IsReadOnly="True"
                        IsUndoEnabled="False"
                        MaxLines="1"
                        SelectionBrush="Green">
                    </TextBox>
                </Grid>
            </ScrollViewer>

字符串
另外,我有两个命令绑定到应用程序窗口来处理击键。如果输入的文本与TextBlock的内容匹配,则会以编程方式将其添加到TextBox中。

Type方法执行滚动文本所需的效果,但仅在文本第一次超过TextBox的宽度之后,并且我需要它在每次超过后发生

处理KeyDownCommand和KeyUpCommand命令的C#代码:

public ICommand KeyDownCommand { get; private set; }
        private void ExecuteKeyDown(object? obj)
        {
            if (obj is KeyEventArgs e && _keyboardButtons.ContainsKey(e.Key))
            {
                Key key = (e.Key == Key.System) ? e.SystemKey : e.Key;
                _keyboardButtons[key].KeyGrid.Background = SecondColor;

                switch (key)
                {
                    case Key.LeftCtrl:
                    case Key.RightCtrl:
                    case Key.LWin:
                    case Key.RWin:
                    case Key.LeftAlt:
                    case Key.RightAlt:
                    case Key.Back:
                    case Key.Tab:
                    case Key.Enter:
                        return;

                    case Key.LeftShift:
                    case Key.RightShift:
                    case Key.CapsLock:
                        UpdateKeyboard();
                        return;

                    case Key.Space:
                        Type(' ');
                        return;

                    default:
                        Type(char.Parse(_keyboardButtons[key].Content.Text));
                        break;
                }

                return;
            }
        }
        public ICommand KeyUpCommand { get; private set; }
        private void ExecuteKeyUp(object? obj)
        {
            if (obj is KeyEventArgs e && _keyboardButtons.ContainsKey(e.Key))
            {
                _keyboardButtons[e.Key].KeyGrid.Background = Brushes.Transparent;
                UpdateKeyboard();
            }
        }

private bool isTextWidthExceededViewport = false;
private void Type(char character)
        {
            if (_textBox.Text.Length < _textBlock.Text.Length)
            {
                char expectedCharacter = _textBlock.Text[_textBox.Text.Length];

                if (character == expectedCharacter)
                {
                    _textBox.Text += character;

                    correctlyTypedTextLength++;
                    _progressBar.Value++;

                    _textBox.Foreground = (correctlyTypedTextLength == _textBox.Text.Length)
                        ? new SolidColorBrush(Colors.Black)
                        : new SolidColorBrush(Colors.Red);

                    _textBox.Select(0, correctlyTypedTextLength);

                    var typeface = new Typeface(_textBox.FontFamily, _textBox.FontStyle, _textBox.FontWeight, _textBox.FontStretch);
                    var formattedText = new FormattedText(_textBox.Text, Thread.CurrentThread.CurrentCulture, _textBox.FlowDirection, typeface, _textBox.FontSize, _textBox.Foreground);
                    var size = new Size(formattedText.Width, formattedText.Height);
                    if (size.Width + 20 > _scrollViewer.ViewportWidth && !isTextWidthExceededViewport)
                    {
                        _scrollViewer.ScrollToRightEnd();
                        isTextWidthExceededViewport = true;
                    }
                }
                else
                {
                    Fails++;
                    _textBox.Foreground = Brushes.Red;

                    if (Properties.Settings.Default.ErrorSound)
                        System.Media.SystemSounds.Exclamation.Play();
                }
            }
        }


我也尝试过使用其他命令和自定义TextBox元素来实现自动滚动,但没有成功。
总而言之,我的WPF应用程序需要一个文本框来自动滚动,以便当用户的输入超过文本框的可见宽度时,最后输入的字符在文本框的左侧保持可见。
我将感谢任何关于如何实现这种自动滚动行为的见解或解决方案。谢谢你,谢谢

2q5ifsrm

2q5ifsrm1#

您可以按以下步骤操作;当文本接近结尾时,它将滚动到接近开始

var typeface = new Typeface(_textBox.FontFamily, _textBox.FontStyle, _textBox.FontWeight, _textBox.FontStretch);
var formattedText = new FormattedText(_textBox.Text, Thread.CurrentThread.CurrentCulture, _textBox.FlowDirection, typeface, _textBox.FontSize, _textBox.Foreground);
var size = new Size(formattedText.Width, formattedText.Height);

if (size.Width - scroll.HorizontalOffset >= (scroll.ViewportWidth - 10))
{
    scroll.ScrollToHorizontalOffset(scroll.HorizontalOffset + scroll.ViewportWidth -10);
}

字符串
要滚动到末尾,可以执行scroll.ScrollToRightEnd();
或将键入的文本始终保持在文本框的中心

var typeface = new Typeface(tbTypedText.FontFamily, tbTypedText.FontStyle, tbTypedText.FontWeight, tbTypedText.FontStretch);
var formattedText = new FormattedText(tbTypedText.Text, Thread.CurrentThread.CurrentCulture, tbTypedText.FlowDirection, typeface, tbTypedText.FontSize, tbTypedText.Foreground);
var size = new Size(formattedText.Width, formattedText.Height);
scroll.ScrollToHorizontalOffset(size.Width > 6 ? size.Width -100 : size.Width);


像这样

private void Type(char character)
    {
        if (_textBox.Text.Length < _textBlock.Text.Length)
        {
            char expectedCharacter = _textBlock.Text[_textBox.Text.Length];

            if (character == expectedCharacter)
            {
                _textBox.Text += character;

                correctlyTypedTextLength++;
                _progressBar.Value++;

                _textBox.Foreground = (correctlyTypedTextLength == _textBox.Text.Length)
                    ? new SolidColorBrush(Colors.Black)
                    : new SolidColorBrush(Colors.Red);

                _textBox.Select(0, correctlyTypedTextLength);
                var typeface = new Typeface(_textBox.FontFamily, _textBox.FontStyle, _textBox.FontWeight, _textBox.FontStretch);
                var formattedText = new FormattedText(_textBox.Text, Thread.CurrentThread.CurrentCulture, _textBox.FlowDirection, typeface, _textBox.FontSize, _textBox.Foreground);
                var size = new Size(formattedText.Width, formattedText.Height);

                if (size.Width - scroll.HorizontalOffset >= (scroll.ViewportWidth - 10))
                {
                    scroll.ScrollToHorizontalOffset(scroll.HorizontalOffset + scroll.ViewportWidth -10);
                }
            }
            else
            {
                Fails++;
                _textBox.Foreground = Brushes.Red;

                if (Properties.Settings.Default.ErrorSound)
                    System.Media.SystemSounds.Exclamation.Play();
            }
        }
    }

相关问题