@DaisyTian-MSFT, I've translated your xaml
into code, not that complicated BUT it looks weird because of those ...Factory
. The primary problem with my original code was in this inputBox.Resources.Add("x", new Style()
line. Here instead of "x"
I've to have typeof(ScrollViewer)
. Now it shifts the ScrollBar
to the right and below the tick mark:
BUT there're two issues. First, as I keep adding lines in the TextBox
the Thumb
keeps getting smaller BUT I don't see what I'm typing in the TextBox
as it doesn't scroll to the caret position automatically. Second, If I move/scroll the PointerWheel on the ScrollBar
or on the TextBox
it doesn't scroll. The only way to scroll is drag the Thumb
or click on the ScrollButton
. How to fix those issues? The equivalent xaml
of my code is:
<TextBox BorderThickness="1"
BorderBrush="SkyBlue"
Height="70"
TextWrapping="Wrap"
AcceptsReturn="True"
ScrollViewer.VerticalScrollBarVisibility="Auto">
<TextBox.Resources>
<Style TargetType="{x:Type ScrollViewer}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ScrollViewer}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<ScrollContentPresenter />
<ScrollBar Name="PART_VerticalScrollBar"
Grid.Column="1"
Margin="0 20 -20 0"
ViewportSize="{TemplateBinding ViewportHeight}"
Value="{Binding VerticalOffset, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}"
Maximum="{Binding ScrollableHeight, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}"
Visibility="{Binding ComputedVerticalScrollBarVisibility, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}">
</ScrollBar>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</TextBox.Resources>
</TextBox>
I've used Binding
instead of TemplateBinding
to match it exactly with my code behind approach. It doesn't solve those issues even if I use TemplateBinding
in Value, Maximum
and Visibility
instead of Binding
.
You can paste the xaml
in the MainWindow.xaml
to see the behavior or if you're interested in the way I did, without xaml
, here's the ControlTemplate
:
class EditTextScrollbar : ControlTemplate
{
public EditTextScrollbar() {
TargetType = typeof(ScrollViewer);
var grid = new FrameworkElementFactory(typeof(Grid));
var col1 = new FrameworkElementFactory(typeof(ColumnDefinition));
var col2 = new FrameworkElementFactory(typeof(ColumnDefinition));
var vScroll = new FrameworkElementFactory(typeof(ScrollBar)) { Name = "PART_VerticalScrollBar" };
var content = new FrameworkElementFactory(typeof(ScrollContentPresenter));
col2.SetValue(ColumnDefinition.WidthProperty, new GridLength(1, GridUnitType.Auto));
vScroll.SetValue(Grid.ColumnProperty, 1);
vScroll.SetValue(ScrollBar.MarginProperty, new Thickness(0, 20, -26, 0));
vScroll.SetValue(ScrollBar.ViewportSizeProperty, new TemplateBindingExtension(ScrollViewer.ViewportHeightProperty));
vScroll.SetBinding(ScrollBar.ValueProperty, new Binding() {
Path = new PropertyPath(nameof(ScrollViewer.VerticalOffset)),
RelativeSource = new RelativeSource(RelativeSourceMode.TemplatedParent),
Mode = BindingMode.OneWay
});
vScroll.SetBinding(ScrollBar.MaximumProperty, new Binding() {
Path = new PropertyPath(nameof(ScrollViewer.ScrollableHeight)),
RelativeSource = new RelativeSource(RelativeSourceMode.TemplatedParent),
Mode = BindingMode.OneWay
});
vScroll.SetBinding(ScrollBar.VisibilityProperty, new Binding() {
Path = new PropertyPath(nameof(ScrollViewer.ComputedVerticalScrollBarVisibility)),
RelativeSource = new RelativeSource(RelativeSourceMode.TemplatedParent),
Mode = BindingMode.OneWay
});
grid.AppendChild(col1);
grid.AppendChild(col2);
grid.AppendChild(content);
grid.AppendChild(vScroll);
VisualTree = grid;
}
}
and here's how it's set to the inputBox
:
inputBox.VerticalScrollBarVisibility = ScrollBarVisibility.Auto;
inputBox.Resources.Add(typeof(ScrollViewer), new Style() {
TargetType = typeof(ScrollViewer),
Setters = { new Setter(ScrollViewer.TemplateProperty, new EditTextScrollbar()) }
});
----
EDIT
With this: content.SetValue(ScrollContentPresenter.CanContentScrollProperty, true);
in the ControlTemplate
it works as expected.