shuhelohelo’s blog

Xamarin.Forms多めです.

Blazorでテキストボックス間の同期

片方のテキストボックスに入力した内容を、もう片方のテキストボックスに同期的に表示したい。

というのはまったくニーズが無い話とは思います。

環境

準備

さて、まずはClient Side Blazorのテンプレートを使ってソリューションを作成します。

f:id:shuhelohelo:20190521171332p:plain

次に空のページを一つ作りましょう。 Pagesフォルダーで右クリックして追加 > クラスとして、名前を「SyncTextBox.razor」という名前をつけます。

f:id:shuhelohelo:20190521171954p:plain

作ったらこのSyncTextBox.razorに書かれているC#のコードを削除します。 これで準備完了です。

ちなみに、なぜこんな回りくどいことをやっているかというと、私のプレビュー×プレビューな環境ではRazorページの自動生成はどころかMVCの各種スキャフォールディングといった自動生成が全く使えないからです。

そのうち修正されると思います。

まずはテキストボックスの同期

それでは、まずはこんなふうに書いてみましょう。

@page "/synctextbox"


<p>エンターを押した時点で出力側が更新</p>
<p>
    入力1
    <input type="text" bind="@Text1" />
</p>
<p>
    出力1
    <input type="text" value="@Text1" />
</p>


@functions{
    string Text1 { get; set; }
}

そうしたら実行して、http://localhost:{ポート番号}/synctextboxをブラウザで開いてみましょう。

以下のようなページが表示されます。

f:id:shuhelohelo:20190521172729p:plain

2つあるテキストボックスのうち、上のテキストボックスに文字を入力してエンターキーを押してみましょう。

下のテキストボックスに同じテキストが表示されたと思います。

コードブロックに用意したText1プロパティを介して入力1のテキストを出力1のテキストボックスに表示させています。

入力側のテキストボックスではbind属性を使用してText1プロパティと双方向バインディングしています。 これで入力側のテキストボックスの内容がText1プロパティに反映されます。

これに対して、出力側のテキストボックスではvalue属性を使ってText1プロパティの値を表示させています。 value属性はプロパティからビューへの単方向バインディングです。 今回の場合、bind属性を使っても良いのですが、せっかくなのでvalueにしました。

この例では、出力側への反映のタイミングは入力側のテキストボックスでエンターが入力されたときです。 エンターが入力されるまでは出力側のテキストボックスには変化はありません。

こんなふうに入力内容が確定したら他の場所で反映させる、ということが簡単にできます。

リアルタイムな同期

それでは、2つのテキストボックス間をリアルタイムに同期させるにはどうしたらいいでしょうか。

その場合はbind属性ではなく、oninput属性を使うと実現できます。イベントですね。

これはテキストボックスに何かしら入力があった場合に発火するイベントです。

このイベントを使って以下のように書くことができます。

@page "/synctextbox"

<p>エンターを押した時点で出力側が更新</p>
<p>
    入力1
    <input type="text" oninput="@(ui=> { Text2 = (string)ui.Value; })" />
</p>
<p>
    出力1
    <input type="text" value="@Text2" />
</p>


@functions{
    string Text2 { get; set; }
}

oninputイベントはUIChangeEventArgs型の引数を一つとり、その中にinput要素の値を指すValueプロパティがあります。 このValueプロパティを使ってText2プロパティを更新することで、2つのテキストボックス間のリアルタイム同期を行っています。

テキストボックス間で双方向の同期

2つのテキストボックスがそれぞれoninput属性でText3プロパティを更新してvalue属性で値を表示するようにすると、双方向同期ができます。

@page "/synctextbox"

<p>エンターを押した時点で出力側が更新</p>
<p>
    入力1
    <input type="text" oninput="@(ui=> { Text2 = (string)ui.Value; })" value="@Text2" />
</p>
<p>
    出力1
    <input type="text" oninput="@(ui=> { Text2 = (string)ui.Value; })" value="@Text2" />
</p>


@functions{
    string Text2 { get; set; }
}