手書きビューでのテキスト入力

Note

手書きビューは、Windows アプリ SDKのテキスト コントロールではサポートされていません。 この記事は、UWP アプリのみに適用されます。

ペンでタップするとテキスト ボックスが展開する

TextBoxRichEditBoxAutoSuggestBoxなどの UWP テキスト入力コントロールに組み込まれている手書きビュー (インクからテキスト入力用) をカスタマイズします。

概要

UWP テキスト入力コントロールは、ユーザーがペンを使用して テキスト入力ボックスにタップしたときに手書き画面に変換することで、Windows Ink を使用したペン入力をサポートします。

ユーザーが手書き面の任意の場所に書くとテキストが認識され、候補ウィンドウに認識結果が表示されます。 ユーザーは結果をタップしてそれを選択したり、書き込み続けて提案された候補を受け入れたりすることができます。 リテラル (1 文字ずつ) による認識結果は候補ウィンドウに含まれているため、認識はディクショナリ内の単語に制限されません。 ユーザーが書き込むと、受け入れられたテキスト入力は自然な手書き感を維持して Script フォントに変換されます。

Note

デフォルトで手書きビューは有効にされていますが、これはコントロールごとに無効にすることができ、代わりに元のテキスト入力パネルに戻すことができます。

インクと修正候補を含むテキスト ボックス

ユーザーは、標準のジェスチャとアクションを使用してテキストを編集できます。

  • 取り消し線またはインクを消す - 取り消し線を引いて単語や単語の一部を削除します
  • 結合 - 単語間に円弧を描き、単語間のスペースを削除します
  • 挿入 - スペースを挿入するキャレット記号を描画します
  • 上書き - 既存のテキストの上に書き込み、それを置き換えます

インクの修正を含むテキスト ボックス

手書きビューを無効にする

デフォルトでは、組み込みの手書きビューは有効になっています。

ご利用のアプリケーションで同等のインクをテキストに変換する機能を既に提供している場合、または、テキスト入力エクスペリエンスが手書きによって使用できない何らかの書式または特殊文字 (タブなど) に依存する場合、手書きビューを無効にする必要がある可能性があります。

この例では、TextBox コントロールの IsHandwritingViewEnabled プロパティを false に設定することで、手書きビューを無効にします。 手書きビューをサポートするすべてのテキスト コントロールで、同様のプロパティがサポートされます。 ​

<TextBox Name="SampleTextBox"​
    Height="50" Width="500" ​
    FontSize="36" FontFamily="Segoe UI" ​
    PlaceholderText="Try taping with your pen" ​
    IsHandwritingViewEnabled="False">​
</TextBox>​

手書きビューの配置を指定する

手書きビューは、基礎となるテキスト コントロールの上に配置され、ユーザーの手書き設定に合わせてサイズが調整されます ([設定] - >[Bluetooth とデバイス] - >[ペンと Windows Ink] -> [手書き] -> [フォント サイズ] を参照)。 また、ビューの配置も、アプリ内のテキスト コントロールとその場所に合わせて自動的に行われます。

アプリケーション UI は、大きなコントロールを収容するためにリフローされないため、重要な UI が隠れてしまう可能性があります。

次のスニペットは、TextBox HandwritingViewPlacementAlignment プロパティを使用して、手書きビューの配置に使用する基になるテキスト コントロール上のアンカーを指定する方法を示しています。 ​

<TextBox Name="SampleTextBox"​
    Height="50" Width="500" ​
    FontSize="36" FontFamily="Segoe UI" ​
    PlaceholderText="Try taping with your pen">​
        <TextBox.HandwritingView>​
            <HandwritingView PlacementAlignment="TopLeft"/>​
        </TextBox.HandwritingView>​
</TextBox>​

オートコンプリートの候補を無効にする

テキスト候補ポップアップは、デフォルトで有効になっています。 これは、主要なインク認識候補が間違っている場合にユーザーが選択できる上位のインク認識候補のリストを提供します。

ご利用のアプリケーションで既に堅牢なカスタムの認識機能が提供されている場合、次の例に示すように、AreCandidatesEnabled プロパティを使用して組み込みの修正候補を無効にすることができます。

<TextBox Name="SampleTextBox"​
    Height="50" Width="500" ​
    FontSize="36" FontFamily="Segoe UI" ​
    PlaceholderText="Try taping with your pen">​
        <TextBox.HandwritingView>​
            <HandwritingView AreCandidatesEnabled="False"/>​
        </TextBox.HandwritingView>​
</TextBox>

手書きフォントの基本設定を使用する

