版本調適型程式碼Version adaptive code

您可以考慮撰寫調適型程式碼 (和您針對建立調適型 UI 所進行的考量類似)。You can think about writing adaptive code similarly to how you think about creating an adaptive UI. 您可以將基底 UI 設計為在最小的螢幕上執行,然後在偵測到 App 正在較大的螢幕上執行時移動或新增元素。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 版本上執行的基底程式碼,並在偵測到 App 正在具有新功能的較新版本上執行時,新增選取功能。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

使用程式碼條件中的 Windows.Foundation.Metadata.ApiInformation 類別,以測試您要呼叫的 API 是否存在。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. 此條件會在您的 App 每次執行時受到評估,但它只會在存在該 API (因而可供呼叫) 的裝置上被評估為 trueThis 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 的一般概觀,請參閱使用擴充功能 SDK 進行程式設計,以及 Dynamically detecting features with API contracts (利用 API 協定動態偵測功能) 這篇部落格文章。For a general overview of using ApiInformation, see Programming with extension SDKs and the blog post Dynamically detecting features with API contracts.

提示

過多執行階段 API 檢查可能會影響您 App 的效能。Numerous runtime API checks can affect the performance of your app. 我們會在這些範例中示範這些內嵌檢查。We show the checks inline in these examples. 在實際執行程式碼中,您應該執行檢查一次,並且快取結果,然後在整個 App 中使用快取的結果。In production code, you should perform the check once and cache the result, then used the cached result throughout your app.

不支援的案例Unsupported scenarios

在大部分情況下,您可以將 App 的「最低」版本設定保持為 SDK 版本 10240,並在您的 App 於較新版本上執行時,使用執行階段檢查來啟用任何新的 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. 不過,在有某些情況下,您必須提高您 App 的最低版本,才能使用新功能。However, there are some cases where you must increase your app's Minimum Version in order to use new features.

如果您使用下列項目,便必須提高您 App 的「最低」版本: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. 因此,您必須只使用您 App 所支援的最低版本中可以使用的資源識別碼,否則 XAMLParseException 會導致您的 App 在執行階段當機。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

建立調適型程式碼有兩種方式。There are two ways to create adaptive code. 在大部分情況下,您會將您的 App 標記撰寫為在「最低」版本上執行,然後在有較新的 OS 功能時,透過 App 程式碼來使用那些功能。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.
  • 必須使用 Setters 來指定值變更,因此只可能進行簡單的變更。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 列舉:ChatWithoutEmojiWindows 10, version 1607 adds a new value to the InputScopeNameValue enumeration: ChatWithoutEmoji. 這個新的輸入範圍具有與 Chat 輸入範圍相同的輸入行為 (拼字檢查、自動完成、自動大寫),但是它會對應到沒有 Emoji 按鈕的觸控式鍵盤。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. 如果您建立自己的 Emoji 選擇器,並想要停用觸控式鍵盤中內建的 Emoji 按鈕,這會很有用。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. 如果它沒有出現在 App 所執行的系統上,InputScope 會改成設定為 ChatIf 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 語言功能,否則您的 App 可能會嘗試存取未定義的類型,且在執行階段當機。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 列舉值,因為它已存在於支援的「最低」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 值,它會進行編譯且不會發生錯誤,因為它已存在於「目標」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. 不過,當 App 在使用「最低」版本 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 導入了新的媒體控制項,稱為 MediaPlayerElementWindows 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.

不過,如果 App 在比 Windows 10 版本 1607 還舊的版本上執行,您必須使用MediaElement 控制項而非新的 MediaPlayerElement 控制項。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 控制項在執行階段是否存在,並載入適用於執行 App 之系統的任何一個控制項。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 類型是否存在來使用新的 MediaPlayerElement 或舊的 MediaElement 的 App。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

MediaElementUserControl 會封裝 MediaElement 控制項。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. 如果存在,將載入 MediaPlayerUserControl,如果沒有,則會載入 MediaElementUserControlIf 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 物件設為 MediaPlayerUserControlMediaElementUserControlRemember that this check only sets the mediaControl object to either MediaPlayerUserControl or MediaElementUserControl. 您必須在程式碼中需要判斷使用 MediaPlayerElement 或 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. 您應該執行檢查一次並且快取結果,然後在整個 App 中使用快取的結果。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.

您應該只有在不同 OS 版本之間有不會影響其他 UI 的小型 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 中設定視覺狀態觸發程序,根據 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 在 FrameworkElement (英文) 類別上導入了新的屬性,稱為 AllowFocusOnInteraction (英文),它可判斷使用者與控制項互動時,控制項是否會接受焦點。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. 它會使用自訂狀態觸發程序來達成與先前的 Chat 範例相同的結果。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>