バージョン アダプティブ コードVersion adaptive code

アダプティブ コードの記述については、アダプティブ UI の作成についての考え方と同じように考えることができます。You can think about writing adaptive code similarly to how you think about creating an adaptive UI. 最小画面で実行するように基本 UI を設計し、より大きな画面でアプリが実行されていることを検出したときに要素を移動または追加できます。You might design your base UI to run on the smallest screen, and then move or add elements when you detect that your app is running on a larger screen. アダプティブ コードの場合、最小の OS バージョンで実行するように基本コードを記述し、新機能が提供されているより高いバージョンでアプリが実行されていることを検出したときに、機能を手動で選んで追加できます。With adaptive code, you write your base code to run on the lowest OS version, and you can add hand-selected features when you detect that your app is running on a higher version where the new feature is available.

ApiInformation に関する重要な背景情報、API コントラクト、Visual Studio の構成については、「バージョン アダプティブ アプリ」をご覧ください。For important background info about ApiInformation, API contracts, and configuring Visual Studio, see Version adaptive apps.

ランタイム API チェックRuntime API checks

呼び出す API が存在するかどうかをテストするために、コードの条件で Windows.Foundation.Metadata.ApiInformation クラスを使います。You use the Windows.Foundation.Metadata.ApiInformation class in a condition in your code to test for the presence of the API you want to call. このテストの条件は、アプリの実行時に必ず評価されますが、API が存在するデバイスに対してのみ true と評価され、呼び出しが可能になります。This condition is evaluated wherever your app runs, but it evaluates to true only on devices where the API is present and therefore available to call. これにより、特定の OS バージョンでのみ利用できる API を使うアプリを作成するためのバージョン アダプティブ コードを記述できます。This lets you write version adaptive code in order to create apps that use APIs that are available only on certain OS versions.

ここでは、Windows Insider Preview の新機能をターゲットにするための具体的な例を示します。Here, we look at specific examples for targeting new features in the Windows Insider Preview. ApiInformation を使う場合の一般的な概要については、デバイス ファミリの概要に関する記事API コントラクトを使った機能の動的な検出に関するブログの投稿をご覧ください。For a general overview of using ApiInformation, see Device families overview and the blog post Dynamically detecting features with API contracts.

ヒント

さまざまなランタイム API チェックが、アプリのパフォーマンスに影響する可能性があります。Numerous runtime API checks can affect the performance of your app. それらの例では、チェックをインラインで示します。We show the checks inline in these examples. 運用コードでは、チェックを一度実行してから結果をキャッシュし、キャッシュされた結果をアプリ全体で使う必要があります。In production code, you should perform the check once and cache the result, then used the cached result throughout your app.

サポートされていないシナリオUnsupported scenarios

ほとんどの場合、アプリの最小バージョンを SDK バージョン 10240 に設定したままにし、アプリがそれより新しいバージョンで実行されたときに、ランタイム チェックを使って新しい API を有効にすることができます。In most cases, you can keep your app's Minimum Version set to SDK version 10240 and use runtime checks to enable any new APIs when your app runs on later a version. ただし、新機能を使うためにアプリの最小バージョンを上げることが必要になる場合もあります。However, there are some cases where you must increase your app's Minimum Version in order to use new features.

アプリの最小バージョンを上げる必要があるのは、以下を使う場合です。You must increase your app's Minimum Version if you use:

  • 以前のバージョンでは使うことができない機能を必要とする新しい API。a new API that requires a capability that isn't available in an earlier version. サポートされる最小バージョンを、その機能が含まれているバージョンに上げる必要があります。You must increase the minimum supported version to one that includes that capability. 詳しくは、「アプリ機能の宣言」をご覧ください。For more info, see App capability declarations.
  • generic.xaml に追加された新しいリソース キーのうち、以前のバージョンでは使うことができないリソース キー。any new resource keys added to generic.xaml and not available in a previous version. 実行時に使われる generic.xaml のバージョンは、デバイスで実行されている OS バージョンによって決まります。The version of generic.xaml used at runtime is determined by the OS version the device is running on. ランタイム API チェックを使って XAML リソースの有無を確認することはできません。You can't use runtime API checks to determine the presence of XAML resources. そのため、アプリがサポートする最小バージョンで利用できるリソース キーのみを使う必要があります。そうしないと、XAMLParseException が原因で実行時にアプリがクラッシュします。So, you must only use resource keys that are available in the minimum version that your app supports or a XAMLParseException will cause your app to crash at runtime.