ユーザーは、インク認識に基づいてテキストをレンダリングするときに使用する手書きベースのフォントの事前定義されたコレクションから選択できます (「設定」 - >「Bluetooth とデバイス」 - > 「ペンと Windows Ink」 - > 「手書き」 - >「フォント」を参照)。

ご利用のアプリでは、この設定にアクセスし、テキスト コントロールで認識されたテキスト用に選択されたフォントを使用することができます。

この例では、TextBoxTextChangedイベントをリッスンし、テキストの変更が HandwritingViewから発生した場合はユーザーが選択したフォント (そうでない場合はデフォルトのフォント) を適用します。 ​

private void SampleTextBox_TextChanged(object sender, TextChangedEventArgs e)​
{​
    ((TextBox)sender).FontFamily = 
        ((TextBox)sender).HandwritingView.IsOpen ?
            new FontFamily(PenAndInkSettings.GetDefault().FontFamilyName) : 
            new FontFamily("Segoe UI");​
}​

複合コントロールで HandwritingView にアクセスする

TextBoxまたは RichEditBoxコントロール (AutoSuggestBoxなど) を使用する複合コントロールも、HandwritingViewをサポートします。

複合コントロールで HandwritingView にアクセスするには、VisualTreeHelper API を使用します。

次の XAML スニペットでは、AutoSuggestBox コントロールが表示されます。

<AutoSuggestBox Name="SampleAutoSuggestBox"​ 
    Height="50" Width="500"​ 
    PlaceholderText="Auto Suggest Example"​ 
    FontSize="16" FontFamily="Segoe UI" ​ 
    Loaded="SampleAutoSuggestBox_Loaded">​
</AutoSuggestBox>​

対応するコードビハインドでは、AutoSuggestBoxHandwritingView を無効にする方法を示しています。

  1. まず、要素の Loadedイベントを処理し、FindInnerTextBox 関数を呼び出してビジュアル ツリーのトラバースを開始します。

    private void SampleAutoSuggestBox_Loaded(object sender, RoutedEventArgs e)​
    {​
        if (FindInnerTextBox((AutoSuggestBox)sender))​
            autoSuggestInnerTextBox.IsHandwritingViewEnabled = false;​
    }​
    
  2. FindInnerTextBox 関数では、FindVisualChildByName 関数を呼び出して、ビジュアル ツリー (AutoSuggestBox から開始) を反復処理します。

    private bool FindInnerTextBox(AutoSuggestBox autoSuggestBox)​
    {​
        if (autoSuggestInnerTextBox == null)​
        {​
            // Cache textbox to avoid multiple tree traversals. ​
            autoSuggestInnerTextBox = 
                (TextBox)FindVisualChildByName<TextBox>(autoSuggestBox);​
        }​
        return (autoSuggestInnerTextBox != null);​
    }​
    ​```
    
    
  3. 最後に、FindVisualChildByName 関数は TextBoxが取得されるまでビジュアル ツリーを反復処理します。

    private FrameworkElement FindVisualChildByName<T>(DependencyObject obj)​
    {​
        FrameworkElement element = null;​
        int childrenCount = 
            VisualTreeHelper.GetChildrenCount(obj);​
        for (int i = 0; (i < childrenCount) && (element == null); i++)​
        {​
            FrameworkElement child = 
                (FrameworkElement)VisualTreeHelper.GetChild(obj, i);​
            if ((child.GetType()).Equals(typeof(T)) || (child.GetType().GetTypeInfo().IsSubclassOf(typeof(T))))​
            {​
                element = child;​
            }​
            else​
            {​
                element = FindVisualChildByName<T>(child);​
            }​
        }​
        return (element);​
    }​
    ​```
    
    

HandwritingView の位置を変更する

場合によっては、HandwritingView 以外ではカバーできない可能性のある UI 要素が確実にカバーされるようにする必要があります。

ここで、ディクテーションをサポートする TextBox を作成します (TextBox とディクテーション ボタンを StackPanel に配置することで実装されます)。

ディクテーションをサポートするテキスト ボックスのスクリーンショット

StackPanel が TextBox よりも大きいため、HandwritingViewが複合コントロールのすべてを遮らない可能性があります。

TextBox の一部を隠している HandwritingView のコントロールと、TextBox が完全に隠されるように再配置された HandwritingView のコントロールのスクリーンショット

これに対処するには、HandwritingView の PlacementTarget プロパティに整列される必要がある UI 要素を設定します。

