【WPF】編集可能なTextBlockを作成：EditableTextBlock

## 概要
編集可能なTextBlockを作成する。
TextBlockを直接編集可能にするわけではなく、通常時はTextBlockでダブルクリックをするとTextBoxになるコントロールを作成します。
編集中にEnterを入力すると編集が完了し、TextBlockに戻ります。Escapeを入力すると元のテキストに戻ります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3562156/9105783e-830b-7355-f044-a4a56cd4b090.png)

## プロジェクトの作成
下記画像のように、プロジェクトを作成し、プロジェクト配下に`EditableTextBlock.cs`を追加しました。
<dt>プロジェクトテンプレート</dt>
    <dd>WPF アプリケーション</dd>
<dt>プロジェクト名</dt>
<dd>EditableTextBlockProject<dd>

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3562156/04245676-5232-7e3a-5860-5c33d86069ae.png)

## EditablTextBlock.cs
ContentControlを継承したクラスを作成し、Grid、TextBlock、TextBoxを配置したシンプルなコントロールです。
```C#:EditableTextBlock.cs
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Input;

namespace EditableTextBlockProject;

public class EditableTextBlock : ContentControl
{
    private readonly Grid grid = new();
    private readonly TextBox textBox = new();
    private readonly TextBlock textBlock = new();
    private string previewText = string.Empty;
    private bool isEditMode = false;

    public string Text
    {
        get { return (string)GetValue(TextProperty); }
        set { SetValue(TextProperty, value); }
    }

    public static readonly DependencyProperty TextProperty = DependencyProperty.Register(
            nameof(Text),
            typeof(string),
            typeof(EditableTextBlock),
            new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));

            
    public EditableTextBlock()
    {
        InitializeControl();

        MouseDoubleClick += EditableTextBlock_MouseDoubleClick;
        textBox.KeyDown += TextBox_KeyDown;
        textBox.LostFocus += TextBox_LostFocus;
    }

    
    private void InitializeControl()
    {
        textBox.Padding = new Thickness(1.0);
        textBox.Visibility = Visibility.Hidden;
        textBox.VerticalAlignment = VerticalAlignment.Center;
        textBox.VerticalContentAlignment = VerticalAlignment.Center;

        textBlock.Visibility = Visibility.Visible;
        textBlock.VerticalAlignment = VerticalAlignment.Center;

        grid.Children.Add(textBlock);
        grid.Children.Add(textBox);
        Content = grid;
        Focusable = false;
        grid.Focusable = false;
        textBlock.Focusable = false;
        MinWidth = 10;

        Binding binding = new(nameof(Text))
        {
            Source = this,
            UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged,
        };
        textBox.SetBinding(TextBox.TextProperty, binding);
        textBlock.SetBinding(TextBlock.TextProperty, binding);
    }

    private void EditableTextBlock_MouseDoubleClick(object sender, MouseEventArgs e)
    {
        if (!isEditMode)
        {
            previewText = textBlock.Text;
            isEditMode = true;
            OnIsEditModeChanged(isEditMode);
            textBox.Focus();
            textBox.SelectAll();
            e.Handled = true;
        }
    }

    private void TextBox_KeyDown(object sender, KeyEventArgs e)
    {
        if (e.Key == Key.Enter)
        {
            isEditMode = false;
            OnIsEditModeChanged(isEditMode);
            e.Handled = true;
        }
        else if (e.Key == Key.Escape)
        {
            textBox.Text = previewText;
            isEditMode = false;
            OnIsEditModeChanged(isEditMode);
            e.Handled = true;
        }
    }

    private void TextBox_LostFocus(object sender, RoutedEventArgs e)
    {
        isEditMode = false;
        OnIsEditModeChanged(isEditMode);
        e.Handled = true;
    }

    private void OnIsEditModeChanged(bool value)
    {
        textBlock.Visibility = value ? Visibility.Hidden : Visibility.Visible;
        textBox.Visibility = value ? Visibility.Visible : Visibility.Hidden;
    }
}

```
## MainWindow
利用側のコード
```xml:MainWindow.xaml
<Window
    x:Class="EditableTextBlockProject.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:EditableTextBlockProject"
    mc:Ignorable="d"
    Title="MainWindow" Height="450" Width="800">
    <StackPanel>
        <local:EditableTextBlock Text="Sample Text" Margin="10"/>
    </StackPanel>
</Window>

```

## まとめ
編集可能なテキストブロックを作成しました。
趣味でプログラミングをしている初心者が作成したコードのため、問題があればご指摘いただけると助かります。
自由に改変したり、公開してもOKですが、本コードを利用して発生した問題について責任を追うことができませんのでご注意ください。