Auto scroll when text changed or selection changed in a TextBox

This commit is contained in:
leo 2020-07-12 22:24:59 +08:00
parent 4cb2568385
commit bd96a9709f
5 changed files with 360 additions and 279 deletions

View file

@ -1,5 +1,6 @@
using System.Windows; using System.Windows;
using System.Windows.Controls; using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media; using System.Windows.Media;
namespace SourceGit.Helpers { namespace SourceGit.Helpers {
@ -9,6 +10,15 @@ namespace SourceGit.Helpers {
/// </summary> /// </summary>
public static class TextBoxHelper { public static class TextBoxHelper {
/// <summary>
/// Auto scroll on text changed.
/// </summary>
public static readonly DependencyProperty AutoScrollProperty = DependencyProperty.RegisterAttached(
"AutoScroll",
typeof(bool),
typeof(TextBoxHelper),
new PropertyMetadata(false, OnAutoScrollChanged));
/// <summary> /// <summary>
/// Placeholder property /// Placeholder property
/// </summary> /// </summary>
@ -36,6 +46,39 @@ namespace SourceGit.Helpers {
typeof(TextBoxHelper), typeof(TextBoxHelper),
new PropertyMetadata(Brushes.Transparent)); new PropertyMetadata(Brushes.Transparent));
/// <summary>
/// Setter for AutoScrollProperty
/// </summary>
/// <param name="element"></param>
/// <param name="enabled"></param>
public static void SetAutoScroll(UIElement element, bool enabled) {
element.SetValue(AutoScrollProperty, enabled);
}
/// <summary>
/// Getter for AutoScrollProperty
/// </summary>
/// <param name="element"></param>
/// <returns></returns>
public static bool GetAutoScroll(UIElement element) {
return (bool)element.GetValue(AutoScrollProperty);
}
/// <summary>
/// Triggered when AutoScroll property changed.
/// </summary>
/// <param name="d"></param>
/// <param name="e"></param>
public static void OnAutoScrollChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) {
var textBox = d as TextBox;
if (textBox == null) return;
textBox.SelectionChanged -= UpdateScrollOnSelectionChanged;
if ((bool)e.NewValue == true) {
textBox.SelectionChanged += UpdateScrollOnSelectionChanged;
}
}
/// <summary> /// <summary>
/// Triggered when placeholder changed. /// Triggered when placeholder changed.
/// </summary> /// </summary>
@ -122,8 +165,8 @@ namespace SourceGit.Helpers {
textBox.SetValue(PlaceholderBrushProperty, brush); textBox.SetValue(PlaceholderBrushProperty, brush);
textBox.Background = brush; textBox.Background = brush;
textBox.TextChanged += OnTextChanged; textBox.TextChanged += UpdatePlaceholder;
OnTextChanged(textBox, null); UpdatePlaceholder(textBox, null);
} }
/// <summary> /// <summary>
@ -131,7 +174,7 @@ namespace SourceGit.Helpers {
/// </summary> /// </summary>
/// <param name="sender"></param> /// <param name="sender"></param>
/// <param name="e"></param> /// <param name="e"></param>
private static void OnTextChanged(object sender, RoutedEventArgs e) { private static void UpdatePlaceholder(object sender, RoutedEventArgs e) {
var textBox = sender as TextBox; var textBox = sender as TextBox;
if (string.IsNullOrEmpty(textBox.Text)) { if (string.IsNullOrEmpty(textBox.Text)) {
textBox.Background = textBox.GetValue(PlaceholderBrushProperty) as Brush; textBox.Background = textBox.GetValue(PlaceholderBrushProperty) as Brush;
@ -139,5 +182,44 @@ namespace SourceGit.Helpers {
textBox.Background = Brushes.Transparent; textBox.Background = Brushes.Transparent;
} }
} }
/// <summary>
///
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private static void UpdateScrollOnSelectionChanged(object sender, RoutedEventArgs e) {
var textBox = sender as TextBox;
if (textBox != null && textBox.IsFocused) {
if (Mouse.LeftButton == MouseButtonState.Pressed && textBox.SelectionLength > 0) {
var p = Mouse.GetPosition(textBox);
if (p.X <= 8) {
textBox.LineLeft();
} else if (p.X >= textBox.ActualWidth - 8) {
textBox.LineRight();
}
if (p.Y <= 8) {
textBox.LineUp();
} else if (p.Y >= textBox.ActualHeight - 8) {
textBox.LineDown();
}
} else {
var rect = textBox.GetRectFromCharacterIndex(textBox.CaretIndex);
if (rect.Left <= 0) {
textBox.ScrollToHorizontalOffset(textBox.HorizontalOffset + rect.Left);
} else if (rect.Right >= textBox.ActualWidth) {
textBox.ScrollToHorizontalOffset(textBox.HorizontalOffset + rect.Right);
}
if (rect.Top <= 0) {
textBox.ScrollToVerticalOffset(textBox.VerticalOffset + rect.Top);
} else if (rect.Bottom >= textBox.ActualHeight) {
textBox.ScrollToVerticalOffset(textBox.VerticalOffset + rect.Bottom);
}
}
}
}
} }
} }

