🎉

WPFでアプリ作成(1)

2024/06/03に公開

TextBox

WPFアプリの作成を今更ながら学んでいます。まずは簡単なところから。
入力コントロールの使い方についてまとめます。

環境

Windows 11 Pro(x64)
VisualStudio Pro 2022

プロジェクトの作成

新しいプロジェクトの作成にて「WPFアプリケーション」を選択
.NET8.0を選択
プロジェクト作成後に、Nugetパッケージマネージャにて、
CommunityToolkitをインストール

実装

xamlファイルでTextBoxコントロールの追加

見た目は、TextBoxだけを追加

MainWindow.xaml

 <Window x:Class="WpfSample01.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:WpfSample01"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
+    <Window.DataContext>
+        <local:ViewModel/>
+    </Window.DataContext>
+    <StackPanel>
+    <TextBox Text="{Binding Age,UpdateSourceTrigger=PropertyChanged}"/>
+    </StackPanel>
 </Window>

クラスの追加

ソリューションエクスプローラにて、プロジェクト名を右クリックで、「追加」「新しい項目」
名前は「ViewModel.cs」とした。

ViewModel.cs

using CommunityToolkit.Mvvm;
using CommunityToolkit.Mvvm.ComponentModel;

namespace WpfSample01
{
    [INotifyPropertyChanged]
    partial class ViewModel
    {
        [ObservableProperty]
        private int age;
    }
}

入力値のチェック

エラー表示のカスタマイズ

ViewModelのageプロパティをint型としているので、空白や文字列を入れるとint型に変換できずに困った事になる。この場合にはプロパティへの代入は行われなし、勝手に入力欄の枠が赤くなって警告感を出してくれる。

赤枠がちゃんと四方に表示されるように、TextBoxのプロパティをちょっと修正しました。

     <TextBox
+       Width="100"
+       Margin="0,5,5,5"
+       HorizontalAlignment="Center"
        Text="{Binding Age,UpdateSourceTrigger=PropertyChanged}"/>

MainWindow.xamlファイルのTextBoxに「UpdateSourceTrigger=PropertyChanged」を書いたのは、これによって1文字ずつ更新イベントが発生して、赤枠の警告が分かり易かったからです。この記述が無い場合には、フォーカスが無くなった時点で、更新イベントが発生して赤枠警告が表示されます。
UpdateSourceTriggerについては下記を参照ください。
https://learn.microsoft.com/ja-jp/dotnet/desktop/wpf/data/how-to-control-when-the-textbox-text-updates-the-source?view=netframeworkdesktop-4.8

入力値のエラー文言を出したい場合には、Xamlファイルにて任意のTemplateを作成して、デフォルトのものと入れ替えて、文字を表示させる。
TemplateはWindow.Resourceに定義

<Window.Resources>
    <ControlTemplate x:Key="ValidationErrorTemplate">
        <StackPanel>
            <Border Width="100" BorderBrush="Red" BorderThickness="1">
                <AdornedElementPlaceholder />
            </Border>
            <ItemsControl DisplayMemberPath="ErrorContent" ItemsSource="{Binding}" />
        </StackPanel>
    </ControlTemplate>
</Window.Resources>

TextBox側で上記のTemplateを設定する

 <TextBox
    Width="100"
    Margin="0,5,5,5"
    HorizontalAlignment="Center"
    Text="{Binding Age, UpdateSourceTrigger=PropertyChanged}"
+   Validation.ErrorTemplate="{StaticResource ValidationErrorTemplate}" />
        

「AdornedElementPlaceholder」の場所に、TextBoxが表示されます。Templateを入れ替えるので、デフォルトで実装されていた赤枠の処理も自前で実装が必要なので、Borderにて赤枠を作成します。その下にエラー文言を表示するためのItemControlを追加してTemplateとしています。

エラー文言は出るけど、文字入力を入れても更新されません。これはエラーとなった時点で、それ以降は正常値が入るまでプロパティの値が更新がされない為です。

独自のエラールールの作成

数値の入力範囲チェックなど、独自のエラーを作成したい場合には、ValidationRuleを作成する必要があります。

public class intValidationRule : ValidationRule
{
    public override ValidationResult Validate(object value, CultureInfo cultureInfo)
    {
       if (value == null) return new ValidationResult(false, "null値となっています");
        if (!int.TryParse(value.ToString(), out int n)) return new ValidationResult(false, "数値ではありません");

        return ValidationResult.ValidResult;
    }
}

ValidationResultにfalseを設定して返すと、エラーって事ですね。
これをTextBoxに設定します。

<TextBox
    Width="100"
    Margin="0,5,5,5"
    HorizontalAlignment="Center" >
    <TextBox.Text>
        <Binding Path="Age" UpdateSourceTrigger="PropertyChanged">
            <Binding.ValidationRules>
                <local:intValidationRule/>
            </Binding.ValidationRules>
        </Binding>
    </TextBox.Text>            
</TextBox>

ToolTipでのエラー表示

エラー文言の表示をツールチップとしたい場合には、Window.Resourceに以下を定義してください。この場合Templateは使用しないので、削除してください。

<Style TargetType="TextBox">
    <Style.Triggers>
        <Trigger Property="Validation.HasError" 
         Value="True">
            <Setter Property="ToolTip">
                <Setter.Value>
                    <Binding 
        Path="(Validation.Errors).CurrentItem.ErrorContent"
        RelativeSource="{x:Static RelativeSource.Self}" />
                </Setter.Value>
            </Setter>
        </Trigger>
    </Style.Triggers>
</Style>

ToolTipでの表示は以下を参照しています。
https://learn.microsoft.com/ja-jp/archive/msdn-magazine/2010/june/msdn-magazine-input-validation-enforcing-complex-business-data-rules-with-wpf

Discussion