アダプティブ コードのオプションAdaptive code options

アダプティブ コードを作成するには 2 つの方法があります。There are two ways to create adaptive code. ほとんどの場合、アプリのマークアップを最小バージョンで実行するように記述してから、アプリ コードを使ってより新しい OS 機能 (存在する場合) を活用します。In most cases, you write your app markup to run on the Minimum version, then use your app code to tap into newer OS features when present. ただし、表示状態でプロパティを更新する必要があり、OS バージョン間でプロパティ値と列挙値の変更のみがある場合、API の存在に基づいてアクティブ化される拡張可能な状態トリガーを作成できます。However, if you need to update a property in a visual state, and there is only a property or enumeration value change between OS versions, you can create an extensible state trigger that’s activated based on the presence of an API.

ここで、以下のオプションを比較します。Here, we compare these options.

アプリコードApp code

使う状況:When to use:

  • すべてのアダプティブ コード シナリオにお勧めします。ただし、拡張可能なトリガー用に以下に定義されている特定のケースは除きます。Recommended for all adaptive code scenarios except for specific cases defined below for extensible triggers.

利点:Benefits:

  • API の相違をマークアップに結び付ける際の開発者のオーバーヘッドや複雑さを回避できます。Avoids developer overhead/complexity of tying API differences into markup.

欠点:Drawbacks:

  • デザイナーがサポートされていません。No Designer support.

状態トリガーState Triggers

使う状況:When to use:

  • OS バージョン間で、ロジックを変更する必要のない、表示状態に関連付けられているプロパティまたは列挙値のみに変更がある場合に使います。Use when there is only a property or enum change between OS versions that doesn’t require logic changes, and is connected to a visual state.

利点:Benefits:

  • API の存在に基づいてトリガーされる特定の表示状態を作成できます。Lets you create specific visual states that are triggered based on the presence of an API.
  • 一部のデザイナー サポートを利用できます。Some designer support available.

欠点:Drawbacks:

  • カスタム トリガーの使用は表示状態に限定されるため、複雑なアダプティブ レイアウトには適していません。Use of custom triggers is restricted to visual states, which doesn’t lend itself to complicated adaptive layouts.
  • セッターを使って値の変更を指定する必要があるため、単純な変更だけを行うことができます。Must use Setters to specify value changes, so only simple changes are possible.
  • カスタム状態トリガーを設定して使うには、非常に細かい設定が必要です。Custom state triggers are fairly verbose to set up and use.

アダプティブ コードの例Adaptive code examples

このセクションでは、Windows 10 バージョン 1607 (Windows Insider Preview) で新しく追加された API を使うアダプティブ コードの例をいくつか示します。In this section, we show several examples of adaptive code that use APIs that are new in Windows 10, version 1607 (Windows Insider Preview).

例 1: 新しい列挙値Example 1: New enum value

Windows 10 バージョン 1607 では、InputScopeNameValue 列挙体に新しい値 ChatWithoutEmoji が追加されています。Windows 10, version 1607 adds a new value to the InputScopeNameValue enumeration: ChatWithoutEmoji. この新しい入力スコープの入力動作は、Chat 入力スコープ (スペルチェック、オートコンプリート、大文字の自動設定) と同じですが、絵文字ボタンのないタッチ キーボードにマップされます。This new input scope has the same input behavior as the Chat input scope (spellchecking, auto-complete, auto-capitalization), but it maps to a touch keyboard without an emoji button. これは、独自の絵文字ピッカーを作成し、タッチ キーボードに組み込まれている絵文字ボタンを無効にする場合に便利です。This is useful if you create your own emoji picker and want to disable the built-in emoji button in the touch keyboard.

