Versionsadaptiver CodeVersion adaptive code

Das Schreiben von adaptivem Code ist vergleichbar mit dem Erstellen einer adaptiven UI.You can think about writing adaptive code similarly to how you think about creating an adaptive UI. Dabei können Sie etwa Ihre grundlegende Benutzeroberfläche für den kleinsten Bildschirm entwerfen und anschließend Elemente verschieben oder hinzufügen, wenn erkannt wird, dass die App auf einem größeren Bildschirm ausgeführt wird.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. Bei adaptivem Code schreiben Sie Ihren Basiscode für die niedrigste Betriebssystemversion und können anschließend ausgewählte Features hinzufügen, wenn erkannt wird, dass Ihre App unter einer höheren Version ausgeführt wird, die über das neue Feature verfügt.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.

Wichtige Hintergrundinformationen zu ApiInformation, API-Verträgen und dem Konfigurieren von Visual Studio findest du unter Versionsadaptive Apps.For important background info about ApiInformation, API contracts, and configuring Visual Studio, see Version adaptive apps.

API-LaufzeitprüfungenRuntime API checks

Verwenden Sie die Windows.Foundation.Metadata.ApiInformation-Klasse in einer Bedingung in Ihrem Code, um zu testen, ob die aufzurufende API vorhanden ist.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. Diese Bedingung wird immer ausgewertet – ganz gleich, wo Ihre App ausgeführt wird. Das Ergebnis ist aber nur dann True, wenn sie auf einem Gerät ausgeführt wird, auf dem die API vorhanden ist und somit aufgerufen werden kann.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. Auf diese Weise kannst du Apps mit versionsadaptivem Code unter Nutzung von APIs erstellen, die nur unter bestimmten Betriebssystemversionen verfügbar sind.This lets you write version adaptive code in order to create apps that use APIs that are available only on certain OS versions.

Hier gehen wir anhand von spezifischen Beispielen auf die Nutzung neuer Features in Windows Insider Preview ein.Here, we look at specific examples for targeting new features in the Windows Insider Preview. Eine allgemeine Übersicht über die Verwendung von ApiInformation finden Sie unterProgrammieren mit Erweiterungs-SDKs sowie im Blogbeitrag Dynamically detecting features with API contracts (Dynamisches Erkennen von Features mithilfe von API-Verträgen).For a general overview of using ApiInformation, see Programming with extension SDKs and the blog post Dynamically detecting features with API contracts.

Tipp

Eine hohe Anzahl von API-Laufzeitprüfungen kann die Leistung Ihrer App beeinträchtigen.Numerous runtime API checks can affect the performance of your app. Die Prüfungen werden in diesen Beispielen inline veranschaulicht.We show the checks inline in these examples. In Produktionscode empfiehlt es sich, die Prüfung nur einmal durchzuführen, das Ergebnis zwischenzuspeichern und es anschließend in der gesamten App zu verwenden.In production code, you should perform the check once and cache the result, then used the cached result throughout your app.

Nicht unterstützte SzenarienUnsupported scenarios

In den meisten Fällen können Sie die auf die SDK-Version 10240 festgelegte Mindestversion Ihrer App beibehalten und neue APIs auf der Grundlage von Laufzeitprüfungen aktivieren, wenn die App unter einer höheren Version ausgeführt wird.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. In bestimmten Fällen müssen Sie allerdings die Mindestversion Ihrer App erhöhen, um neue Features verwenden zu können.However, there are some cases where you must increase your app's Minimum Version in order to use new features.

