Windows 8.1 Pro (64bit)
Microsoft Visual Studio 2017 Community
Sublime Text 2
実装内容
ロギングなどで複数行のTextBoxの表示をする場合、1行追加のたびに最終行が表示されることが望ましい場合がある。
C++ Builder | TMemo > 最終行に移動する実装
WPFではどう実装するか調べた。
https://stackoverflow.com/questions/7010462/how-to-make-wpf-textbox-with-a-scrollbar-automatically-scroll-to-the-bottom-when/7010608
answered Aug 10 '11 at 12:14
bitbonk
You could write an attached property or even better a behavior that listens to the TextChanged event and scrolls to the bottom in the callback.
Behavior を使ってみる。
参考
添付ビヘイビアを使い TextBox で数値以外を入力できなくする。 by hilaponさん
にBehaviorの使用例があり、これを元に自動スクロールにしてみる。
code
<Window x:Class="_171207_t1930_behavior.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:local="clr-namespace:_171207_t1930_behavior"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid>
<StackPanel>
<Button Name="B_add" Content="Add" Height="30" Click="B_add_Click"/>
<TextBox Name="T_memo" Height="250" Width="500"
VerticalScrollBarVisibility="Visible"
local:TextBoxBehaviors.AutoScrollToEnd="True"/>
</StackPanel>
</Grid>
</Window>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace _171207_t1930_behavior
{
/// <summary>
/// MainWindow.xaml の相互作用ロジック
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void B_add_Click(object sender, RoutedEventArgs e)
{
T_memo.Text += "HELLO" + System.Environment.NewLine;
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
// 以下を追加した
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
namespace _171207_t1930_behavior
{
/// <summary>
/// TextBox 添付ビヘイビア
/// </summary>
public class TextBoxBehaviors
{
/// <summary>
/// 複数行のテキストを扱う
/// テキスト追加時に最終行が表示されるようにする
/// </summary>
public static readonly DependencyProperty AutoScrollToEndProperty =
DependencyProperty.RegisterAttached(
"AutoScrollToEnd", typeof(bool),
typeof(TextBoxBehaviors),
new UIPropertyMetadata(false, IsTextChanged)
);
[AttachedPropertyBrowsableForType(typeof(TextBox))]
public static bool GetAutoScrollToEnd(DependencyObject obj)
{
return (bool)obj.GetValue(AutoScrollToEndProperty);
}
public static void SetAutoScrollToEnd(DependencyObject obj, bool value)
{
obj.SetValue(AutoScrollToEndProperty, value);
}
private static void IsTextChanged
(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
var textBox = sender as TextBox;
if (textBox == null) return;
// イベントを登録・削除
textBox.TextChanged -= OnTextChanged;
Console.Write("-");
var newValue = (bool)e.NewValue;
if (newValue)
{
textBox.TextChanged += OnTextChanged;
}
}
private static void OnTextChanged(object sender, TextChangedEventArgs e)
{
var textBox = sender as TextBox;
if (textBox == null) return;
if (string.IsNullOrEmpty(textBox.Text))
{
return;
}
textBox.ScrollToEnd();
Console.Write("*");
}
}
}
実行例
自動スクロールになった。
デバッグウィンドウに表示される項目は下記である。
-
-
: 起動時に表示される- イベント登録処理
-
*
: TextChangedごとに表示される
補足
Behaviorを使うことで、MVVMにした場合にも動作するようになると考えている。