在两个文本框上同步滚动

时间:2018-07-11 13:48:02

标签: c# wpf

我有两个TextBoxes和一个ScrollBar。使用滚动条,我要滚动两个文本框。滚动条的最大值是两个文本框滚动条的最大值中的最大值。

我的问题是,如果文本框内的文本不大于文本框本身,则文本不会滚动。如何强制文本可滚动?

这是我的代码:

<Window x:Class="HorizontalScrollViewerTest.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    Title="MainWindow" Height="450" Width="800"
    Loaded="MainWindow_OnLoaded">
<Grid>
    <Grid.RowDefinitions>
        <RowDefinition/>
        <RowDefinition/>
        <RowDefinition Height="Auto"/>
    </Grid.RowDefinitions>

    <TextBox Grid.Row="0"
             x:Name="UpperTextBox"
             Text="abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"
             HorizontalScrollBarVisibility="Hidden"/>
    <TextBox Grid.Row="1"
             x:Name="LowerTextBox"
             Text="abc"
             HorizontalScrollBarVisibility="Hidden"/>
    <ScrollBar Grid.Row="2"
               x:Name="ScrollBar"
               Orientation="Horizontal"
               Value="{Binding ScrollValue, RelativeSource={RelativeSource AncestorType=Window}}"/>
</Grid>

using System;
using System.Windows;

namespace HorizontalScrollViewerTest
{
    public partial class MainWindow
    {
        public static readonly DependencyProperty ScrollValueProperty = DependencyProperty.Register(
        "ScrollValue", typeof(int), typeof(MainWindow), new PropertyMetadata(default(int), ScrollValueChanged));

        private static void ScrollValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            (d as MainWindow).UpperTextBox.ScrollToHorizontalOffset((int)e.NewValue);
            (d as MainWindow).LowerTextBox.ScrollToHorizontalOffset((int)e.NewValue);
        }

        public int ScrollValue
        {
            get => (int) GetValue(ScrollValueProperty);
            set => SetValue(ScrollValueProperty, value);
        }
        public MainWindow()
        {
            InitializeComponent();
        }

        private void MainWindow_OnLoaded(object sender, RoutedEventArgs e)
        {
            var maxExtent = Math.Max(UpperTextBox.ExtentWidth, LowerTextBox.ExtentWidth);
            ScrollBar.Maximum = Math.Max(ScrollBar.ActualWidth, maxExtent) - ScrollBar.ActualWidth;
            ScrollBar.ViewportSize = ScrollBar.ActualWidth;
        }
    }
}

1 个答案:

答案 0 :(得分:1)

您不能只将这两个TextBox包装在ScrollViewer中吗?

<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition/>
        <ColumnDefinition/>
    </Grid.ColumnDefinitions>
    <ScrollViewer CanContentScroll="true" HorizontalScrollBarVisibility="Visible" VerticalScrollBarVisibility="Hidden" Grid.Column="1">
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition/>
                <RowDefinition/>
            </Grid.RowDefinitions>
            <TextBox Grid.Row="0"
     x:Name="UpperTextBox"
     Text="abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"/>
            <TextBox Grid.Row="1"
     x:Name="LowerTextBox"
     Text="abc"/>
        </Grid>
    </ScrollViewer>
</Grid>

如果无法包装TextBoxes,则可以对它们应用Margin而不是使用ScrollToHorizontalOffset

    private static void ScrollValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        (d as MainWindow).UpperTextBox.Margin = new Thickness(-1 * (int)e.NewValue, 0, 0, 0);
        (d as MainWindow).LowerTextBox.Margin = new Thickness(-1 * (int)e.NewValue, 0, 0, 0);
        //(d as MainWindow).UpperTextBox.ScrollToHorizontalOffset((int)e.NewValue * 100);
        //(d as MainWindow).LowerTextBox.ScrollToHorizontalOffset((int)e.NewValue * 100);
    }

您还应该在每次调整一个组件的大小时计算ScrollBar.MaximumScrollBar.ViewportSize

<ScrollBar Grid.Row="2" SizeChanged="MainWindow_OnLoaded" [...]/>