Die Mindestversion der App muss erhöht werden, wenn Sie Folgendes verwenden:You must increase your app's Minimum Version if you use:

  • Eine neue API, die eine Funktion erfordert, die in einer früheren Version nicht verfügbar ist.a new API that requires a capability that isn't available in an earlier version. Die unterstützte Mindestversion muss auf eine höhere Version festgelegt werden, die über diese Funktion verfügt.You must increase the minimum supported version to one that includes that capability. Weitere Informationen finden Sie unter Deklaration der App-Funktionen.For more info, see App capability declarations.
  • Einen neuen Ressourcenschlüssel, der zu „generic.xaml“ hinzugefügt wurde und in einer früheren Version nicht verfügbar war.any new resource keys added to generic.xaml and not available in a previous version. Die zur Laufzeit verwendete Version von „generic.xaml“ wird durch die auf dem Gerät ausgeführte Betriebssystemversion bestimmt.The version of generic.xaml used at runtime is determined by the OS version the device is running on. Mit API-Laufzeitprüfungen lässt sich nicht ermitteln, ob XAML-Ressourcen vorhanden sind.You can't use runtime API checks to determine the presence of XAML resources. Daher dürfen nur Ressourcenschlüssel verwendet werden, die in der von der App unterstützten Mindestversion zur Verfügung stehen. Andernfalls bringt eine XAMLParseException Ihre App zur Laufzeit zum Absturz.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.

Optionen für adaptiven CodeAdaptive code options

Adaptiver Code kann auf zwei Arten erstellt werden.There are two ways to create adaptive code. In den meisten Fällen schreiben Sie den Markupcode Ihrer App für die Mindestversion und verwenden dann Ihren App-Code, um ggf. die Nutzung neuerer Betriebssystemfeatures zu ermöglichen.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. Wenn Sie allerdings eine Eigenschaft in einem visuellen Zustand aktualisieren müssen und sich zwischen Betriebssystemversionen lediglich ein Eigenschafts- oder Enumerationswert ändert, können Sie einen erweiterbaren Zustandsauslöser erstellen, dessen Aktivierung davon abhängt, ob eine API vorhanden ist.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.

Im Anschluss finden Sie eine Gegenüberstellung dieser Optionen:Here, we compare these options.

App-CodeApp code

VerwendungWhen to use:

  • Empfohlen für alle Szenarien mit adaptivem Code mit Ausnahme bestimmter Fälle, die weiter unten für erweiterbare Auslöser definiert sind.Recommended for all adaptive code scenarios except for specific cases defined below for extensible triggers.

Vorteile:Benefits:

  • Weniger Aufwand/Komplexität für Entwickler beim Einbinden von API-Unterschieden in das MarkupAvoids developer overhead/complexity of tying API differences into markup.

Nachteile:Drawbacks:

  • Keine DesignerunterstützungNo Designer support.

ZustandsauslöserState Triggers

VerwendungWhen to use:

  • Verwenden Sie diese Option, wenn sich zwischen Betriebssystemversionen nur eine Eigenschaft oder Enumeration geändert hat, keine Änderung der Logik erforderlich ist und eine Verbindung mit einem visuellen Zustand besteht.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.

Vorteile:Benefits:

  • Ermöglicht die Erstellung spezifischer visueller Zustände, die abhängig davon ausgelöst werden, ob eine API vorhanden ist.Lets you create specific visual states that are triggered based on the presence of an API.
  • Eingeschränkte Designerunterstützung verfügbar.Some designer support available.

Nachteile:Drawbacks:

  • Die Verwendung von benutzerdefinierten Auslösern ist auf visuelle Zustände beschränkt, weshalb sich die Option nicht für komplizierte adaptive Layouts eignet.Use of custom triggers is restricted to visual states, which doesn’t lend itself to complicated adaptive layouts.
  • Wertänderungen müssen mithilfe von Settern angegeben werden, sodass nur einfache Änderungen möglich sind.Must use Setters to specify value changes, so only simple changes are possible.
  • Die Einrichtung und Verwendung benutzerdefinierter Zustandsauslöser ist relativ aufwendig.Custom state triggers are fairly verbose to set up and use.

Beispiele für adaptiven CodeAdaptive code examples

In diesem Abschnitt zeigen wir verschiedene Beispiele für adaptiven Code, in denen neue APIs aus der Windows 10-Version 1607 (Windows Insider Preview) verwendet werden.In this section, we show several examples of adaptive code that use APIs that are new in Windows 10, version 1607 (Windows Insider Preview).

Beispiel 1: Neuer EnumerationswertExample 1: New enum value