View file

@ -1,5 +1,7 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:helpers="clr-namespace:SourceGit.Helpers">
<!-- 错误Tooltip --> <!-- 错误Tooltip -->
<ControlTemplate x:Key="Template.Validation.Tooltip" TargetType="{x:Type ToolTip}"> <ControlTemplate x:Key="Template.Validation.Tooltip" TargetType="{x:Type ToolTip}">
<Border x:Name="Root" Margin="5,0,0,0" Opacity="0" Padding="0,0,20,20" RenderTransformOrigin="0,0"> <Border x:Name="Root" Margin="5,0,0,0" Opacity="0" Padding="0,0,20,20" RenderTransformOrigin="0,0">
@ -81,6 +83,7 @@
<Setter Property="Background" Value="Transparent"/> <Setter Property="Background" Value="Transparent"/>
<Setter Property="BorderBrush" Value="{DynamicResource Brush.Border1}"/> <Setter Property="BorderBrush" Value="{DynamicResource Brush.Border1}"/>
<Setter Property="Validation.ErrorTemplate" Value="{StaticResource Template.Validation.Error}"/> <Setter Property="Validation.ErrorTemplate" Value="{StaticResource Template.Validation.Error}"/>
<Setter Property="helpers:TextBoxHelper.AutoScroll" Value="True"/>
<Setter Property="Template"> <Setter Property="Template">
<Setter.Value> <Setter.Value>
@ -93,9 +96,10 @@
<ScrollViewer x:Name="PART_ContentHost" <ScrollViewer x:Name="PART_ContentHost"
Margin="{TemplateBinding Padding}" Margin="{TemplateBinding Padding}"
VerticalAlignment="Center" VerticalAlignment="Center"
Background="{x:Null}" Background="Transparent"
BorderThickness="0" BorderThickness="0"
IsTabStop="False" IsTabStop="False"
CanContentScroll="False"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/> SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
</Border> </Border>

View file

@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop"> <Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net461</TargetFramework> <TargetFramework>net46</TargetFramework>
<OutputType>WinExe</OutputType> <OutputType>WinExe</OutputType>
<UseWPF>true</UseWPF> <UseWPF>true</UseWPF>
<UseWindowsForms>true</UseWindowsForms> <UseWindowsForms>true</UseWindowsForms>

View file

@ -343,8 +343,7 @@
ScrollViewer.HorizontalScrollBarVisibility="Disabled" ScrollViewer.HorizontalScrollBarVisibility="Disabled"
ScrollViewer.VerticalScrollBarVisibility="Auto" ScrollViewer.VerticalScrollBarVisibility="Auto"
helpers:TextBoxHelper.Placeholder="Enter commit message" helpers:TextBoxHelper.Placeholder="Enter commit message"
helpers:TextBoxHelper.PlaceholderBaseline="Top" helpers:TextBoxHelper.PlaceholderBaseline="Top">
TextChanged="CommitMessageChanged">
<TextBox.Text> <TextBox.Text>
<Binding ElementName="me" Path="CommitMessage" Mode="TwoWay" UpdateSourceTrigger="PropertyChanged"> <Binding ElementName="me" Path="CommitMessage" Mode="TwoWay" UpdateSourceTrigger="PropertyChanged">
<Binding.ValidationRules> <Binding.ValidationRules>

View file

@ -729,10 +729,6 @@ namespace SourceGit.UI {
e.Handled = true; e.Handled = true;
} }
private void CommitMessageChanged(object sender, TextChangedEventArgs e) {
(sender as TextBox).ScrollToEnd();
}
private void StartAmend(object sender, RoutedEventArgs e) { private void StartAmend(object sender, RoutedEventArgs e) {
var commits = Repo.Commits("-n 1"); var commits = Repo.Commits("-n 1");
if (commits.Count == 0) { if (commits.Count == 0) {