次の例は、ChatWithoutEmoji 列挙値が存在するかどうかを確認し、存在する場合は TextBoxInputScope プロパティを設定する方法を示しています。This example shows how to check if the ChatWithoutEmoji enum value is present and sets the InputScope property of a TextBox if it is. アプリが実行されているシステムにこの列挙値が存在しない場合、InputScopeChat に設定されます。If it’s not present on the system the app is run on, the InputScope is set to Chat instead. ここに示されているコードは、Page コンストラクターまたは Page.Loaded イベント ハンドラーに配置できます。The code shown could be placed in a Page consructor or Page.Loaded event handler.

ヒント

API をチェックするときは、.NET 言語機能を使うのではなく静的な文字列を使います。そうしないと、アプリは定義されていない型にアクセスしようとして、実行時にクラッシュすることがあります。When you check an API, use static strings instead of relying on .NET language features, otherwise your app might try to access a type that isn’t defined and crash at runtime.

C#C#

// Create a TextBox control for sending messages 
// and initialize an InputScope object.
TextBox messageBox = new TextBox();
messageBox.AcceptsReturn = true;
messageBox.TextWrapping = TextWrapping.Wrap;
InputScope scope = new InputScope();
InputScopeName scopeName = new InputScopeName();

// Check that the ChatWithEmoji value is present.
// (It's present starting with Windows 10, version 1607,
//  the Target version for the app. This check returns false on earlier versions.)         
if (ApiInformation.IsEnumNamedValuePresent("Windows.UI.Xaml.Input.InputScopeNameValue", "ChatWithoutEmoji"))
{
    // Set new ChatWithoutEmoji InputScope if present.
    scopeName.NameValue = InputScopeNameValue.ChatWithoutEmoji;
}
else
{
    // Fall back to Chat InputScope.
    scopeName.NameValue = InputScopeNameValue.Chat;
}

// Set InputScope on messaging TextBox.
scope.Names.Add(scopeName);
messageBox.InputScope = scope;

// For this example, set the TextBox text to show the selected InputScope.
messageBox.Text = messageBox.InputScope.Names[0].NameValue.ToString();

// Add the TextBox to the XAML visual tree (rootGrid is defined in XAML).
rootGrid.Children.Add(messageBox);

前の例では、TextBox が作成され、コードにすべてのプロパティが設定されています。In the previous example, the TextBox is created and all properties are set in code. ただし、既存の XAML があり、新しい値がサポートされているシステムで InputScope プロパティのみを変更する必要がある場合、次に示すように、XAML を変更せずにその操作を実行できます。However, if you have existing XAML, and just need to change the InputScope property on systems where the new value is supported, you can do that without changing your XAML, as shown here. XAML で既定値を Chat に設定しますが、ChatWithoutEmoji 値が存在する場合はコードでそれをオーバーライドします。You set the default value to Chat in XAML, but you override it in code if the ChatWithoutEmoji value is present.

XAMLXAML

<TextBox x:Name="messageBox"
         AcceptsReturn="True" TextWrapping="Wrap"
         InputScope="Chat"
         Loaded="messageBox_Loaded"/>

C#C#

private void messageBox_Loaded(object sender, RoutedEventArgs e)
{
    if (ApiInformation.IsEnumNamedValuePresent("Windows.UI.Xaml.Input.InputScopeNameValue", "ChatWithoutEmoji"))
    {
        // Check that the ChatWithEmoji value is present.
        // (It's present starting with Windows 10, version 1607,
        //  the Target version for the app. This code is skipped on earlier versions.)
        InputScope scope = new InputScope();
        InputScopeName scopeName = new InputScopeName();
        scopeName.NameValue = InputScopeNameValue.ChatWithoutEmoji;
        // Set InputScope on messaging TextBox.
        scope.Names.Add(scopeName);
        messageBox.InputScope = scope;
    }

    // For this example, set the TextBox text to show the selected InputScope.
    // This is outside of the API check, so it will happen on all OS versions.
    messageBox.Text = messageBox.InputScope.Names[0].NameValue.ToString();
}

既に具体例があるので、ターゲット バージョンと最小バージョンの設定がどのように適用されるのかを見てみましょう。Now that we have a concrete example, let’s see how the Target and Minimum version settings apply to it.

これらの例では、XAML またはチェックを含まないコードで Chat 列挙値を使うことができます。これは、Chat 列挙値がサポートされる最小の OS バージョンに存在するためです。In these examples, you can use the Chat enum value in XAML, or in code without a check, because it’s present in the minimum supported OS version.