In Windows 10 Version 1607 wird die Enumeration InputScopeNameValue um einen neuen Wert erweitert: ChatWithoutEmoji.Windows 10, version 1607 adds a new value to the InputScopeNameValue enumeration: ChatWithoutEmoji. Dieser neue Eingabeumfang besitzt das gleiche Eingabeverhalten wie der Eingabeumfang Chat (Rechtschreibprüfung, AutoVervollständigen, automatische Großschreibung), wird aber einer Bildschirmtastatur ohne Emoji-Schaltfläche zugeordnet.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. Dies ist hilfreich, wenn Sie Ihre eigene Emoji-Auswahl erstellen und die integrierte Emoji-Schaltfläche auf der Bildschirmtastatur deaktivieren möchten.This is useful if you create your own emoji picker and want to disable the built-in emoji button in the touch keyboard.

Dieses Beispiel zeigt, wie Sie überprüfen, ob der ChatWithoutEmoji-Enumerationswert vorhanden ist, und die InputScope-Eigenschaft eines TextBox-Elements festlegen, falls dies der Fall ist.This example shows how to check if the ChatWithoutEmoji enum value is present and sets the InputScope property of a TextBox if it is. Ist der Wert in dem System, auf dem die App ausgeführt wird, nicht vorhanden, wird InputScope stattdessen auf Chat festgelegt.If it’s not present on the system the app is run on, the InputScope is set to Chat instead. Der hier gezeigte Code kann in einem Page-Konstruktor oder in einem Page.Loaded-Ereignishandler platziert werden.The code shown could be placed in a Page consructor or Page.Loaded event handler.

Tipp

Verlassen Sie sich beim Prüfen einer API nicht auf .NET-Sprachfeatures, sondern verwenden Sie statische Zeichenfolgen. Andernfalls versucht Ihre App unter Umständen, auf einen nicht definierten Typ zuzugreifen, was einen Absturz zur Laufzeit zur Folge hat.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);

Im vorherigen Beispiel wird das TextBox-Element erstellt, und alle Eigenschaften werden im Code festgelegt.In the previous example, the TextBox is created and all properties are set in code. Wenn Sie allerdings bereits über XAML verfügen und lediglich die InputScope-Eigenschaft für Systeme ändern möchten, auf denen der neue Wert unterstützt wird, können Sie dies wie hier zu sehen ohne XAML-Änderung implementieren.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. Der Standardwert wird in XAML auf Chat festgelegt und im Code überschrieben, falls der ChatWithoutEmoji-Wert vorhanden ist.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();
}

Nachdem wir nun über ein konkretes Beispiel verfügen, sehen wir uns einmal an, wie in diesem Fall die Einstellungen für Mindest- und Zielversion angewendet werden.Now that we have a concrete example, let’s see how the Target and Minimum version settings apply to it.

In diesen Beispielen können Sie den Chat-Enumerationswert in XAML oder in Code ohne Überprüfung verwenden, da der Wert in der unterstützten Mindestversion des Betriebssystems vorhanden ist.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.

Wenn Sie den ChatWithoutEmoji-Wert in XAML oder in Code ohne Überprüfung verwenden, wird er ohne Fehler kompiliert, da der Wert in der Zielversion des Betriebssystems vorhanden ist.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. Auch die Ausführung auf einem System mit der Zielversion des Betriebssystems ist ohne Fehler möglich.It will also run without error on a system with the Target OS version. Wenn die App allerdings auf einem System mit der Mindestversion des Betriebssystems ausgeführt wird, stürzt sie zur Laufzeit ab, da der ChatWithoutEmoji-Enumerationswert nicht vorhanden ist.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. Daher dürfen Sie diesen Wert nur in Code verwenden und müssen ihn mit einer API-Laufzeitprüfung umschließen, sodass er nur aufgerufen wird, wenn dies auf dem aktuellen System unterstützt wird.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.

Beispiel 2: Neues SteuerelementExample 2: New control

Eine neue Version von Windows verfügt üblicherweise über neue Steuerelemente für die UWP-API-Oberfläche, die den Funktionsumfang der Plattform erweitern.A new version of Windows typically brings new controls to the UWP API surface that bring new functionality to the platform. Das Vorhandensein eines neuen Steuerelements kann mithilfe der ApiInformation.IsTypePresent-Methode ermittelt werden.To leverage the presence of a new control, use the ApiInformation.IsTypePresent method.

