Reputation: 4366
I have two TextBoxes and a ScrollBar. With the scrollbar I want to scroll both TextBoxes. The maximum value of the scrollbar is the maximum of the maximum values of the two textbox scrollbars.
My problem is that if the text inside a TextBox is not bigger than the textbox itself, the text won't scroll. How can I force the text to be scrollable?
Here is my code:
<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;
}
}
}
Upvotes: 1
Views: 1026
Reputation: 960
Can't you just wrap these two TextBoxes in a 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>
If you cannot wrap the TextBoxes
you can apply a Margin
to them instead of using 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);
}
You should also compute the ScrollBar.Maximum
and the ScrollBar.ViewportSize
each time one of the component is resized:
<ScrollBar Grid.Row="2" SizeChanged="MainWindow_OnLoaded" [...]/>
Upvotes: 1