XAML またはチェックを含まないコードで ChatWithoutEmoji 値を使うと、ChatWithoutEmoji 値がターゲットの OS バージョンに存在するためエラーなしでコンパイルされます。If you use the ChatWithoutEmoji value in XAML, or in code without a check, it will compile without error because it's present in the Target OS version. また、ターゲットの OS バージョンが含まれたシステムで、エラーなしで実行されます。It will also run without error on a system with the Target OS version. ただし、アプリが最小バージョンを使っている OS を含むシステムで実行されると、ChatWithoutEmoji 列挙値が存在しないため実行時にクラッシュします。However, when the app runs on a system with an OS using the Minimum version, it will crash at runtime because the ChatWithoutEmoji enum value is not present. そのため、コードでのみこの値を使って、この値が現在のシステムでサポートされている場合だけ呼び出されるように、ランタイム API チェックにラップする必要があります。Therefore, you must use this value only in code, and wrap it in a runtime API check so it’s called only if it’s supported on the current system.

例 2: 新しいコントロールExample 2: New control

通常、新しいバージョンの Windows では、プラットフォームに新機能をもたらす新しいコントロールが UWP API サーフェスに追加されています。A new version of Windows typically brings new controls to the UWP API surface that bring new functionality to the platform. 新しいコントロールを活用するには、ApiInformation.IsTypePresent メソッドを使います。To leverage the presence of a new control, use the ApiInformation.IsTypePresent method.

Windows 10 バージョン 1607 には、MediaPlayerElement と呼ばれる新しいメディア コントロールが導入されています。Windows 10, version 1607 introduces a new media control called MediaPlayerElement. このコントロールは、MediaPlayer クラスに基づいて作成されているため、バックグラウンド オーディオに簡単に結び付けることができるような機能が追加され、メディア スタックの向上したアーキテクチャを活用しています。This control builds on the MediaPlayer class, so it brings features like the ability to easily tie into background audio, and it makes use of architectural improvements in the media stack.

ただし、アプリが Windows 10 バージョン 1607 より古いバージョンを実行しているデバイスで実行される場合、新しい MediaPlayerElement コントロールではなく、MediaElement コントロールを使う必要があります。However, if the app runs on a device that’s running a version of Windows 10 older than version 1607, you must use the MediaElement control instead of the new MediaPlayerElement control. ApiInformation.IsTypePresent メソッドを使って実行時に MediaPlayerElement コントロールが存在するかどうかをチェックし、アプリが実行されているシステムに適しているコントロールを読み込むことができます。You can use the ApiInformation.IsTypePresent method to check for the presence of the MediaPlayerElement control at runtime, and load whichever control is suitable for the system where the app is running.

この例は、新しい MediaPlayerElement または古い MediaElement を使うアプリを作成する方法を示しています。どちらを使うかは、MediaPlayerElement 型が存在するかどうかによって異なります。This example shows how to create an app that uses either the new MediaPlayerElement or the old MediaElement depending on whether MediaPlayerElement type is present. このコードでは、UserControl クラスを使って、コントロール、およびそれに関連する UI とコードをコンポーネント化し、OS バージョンに基づいて切り替えることができるようにしています。In this code, you use the UserControl class to componentize the controls and their related UI and code so that you can switch them in and out based on the OS version. また、このシンプルな例に必要なものよりも機能的でカスタムの動作を提供するカスタム コントロールを使うこともできます。As an alternative, you can use a custom control, which provides more functionality and custom behavior than what’s needed for this simple example.

MediaPlayerUserControlMediaPlayerUserControl

MediaPlayerUserControl は、MediaPlayerElement と、フレーム単位でメディアを飛ばすために使われるいくつかのボタンをカプセル化します。The MediaPlayerUserControl encapsulates a MediaPlayerElement and several buttons that are used to skip through the media frame by frame. UserControl を使うと、これらのコントロールを単一のエンティティとして扱って、以前のシステムの MediaElement と簡単に切り替えることができます。The UserControl lets you treat these controls as a single entity and makes it easier to switch with a MediaElement on older systems. このユーザー コントロールは、MediaPlayerElement が存在するシステムでのみ使う必要があるため、このユーザー コントロール内のコードでは ApiInformation チェックを使いません。This user control should be used only on systems where MediaPlayerElement is present, so you don’t use ApiInformation checks in the code inside this user control.