In der Windows 10-Version 1607 wird ein neues Mediensteuerelement namens MediaPlayerElement eingeführt.Windows 10, version 1607 introduces a new media control called MediaPlayerElement. Dieses Steuerelement basiert auf der MediaPlayer-Klasse, stellt beispielweise Features wie die problemlose Einbindung von Hintergrundaudio bereit und profitiert von Verbesserungen bei der Architektur des Medienstapels.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.

Wenn die App allerdings auf einem Gerät mit einer älteren Windows 10-Version als 1607 ausgeführt wird, muss anstelle des neuen MediaPlayerElement-Steuerelements das MediaElement-Steuerelement verwendet werden.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. Sie können mithilfe der ApiInformation.IsTypePresent-Methode zur Laufzeit überprüfen, ob das MediaPlayerElement-Steuerelement vorhanden ist, und dann das geeignete Steuerelement für das System laden, auf dem die App ausgeführt wird.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.

Dieses Beispiel zeigt, wie Sie eine App erstellen, die abhängig davon, ob der MediaPlayerElement-Typ vorhanden ist, entweder das neue MediaPlayerElement-Steuerelement oder das alte MediaElement-Steuerelement verwendet.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. In diesem Code werden die Steuerelemente samt dazugehöriger Benutzeroberfläche und entsprechendem Code mithilfe der UserControl-Klasse in Komponenten zerlegt, sodass sie abhängig von der Betriebssystemversion einbezogen werden können.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. Alternativ können Sie ein benutzerdefiniertes Steuerelement verwendet. Dieses bietet mehr Funktionen und benutzerdefiniertes Verhalten als in diesem einfachen Beispiel erforderlich.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 kapselt ein MediaPlayerElement und mehrere Schaltflächen für eine framebasierte Mediennavigation.The MediaPlayerUserControl encapsulates a MediaPlayerElement and several buttons that are used to skip through the media frame by frame. „UserControl“ ermöglicht die Behandlung dieser Steuerelemente als einzelne Entität und erleichtert den Wechsel zu „MediaElement“ bei älteren Systemen.The UserControl lets you treat these controls as a single entity and makes it easier to switch with a MediaElement on older systems. Dieses Benutzersteuerelement sollte nur für Systeme verwendet werden, die über „MediaPlayerElement“ verfügen, sodass im Code innerhalb dieses Benutzersteuerelements keine ApiInformation-Prüfungen ausgeführt werden.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.

Hinweis

Die Schaltflächen für die Frameschritte werden außerhalb des Medienplayers platziert, um dieses Beispiel möglichst einfach und prägnant zu halten.To keep this example simple and focused, the frame step buttons are placed outside of the media player. Zur Verbesserung der Benutzerfreundlichkeit sollten Sie „MediaTransportControls“ mit Ihren benutzerdefinierten Schaltflächen anpassen.For a better user experiance, you should customize the MediaTransportControls to include your custom buttons. Weitere Informationen finden Sie unter Benutzerdefinierte Transportsteuerelemente.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 kapselt ein MediaElement-Steuerelement.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>

Hinweis

Die Codepage für MediaElementUserControl enthält nur generierten Code und wird daher nicht gezeigt.The code page for MediaElementUserControl contains only generated code, so it's not shown.

Initialisieren eines Steuerelements auf der Grundlage von IsTypePresentInitialize a control based on IsTypePresent

Rufen Sie zur Laufzeit ApiInformation.IsTypePresent auf, um zu prüfen, ob „MediaPlayerElement“ vorhanden ist.At runtime, you call ApiInformation.IsTypePresent to check for MediaPlayerElement. Falls ja, wird MediaPlayerUserControl geladen. Andernfalls wird MediaElementUserControl geladen.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);
}

Wichtig

Zur Erinnerung: Diese Überprüfung legt nur das mediaControl-Objekt auf MediaPlayerUserControl oder MediaElementUserControl fest.Remember that this check only sets the mediaControl object to either MediaPlayerUserControl or MediaElementUserControl. Diese bedingten Überprüfungen müssen überall im Code durchgeführt werden, wo Sie ermitteln müssen, ob die MediaPlayerElement- oder die MediaElement-API verwendet werden soll.You need to perform these conditional checks anywhere else in your code that you need to determine whether to use MediaPlayerElement or MediaElement APIs. Es empfiehlt sich, die Prüfung nur einmal durchzuführen, das Ergebnis zwischenzuspeichern und es anschließend in der gesamten App zu verwenden.You should perform the check once and cache the result, then used the cached result throughout your app.