<StackPanel Name="DictationBox" 
    Orientation="Horizontal" ​
    VerticalAlignment="Top" 
    HorizontalAlignment="Left" ​
    BorderThickness="1" BorderBrush="DarkGray" ​
    Height="55" Width="500" Margin="50">​
    <TextBox Name="DictationTextBox" 
        Width="450" BorderThickness="0" ​
        FontSize="24" VerticalAlignment="Center">​
        <TextBox.HandwritingView>​
            <HandwritingView PlacementTarget="{Binding ElementName=DictationBox}"/>​
        </TextBox.HandwritingView>​
    </TextBox>​
    <Button Name="DictationButton" 
        Height="48" Width="48" 
        FontSize="24" ​
        FontFamily="Segoe MDL2 Assets" 
        Content="&#xE720;" ​
        Background="White" Foreground="DarkGray" ​    Tapped="DictationButton_Tapped" />​
</StackPanel>​

HandwritingView のサイズを変更する

ビューにより重要な UI が遮られないことを確実にする必要があるときに便利な場合がある、HandwritingView のサイズを設定することもできます。

前の例のように、ディクテーションをサポートする TextBox を作成します (TextBox とディクテーション ボタンを StackPanel に配置することで実装されます)。

ディクテーションをサポートする TextBox のスクリーンショット

この場合、確実にディクテーション ボタンが表示されるように HandwritingView のサイズを変更します。

ディクテーション ボタンを隠している HandwritingView のコントロールと、確実にディクテーション ボタンが表示されるようにサイズが変更された HandwritingView のコントロールのスクリーンショット

これを行うには、HandwritingView の MaxWidth プロパティを、見えなくなる UI 要素の幅にバインドします。

<StackPanel Name="DictationBox" 
    Orientation="Horizontal" ​
    VerticalAlignment="Top" 
    HorizontalAlignment="Left" ​
    BorderThickness="1" 
    BorderBrush="DarkGray" ​
    Height="55" Width="500" 
    Margin="50">​
    <TextBox Name="DictationTextBox" 
        Width="450" 
        BorderThickness="0" ​
        FontSize="24" 
        VerticalAlignment="Center">​
        <TextBox.HandwritingView>​
            <HandwritingView 
                PlacementTarget="{Binding ElementName=DictationBox}"​
                MaxWidth="{Binding ElementName=DictationTextBox, Path=Width"/>​
        </TextBox.HandwritingView>​
    </TextBox>​
    <Button Name="DictationButton" 
        Height="48" Width="48" 
        FontSize="24" ​
        FontFamily="Segoe MDL2 Assets" 
        Content="&#xE720;" ​
        Background="White" Foreground="DarkGray" ​
        Tapped="DictationButton_Tapped" />​
</StackPanel>​

カスタム UI の位置を変更する

情報のポップアップなど、テキスト入力に応答して表示されるカスタムの UI がある場合、手書きビューが見えなくならないように、その UI の配置を変更する必要があります。

カスタム UI を含む TextBox

次の例では、ポップアップの位置を設定するために、HandwritingViewOpenedClosedSizeChanged イベントをリッスンする方法を示します。

private void Search_HandwritingViewOpened(
    HandwritingView sender, HandwritingPanelOpenedEventArgs args)​
{​
    UpdatePopupPositionForHandwritingView();​
}​
​
private void Search_HandwritingViewClosed(
    HandwritingView sender, HandwritingPanelClosedEventArgs args)​
{​
    UpdatePopupPositionForHandwritingView();​
}​
​
private void Search_HandwritingViewSizeChanged(
    object sender, SizeChangedEventArgs e)​
{​
    UpdatePopupPositionForHandwritingView();​
}​
​
private void UpdatePopupPositionForHandwritingView()​
{​
if (CustomSuggestionUI.IsOpen)​
    CustomSuggestionUI.VerticalOffset = GetPopupVerticalOffset();​
}​
​
private double GetPopupVerticalOffset()​
{​
    if (SearchTextBox.HandwritingView.IsOpen)​
        return (SearchTextBox.Margin.Top + SearchTextBox.HandwritingView.ActualHeight);​
    else​
        return (SearchTextBox.Margin.Top + SearchTextBox.ActualHeight);​    ​
}​

HandwritingView コントロールの再テンプレート化

すべての XAML フレームワーク コントロールで、特定の要件のために、HandwritingView の視覚的な構造と視覚的な動作の両方をカスタマイズできます。

カスタム テンプレートを作成する完全な例を表示するには、「カスタム トランスポート コントロールを作成する」の方法または「カスタムの編集コントロールのサンプル」を確認してください。 ​ ​ ​ ​ ​ ​ ​ ​