注意

この例をシンプルなままにし、集中して取り組むために、フレーム ステップ ボタンはメディア プレーヤーの外部に配置されています。To keep this example simple and focused, the frame step buttons are placed outside of the media player. ユーザー エクスペリエンスを向上するためには、MediaTransportControls をカスタマイズしてカスタム ボタンを含める必要があります。For a better user experiance, you should customize the MediaTransportControls to include your custom buttons. 詳しくは、「カスタム トランスポート コントロールを作成する」をご覧ください。See Custom transport controls for more info.

XAMLXAML

<UserControl
    x:Class="MediaApp.MediaPlayerUserControl"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:MediaApp"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    d:DesignHeight="300"
    d:DesignWidth="400">

    <Grid x:Name="MPE_grid>
        <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <StackPanel Orientation="Horizontal" 
                    HorizontalAlignment="Center" Grid.Row="1">
            <RepeatButton Click="StepBack_Click" Content="Step Back"/>
            <RepeatButton Click="StepForward_Click" Content="Step Forward"/>
        </StackPanel>
    </Grid>
</UserControl>

C#C#

using System;
using Windows.Media.Core;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;

namespace MediaApp
{
    public sealed partial class MediaPlayerUserControl : UserControl
    {
        public MediaPlayerUserControl()
        {
            this.InitializeComponent();
            
            // The markup code compiler runs against the Minimum OS version so MediaPlayerElement must be created in app code
            MPE = new MediaPlayerElement();
            Uri videoSource = new Uri("ms-appx:///Assets/UWPDesign.mp4");
            MPE.Source = MediaSource.CreateFromUri(videoSource);
            MPE.AreTransportControlsEnabled = true;
            MPE.MediaPlayer.AutoPlay = true;

            // Add MediaPlayerElement to the Grid
            MPE_grid.Children.Add(MPE);

        }

        private void StepForward_Click(object sender, RoutedEventArgs e)
        {
            // Step forward one frame, only available using MediaPlayerElement.
            MPE.MediaPlayer.StepForwardOneFrame();
        }

        private void StepBack_Click(object sender, RoutedEventArgs e)
        {
            // Step forward one frame, only available using MediaPlayerElement.
            MPE.MediaPlayer.StepForwardOneFrame();
        }
    }
}

MediaElementUserControlMediaElementUserControl

MediaElementUserControlMediaElement コントロールをカプセル化します。The MediaElementUserControl encapsulates a MediaElement control.

XAMLXAML

<UserControl
    x:Class="MediaApp.MediaElementUserControl"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:MediaApp"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    d:DesignHeight="300"
    d:DesignWidth="400">

    <Grid>
        <MediaElement AreTransportControlsEnabled="True" 
                      Source="Assets/UWPDesign.mp4"/>
    </Grid>
</UserControl>

注意

MediaElementUserControl のコード ページには、生成されたコードのみが含まれているため、ここでは示しません。The code page for MediaElementUserControl contains only generated code, so it's not shown.

IsTypePresent に基づいてコントロールを初期化するInitialize a control based on IsTypePresent

実行時に、ApiInformation.IsTypePresent を呼び出して、MediaPlayerElement の有無を確認します。At runtime, you call ApiInformation.IsTypePresent to check for MediaPlayerElement. MediaPlayerElement が存在する場合は MediaPlayerUserControl を読み込み、存在しない場合は MediaElementUserControl を読み込みます。If it's present, you load MediaPlayerUserControl, if it's not, you load MediaElementUserControl.

C#C#

public MainPage()
{
    this.InitializeComponent();

    UserControl mediaControl;

    // Check for presence of type MediaPlayerElement.
    if (ApiInformation.IsTypePresent("Windows.UI.Xaml.Controls.MediaPlayerElement"))
    {
        mediaControl = new MediaPlayerUserControl();
    }
    else
    {
        mediaControl = new MediaElementUserControl();
    }

    // Add mediaControl to XAML visual tree (rootGrid is defined in XAML).
    rootGrid.Children.Add(mediaControl);
}

