😽

MAUIでアプリ作成(3)

2024/01/17に公開

MAUIサンプル

電話番号の入力インターフェース

プロパティのBindは学習済なので、次はButtonを押した際のEvent処理の説明。
プロパティのBindで変数値の表示は出来てるので、あとはButton操作の処理が記述出来れば、簡単なアプリは作成できるかも。

ICommand

Eventの作成する為に必要なインターフェース
System.Windows.Input名前空間
2つのメソッドと1つのイベントで構成されている。
・void Execute(object arg)
・bool CanExecute(object arg)
・event EventHandler CanExecuteChanged

ビューモデルでICommand型のプロパティを定義して、Buttonのプロパティにバインドする。

実装

毎回ですが、今回もViewModelを新規作成する為に、プロジェクトにクラスを追加
名前はKeypadViewModelとして下さい。
KeypadViewModel.cs内の記述は以下

using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Windows.Input;
using Microsoft.Maui.Controls.Platform;

namespace MauiSample
{
    class KeypadViewModel : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler? PropertyChanged;

        private string _inputString = "";
        private string _displayText = "";
        private char[] _specialChars = { '*', '#' };

        public ICommand AddCharCommand { get; private set; }
        public ICommand DeleteCharCommand { get; private set; }

        public string InputString
        {
            get => _inputString;
            private set
            {
                if(_inputString != value)
                {
                    _inputString = value;

                    OnPropertyChanged();
                    DisplayText = FormatText(_inputString);

                    ((Command)DeleteCharCommand).ChangeCanExecute();
                }
            }
        }
        public string DisplayText
        {
            get => _displayText;
            private set
            {
                if( _displayText != value)
                {
                    _displayText = value;
                    OnPropertyChanged();
                }
            }
        }
        public KeypadViewModel()
        {
            AddCharCommand = new Command<string>((key) => InputString += key);
            DeleteCharCommand = new Command(
                () => InputString = InputString.Substring(0, InputString.Length - 1),
                () => InputString.Length > 0
             );
        }
        string FormatText(string str)
        {
            bool hasNonNumbers = str.IndexOfAny(_specialChars) != -1;
            string formatted = str;

            if (hasNonNumbers || str.Length < 4 || str.Length > 10)
            {

            }
            else if (str.Length < 8)
                formatted = string.Format("{0}-{1}", str.Substring(0, 3), str.Substring(3));
            else
                formatted = string.Format("({0}) {1}-{2}",str.Substring(0,3),str.Substring(3,3),str.Substring(6));
            return formatted;
        }
        private void OnPropertyChanged([CallerMemberName] string name = "")=>
            PropertyChanged?.Invoke(this,new PropertyChangedEventArgs(name));

        
    }
}

説明は後程で、Viewのxamlファイルの実装は以下
MainPage.xaml

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:MauiSample"
             x:Class="MauiSample.MainPage"
             Title="Keypad Page">
    <ContentPage.BindingContext>
        <local:KeypadViewModel />
    </ContentPage.BindingContext>
    <Grid HorizontalOptions="Center" VerticalOptions="Center">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="80" />
            <ColumnDefinition Width="80" />
            <ColumnDefinition Width="80" />
        </Grid.ColumnDefinitions>

        <Label Text="{Binding DisplayText}"
               Margin="0,0,10,0" FontSize="20" LineBreakMode="HeadTruncation"
               VerticalTextAlignment="Center" HorizontalTextAlignment="End"
               Grid.ColumnSpan="2" />

        <Button Text="&#x21E6;" Command="{Binding DeleteCharCommand}" Grid.Column="2"/>

        <Button Text="1" Command="{Binding AddCharCommand}" CommandParameter="1" Grid.Row="1" />
        <Button Text="2" Command="{Binding AddCharCommand}" CommandParameter="2" Grid.Row="1" Grid.Column="1" />
        <Button Text="3" Command="{Binding AddCharCommand}" CommandParameter="3" Grid.Row="1" Grid.Column="2" />

        <Button Text="4" Command="{Binding AddCharCommand}" CommandParameter="4" Grid.Row="2" />
        <Button Text="5" Command="{Binding AddCharCommand}" CommandParameter="5" Grid.Row="2" Grid.Column="1" />
        <Button Text="6" Command="{Binding AddCharCommand}" CommandParameter="6" Grid.Row="2" Grid.Column="2" />

        <Button Text="7" Command="{Binding AddCharCommand}" CommandParameter="7" Grid.Row="3" />
        <Button Text="8" Command="{Binding AddCharCommand}" CommandParameter="8" Grid.Row="3" Grid.Column="1" />
        <Button Text="9" Command="{Binding AddCharCommand}" CommandParameter="9" Grid.Row="3" Grid.Column="2" />

        <Button Text="*" Command="{Binding AddCharCommand}" CommandParameter="*" Grid.Row="4" />
        <Button Text="0" Command="{Binding AddCharCommand}" CommandParameter="0" Grid.Row="4" Grid.Column="1" />
        <Button Text="#" Command="{Binding AddCharCommand}" CommandParameter="#" Grid.Row="4" Grid.Column="2" />
    </Grid>
</ContentPage>

説明

Buttonを押下時の処理は、xamlファイルButtonコントロールのCommandプロパティにBindされている(①)
AddCharCommandは、KeypadViewModelクラスにPublicとして定義されている(③)
AddCharCommandの実態は、AddCharCommandクラスのコンストラクタで定義されている(④)
Command<string>型なので、stringは引数の型となる。引数は、Buttonコントロールにて、CommandParameterとして指定されている(②)


左側:MainPage.xaml 右側:KeypadViewModel.cs

もう一つのCommandとしてDeleteCharCommandがあるが、こっちも同じ様な感じで実装されている。ただしDeleteCharCommandへの代入処理にて違う形式となっている。

DeleteCharCommand = new Command(
    () => InputString = InputString.Substring(0, InputString.Length - 1),
    () => InputString.Length > 0
 );

Command型なので、AddCharCommandの様なStringを渡す処理は無いけど、Commandの定義にて引数が2個となっている。
引数の意味は以下の通り。

内容
Action イベントの登録
Func<Bool> コントロールの有効/無効

第2引数が新しい。このイベントを行うボタンなどのコントロールの有効/無効の条件を設定できる。
ここの実装では、InputString内の文字数が0以上の場合には、コントロールが有効となる。

Discussion