I'm trying to keep the vertical scroll bar at the bottom (the latest entry), but at the moment, the scroll bar just stays in the same place, so as content is being added to the string, the scroll bar moves to the top.
I know that I can use the ServerScroll.ScrollToEnd()
property in my code-behind to move the bar to the end. But is there a way to automatically do this is xaml? (so that I don't have to call this property every time I add to the string).
XAML
<ScrollViewer Name="ServerScroll"
VerticalScrollBarVisibility="Auto">
<TextBlock Name="serverConsole"
Margin="5"
Background="White"
TextWrapping="Wrap"/>
</ScrollViewer>
Code-behind
private void example_Click(object sender, RoutedEventArgs e)
{
ServerConsole += "asdf\r\n"; // binded to TextBlock
ServerScroll.ScrollToEnd();
}
With a TextBox, reacting to TextBox.TextChanged
If you want to scroll to the end everytime the Text
property of your TextBlock
is changed, I would recommend switching to a TextBox
so that you can hookup to its TextChanged
event using System.Windows.Interactivity
:
<Window x:Class="WpfApp1.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"
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
xmlns:ei="clr-namespace:Microsoft.Expression.Interactivity.Core;assembly=Microsoft.Expression.Interactions">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Button Grid.Row="0" Width="50" Height="25" Click="Button_Click"></Button>
<ScrollViewer Grid.Row="1" Name="ServerScroll"
VerticalScrollBarVisibility="Auto">
<TextBox Name="serverConsole"
Margin="5"
Background="White"
TextWrapping="Wrap">
<i:Interaction.Triggers>
<i:EventTrigger EventName="TextChanged">
<ei:CallMethodAction MethodName="ScrollToEnd" TargetObject="{Binding ElementName=ServerScroll}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBox>
</ScrollViewer>
</Grid>
</Window>
With a TextBlock, reacting to Button.Click
If you wish to scroll to the end whenever your Button
is clicked, you can use the same technique to hook-up to its Click
event:
<Window x:Class="WpfApp1.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"
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
xmlns:ei="clr-namespace:Microsoft.Expression.Interactivity.Core;assembly=Microsoft.Expression.Interactions">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Button Grid.Row="0" Width="50" Height="25" Click="Button_Click">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<ei:CallMethodAction MethodName="ScrollToEnd" TargetObject="{Binding ElementName=ServerScroll}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
<ScrollViewer Grid.Row="1" Name="ServerScroll"
VerticalScrollBarVisibility="Auto">
<TextBlock Name="serverConsole"
Margin="5"
Background="White"
TextWrapping="Wrap">
</TextBlock>
</ScrollViewer>
</Grid>
</Window>
With a ListView, reacting to CollectionChanged
It looks like you really want to use an ItemsControl
instead of a TextBlock
though, because you're talking about entries and everything. You could switch to a ListView
and hook-up to its CollectionChanged
event as well:
<Window x:Class="WpfApp1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
xmlns:ei="clr-namespace:Microsoft.Expression.Interactivity.Core;assembly=Microsoft.Expression.Interactions">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Button Grid.Row="0" Width="50" Height="25" Click="Button_Click"/>
<ScrollViewer Grid.Row="1" Name="ServerScroll"
VerticalScrollBarVisibility="Auto">
<ListView x:Name="listView" ItemsSource="{Binding MyList}">
<i:Interaction.Triggers>
<i:EventTrigger SourceObject="{Binding MyList}" EventName="CollectionChanged">
<ei:CallMethodAction MethodName="ScrollToEnd" TargetObject="{Binding ElementName=ServerScroll}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</ListView>
</ScrollViewer>
</Grid>
</Window>
And in your view model:
public ObservableCollection<string> MyList { get; } = new ObservableCollection<string>();