LoginSignup
4
4

More than 5 years have passed since last update.

Visual Studio | WPF > Behavior > 複数行のTextBox > 最終行に移動する(自動スクロール)実装

Last updated at Posted at 2017-12-08
動作環境
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

MainWindow.xaml.cs
<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>
MainWindow.xaml.cs
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;
        }
    }

}
TextBoxBehavior.cs
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("*");
        }
    }
}

実行例

自動スクロールになった。

qiita.png

デバッグウィンドウに表示される項目は下記である。

  • -: 起動時に表示される
    • イベント登録処理
  • *: TextChangedごとに表示される

補足

Behaviorを使うことで、MVVMにした場合にも動作するようになると考えている。

関連

4
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
4