Beispiele für ZustandsauslöserState trigger examples

Mithilfe erweiterbarer Zustandsauslöser können Sie Markup und Code zusammen verwenden, um Änderungen des visuellen Zustands auf der Grundlage einer im Code überprüften Bedingung auszulösen (in diesem Fall: das Vorhandensein einer bestimmten 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. In allgemeinen Szenarien mit adaptivem Code wird die Verwendung von Zustandsauslösern aufgrund des zusätzlichen Aufwands und der Beschränkung auf visuelle Zustände nicht empfohlen.We don’t recommend state triggers for common adaptive code scenarios because of the overhead involved, and the restriction to only visual states.

Verwenden Sie Zustandsauslöser nur dann für adaptiven Code, wenn lediglich geringfügige Benutzeroberflächenänderungen zwischen Betriebssystemversionen vorliegen, die sich nicht auf die restliche Benutzeroberfläche auswirken (etwa die Änderung einer Eigenschaft oder eines Enumerationswerts für ein Steuerelement).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.

Beispiel 1: Neue EigenschaftExample 1: New property

Der erste Schritt bei der Einrichtung eines erweiterbaren Zustandsauslösers besteht in der Verwendung von Unterklassen für die StateTriggerBase-Klasse zur Erstellung eines benutzerdefinierten Auslösers, dessen Aktivierung davon abhängt, ob eine API vorhanden ist.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. Dieses Beispiel zeigt einen Auslöser, der aktiviert wird, wenn das Vorhandensein der Eigenschaft der in XAML festgelegten _isPresent-Variablen entspricht.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);
        }
    }
}

Im nächsten Schritt wird der visuelle Zustandsauslöser in XAML eingerichtet, um abhängig vom Vorhandensein der API zwei unterschiedliche visuelle Zustände zu erhalten.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.

In der Windows 10-Version 1607 wird für die FrameworkElement-Klasse eine neue Eigenschaft namens AllowFocusOnInteraction eingeführt, die bestimmt, ob ein Steuerelement den Fokus erhält, wenn ein Benutzer damit interagiert.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. Dies ist hilfreich, falls ein Textfeld für die Dateneingabe den Fokus behalten (und die Bildschirmtastatur weiter angezeigt werden) soll, wenn der Benutzer auf eine Schaltfläche klickt.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.

Der Auslöser in diesem Beispiel überprüft, ob die Eigenschaft vorhanden ist.The trigger in this example checks if the property is present. Ist die Eigenschaft vorhanden, wird die AllowFocusOnInteraction-Eigenschaft für eine Schaltfläche auf False festgelegt. Ist die Eigenschaft nicht vorhanden, wird der ursprüngliche Zustand der Schaltfläche beibehalten.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. Das TextBox-Element dient zur Veranschaulichung der Auswirkung dieser Eigenschaft, wenn Sie den Code ausführen.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>

Beispiel 2: Neuer EnumerationswertExample 2: New enum value

Dieses Beispiel zeigt, wie Sie abhängig davon, ob ein Wert vorhanden ist, unterschiedliche Enumerationswerte festlegen.This example shows how to set different enumeration values based on whether a value is present. Hierbei kommt ein benutzerdefinierter Zustandsauslöser zum Einsatz, um das gleiche Ergebnis zu erhalten wie im vorherigen Chatbeispiel.It uses a custom state trigger to achieve the same result as the previous chat example. In diesem Beispiel wird der neue ChatWithoutEmoji-Eingabeumfang verwendet, wenn auf dem Gerät die Windows 10-Version 1607 ausgeführt wird. Andernfalls wird der Eingabeumfang Chat verwendet.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. Die visuellen Zustände, die diesen Auslöser verwenden, werden im if-else-Stil eingerichtet, wobei die Wahl des Eingabeumfangs davon abhängt, ob der neue Enumerationswert vorhanden ist.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>