重要

このチェックでは mediaControl オブジェクトを MediaPlayerUserControl または MediaElementUserControl に設定するだけです。Remember that this check only sets the mediaControl object to either MediaPlayerUserControl or MediaElementUserControl. コード内の MediaPlayerElement API と MediaElement API のどちらを使うのかを判断する必要がある他の場所でこれらの条件付きチェックを実行する必要があります。You need to perform these conditional checks anywhere else in your code that you need to determine whether to use MediaPlayerElement or MediaElement APIs. チェックを一度実行してから結果をキャッシュし、キャッシュされた結果をアプリ全体で使う必要があります。You should perform the check once and cache the result, then used the cached result throughout your app.

状態トリガーの例State trigger examples

拡張可能な状態トリガーでは、マークアップとコードを一緒に使って、コードでチェックする条件 (ここでは、特定の API が存在するかどうか) に基づいて表示状態の変更をトリガーできます。Extensible state triggers let you use markup and code together to trigger visual state changes based on a condition that you check in code; in this case, the presence of a specific API. 関係するオーバーヘッドと、表示状態のみへの制限があるため、一般的なアダプティブ コード シナリオで状態トリガーを使うことはお勧めしません。We don’t recommend state triggers for common adaptive code scenarios because of the overhead involved, and the restriction to only visual states.

コントロール上のプロパティ値や列挙値の変更など、残りの UI に影響しない、異なる OS バージョン間での小さな UI の変更がある場合のみ、アダプティブ コードに状態トリガーを使ってください。You should use state triggers for adaptive code only when you have small UI changes between different OS versions that won’t impact the remaining UI, such as a property or enum value change on a control.

例 1: 新しいプロパティExample 1: New property

拡張可能な状態トリガーを設定する最初の手順は、StateTriggerBase クラスのサブクラスを作成して、API の有無に基づいてアクティブになるカスタム トリガーを作成することです。The first step in setting up an extensible state trigger is subclassing the StateTriggerBase class to create a custom trigger that will be active based on the presence of an API. この例は、プロパティの有無が XAML に設定されている _isPresent 変数に一致する場合にアクティブ化されるトリガーを示しています。This example shows a trigger that activates if the property presence matches the _isPresent variable set in XAML.

C#C#

class IsPropertyPresentTrigger : StateTriggerBase
{
    public string TypeName { get; set; }
    public string PropertyName { get; set; }

    private Boolean _isPresent;
    private bool? _isPropertyPresent = null;

    public Boolean IsPresent
    {
        get { return _isPresent; }
        set
        {
            _isPresent = value;
            if (_isPropertyPresent == null)
            {
                // Call into ApiInformation method to determine if property is present.
                _isPropertyPresent =
                ApiInformation.IsPropertyPresent(TypeName, PropertyName);
            }

            // If the property presence matches _isPresent then the trigger will be activated;
            SetActive(_isPresent == _isPropertyPresent);
        }
    }
}

次の手順は、XAML で表示状態トリガーを設定して、2 つの異なる表示状態が API の有無に基づいた結果になるようにします。The next step is setting up the visual state trigger in XAML so that two different visual states result based on the presence of the API.

Windows 10 バージョン 1607 では、ユーザーがコントロールを操作するときにそのコントロールがフォーカスを取得するかどうかを判断する AllowFocusOnInteraction と呼ばれる FrameworkElement クラスに新しいプロパティが導入されています。Windows 10, version 1607 introduces a new property on the FrameworkElement class called AllowFocusOnInteraction that determines whether a control takes focus when a user interacts with it. これは、ユーザーがボタンをクリックしたときに、データ入力用のテキスト ボックスにフォーカスを保持する (タッチ キーボードを表示したままにする) のに役立ちます。This is useful if you want to keep focus on a text box for data entry (and keep the touch keyboard showing) while the user clicks a button.

この例のトリガーは、プロパティが存在するかどうかをチェックします。The trigger in this example checks if the property is present. プロパティが存在する場合、Button の AllowFocusOnInteraction プロパティが false に設定されます。プロパティが存在しない場合は、Button はその元の状態を保持します。If the property is present it sets the AllowFocusOnInteraction property on a Button to false; if the property isn’t present, the Button retains its original state. TextBox は、コードの実行時にこのプロパティの影響をわかりやすくするために含まれています。The TextBox is included to make it easier to see the effect of this property when you run the code.

XAMLXAML

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
    <StackPanel>
        <TextBox Width="300" Height="36"/>
        <!-- Button to set the new property on. -->
        <Button x:Name="testButton" Content="Test" Margin="12"/>
    </StackPanel>

    <VisualStateManager.VisualStateGroups>
        <VisualStateGroup x:Name="propertyPresentStateGroup">
            <VisualState>
                <VisualState.StateTriggers>
                    <!--Trigger will activate if the AllowFocusOnInteraction property is present-->
                    <local:IsPropertyPresentTrigger 
                        TypeName="Windows.UI.Xaml.FrameworkElement" 
                        PropertyName="AllowFocusOnInteraction" IsPresent="True"/>
                </VisualState.StateTriggers>
                <VisualState.Setters>
                    <Setter Target="testButton.AllowFocusOnInteraction" 
                            Value="False"/>
                </VisualState.Setters>
            </VisualState>
        </VisualStateGroup>
    </VisualStateManager.VisualStateGroups>
</Grid>

例 2: 新しい列挙値Example 2: New enum value

次の例は、値が存在するかどうかに基づいてさまざまな列挙値を設定する方法を示しています。This example shows how to set different enumeration values based on whether a value is present. カスタム状態トリガーを使って、前のチャットの例と同じ結果を実現します。It uses a custom state trigger to achieve the same result as the previous chat example. この例では、デバイスが Windows 10 バージョン 1607 を実行している場合に、新しい ChatWithoutEmoji 入力スコープを使います。それ以外の場合、Chat 入力スコープが使われます。In this example, you use the new ChatWithoutEmoji input scope if the device is running Windows 10, version 1607, otherwise the Chat input scope is used. このトリガーを使う表示状態は、新しい列挙値の有無に基づいて入力スコープが選択される if-else スタイルで設定されます。The visual states that use this trigger are set up in an if-else style where the input scope is chosen based on the presence of the new enum value.

C#C#

class IsEnumPresentTrigger : StateTriggerBase
{
    public string EnumTypeName { get; set; }
    public string EnumValueName { get; set; }

    private Boolean _isPresent;
    private bool? _isEnumValuePresent = null;

    public Boolean IsPresent
    {
        get { return _isPresent; }
        set
        {
            _isPresent = value;

            if (_isEnumValuePresent == null)
            {
                // Call into ApiInformation method to determine if value is present.
                _isEnumValuePresent =
                ApiInformation.IsEnumNamedValuePresent(EnumTypeName, EnumValueName);
            }

            // If the property presence matches _isPresent then the trigger will be activated;
            SetActive(_isPresent == _isEnumValuePresent);
        }
    }
}

XAMLXAML

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">

    <TextBox x:Name="messageBox"
     AcceptsReturn="True" TextWrapping="Wrap"/>


    <VisualStateManager.VisualStateGroups>
        <VisualStateGroup x:Name="EnumPresentStates">
            <!--if-->
            <VisualState x:Name="isPresent">
                <VisualState.StateTriggers>
                    <local:IsEnumPresentTrigger 
                        EnumTypeName="Windows.UI.Xaml.Input.InputScopeNameValue" 
                        EnumValueName="ChatWithoutEmoji" IsPresent="True"/>
                </VisualState.StateTriggers>
                <VisualState.Setters>
                    <Setter Target="messageBox.InputScope" Value="ChatWithoutEmoji"/>
                </VisualState.Setters>
            </VisualState>
            <!--else-->
            <VisualState x:Name="isNotPresent">
                <VisualState.StateTriggers>
                    <local:IsEnumPresentTrigger 
                        EnumTypeName="Windows.UI.Xaml.Input.InputScopeNameValue" 
                        EnumValueName="ChatWithoutEmoji" IsPresent="False"/>
                </VisualState.StateTriggers>
                <VisualState.Setters>
                    <Setter Target="messageBox.InputScope" Value="Chat"/>
                </VisualState.Setters>
            </VisualState>
        </VisualStateGroup>
    </VisualStateManager.VisualStateGroups>
</Grid>