Sdílet prostřednictvím


Použití objektů prostředí Windows Runtime v prostředí s více vlákny

Tento článek popisuje způsob, jakým rozhraní .NET Framework zpracovává volání z jazyka C# a kódu jazyka Visual Basic na objekty poskytované modulem Windows Runtime nebo komponentami prostředí Windows Runtime.

V rozhraní .NET Framework můžete ve výchozím nastavení přistupovat k libovolnému objektu z více vláken bez speciálního zpracování. Jediné, co potřebujete, je odkaz na objekt. V prostředí Windows Runtime se takové objekty nazývají agilní. Většina Windows Runtime tříd je flexibilní, ale několik tříd není, a dokonce i flexibilní třídy mohou vyžadovat speciální zpracování.

Pokud je to možné, modul CLR (Common Language Runtime) považuje objekty z jiných zdrojů, například prostředí Windows Runtime, jako by se jednalo o objekty rozhraní .NET Framework:

Následující části popisují účinky tohoto chování na objekty z různých zdrojů.

Objekty z komponenty prostředí Windows Runtime napsané v jazyce C# nebo Visual Basic

Všechny typy v komponentě, které je možné aktivovat, jsou ve výchozím nastavení agilní.

Poznámka:

Flexibilita neznamená bezpečnost vláken. V prostředí Windows Runtime i rozhraní .NET Framework nejsou většina tříd bezpečné pro vlákna, protože zajištění bezpečnosti vláken má dopad na výkon, a většina objektů není nikdy přistupována více vlákny. Je efektivnější synchronizovat přístup k jednotlivým objektům (nebo používat třídy bezpečné pro přístup z více vláken) pouze podle potřeby.

Když vytvoříte komponentu prostředí Windows Runtime, můžete výchozí nastavení přepsat. Viz ICustomQueryInterface rozhraní a IAgileObject rozhraní.

Objekty z prostředí Windows Runtime

Většina tříd v prostředí Windows Runtime je agilní a CLR je považuje za agilní. Dokumentace pro tyto třídy uvádí "MarshalingBehaviorAttribute(Agile)" mezi atributy třídy. Členové některých z těchto agilních tříd, jako jsou například ovládací prvky XAML, však můžou vyvolat výjimky, pokud nejsou volány ve vlákně uživatelského rozhraní. Například následující kód se pokusí použít vlákno na pozadí k nastavení vlastnosti tlačítka, na které jste klikli. Vlastnost Content tlačítka vyvolá výjimku.

private async void Button_Click_2(object sender, RoutedEventArgs e)
{
    Button b = (Button) sender;
    await Task.Run(() => {
        b.Content += ".";
    });
}
Private Async Sub Button_Click_2(sender As Object, e As RoutedEventArgs)
    Dim b As Button = CType(sender, Button)
    Await Task.Run(Sub()
                       b.Content &= "."
                   End Sub)
End Sub

K tlačítku se dostanete bezpečně pomocí jeho vlastnosti Dispatcher nebo Dispatcher vlastnosti libovolného objektu, který existuje v kontextu vlákna uživatelského rozhraní (například stránka, na které je tlačítko zapnuto). Následující kód používá metodu RunAsync objektu CoreDispatcher, aby odeslal volání ve vlákně uživatelského rozhraní.

private async void Button_Click_2(object sender, RoutedEventArgs e)
{
    Button b = (Button) sender;
    await b.Dispatcher.RunAsync(
        Windows.UI.Core.CoreDispatcherPriority.Normal,
        () => {
            b.Content += ".";
    });
}

Private Async Sub Button_Click_2(sender As Object, e As RoutedEventArgs)
    Dim b As Button = CType(sender, Button)
    Await b.Dispatcher.RunAsync(
        Windows.UI.Core.CoreDispatcherPriority.Normal,
        Sub()
            b.Content &= "."
        End Sub)
End Sub

Poznámka:

Vlastnost Dispatcher nevyvolá výjimku, pokud je volána z jiného vlákna.

Životnost objektu prostředí Windows Runtime, který je vytvořen ve vlákně uživatelského rozhraní, je vázán životností vlákna. Po zavření okna se nepokoušejte o přístup k objektům ve vlákně uživatelského rozhraní.

Pokud vytváříte vlastní ovládací prvek děděním ovládacího prvku XAML nebo vytvořením sady ovládacích prvků XAML, je ovládací prvek agilní, protože se jedná o objekt rozhraní .NET Framework. Pokud však volá členy své základní třídy nebo složených tříd, nebo pokud voláte zděděné členy, tyto členy vyvolají výjimky, když jsou volány z jakéhokoliv vlákna kromě vlákna uživatelského rozhraní.

Třídy, které nelze zařadovat

Třídy prostředí Windows Runtime, které neposkytují maršálovací informace, mají atribut MarshalingBehaviorAttribute s MarshalingType.None. Dokumentace pro takovou třídu uvádí "MarshalingBehaviorAttribute(None)" mezi jejími atributy.

Následující kód vytvoří CameraCaptureUI objekt ve vlákně uživatelského rozhraní a pak se pokusí nastavit vlastnost objektu z vlákna fondu vláken. CLR nemůže zařadit volání a vyvolá výjimku System.InvalidCastException se zprávou, že objekt lze použít pouze v kontextu vlákna, ve kterém byl vytvořen.

Windows.Media.Capture.CameraCaptureUI ccui;

private async void Button_Click_1(object sender, RoutedEventArgs e)
{
    ccui = new Windows.Media.Capture.CameraCaptureUI();

    await Task.Run(() => {
        ccui.PhotoSettings.AllowCropping = true;
    });
}

Private ccui As Windows.Media.Capture.CameraCaptureUI

Private Async Sub Button_Click_1(sender As Object, e As RoutedEventArgs)
    ccui = New Windows.Media.Capture.CameraCaptureUI()

    Await Task.Run(Sub()
                       ccui.PhotoSettings.AllowCropping = True
                   End Sub)
End Sub

Dokumentace pro CameraCaptureUI také uvádí "ThreadingAttribute(STA)" mezi atributy třídy, protože se musí vytvořit v kontextu s jedním vláknem, jako je vlákno uživatelského rozhraní.

Pokud chcete získat přístup k objektu CameraCaptureU I z jiného vlákna, můžete uložit objekt CoreDispatcher do mezipaměti pro vlákno uživatelského rozhraní a později ho použít k odeslání volání v daném vlákně. Nebo můžete dispečera získat z objektu XAML, jako je například stránka, jak je znázorněno v následujícím kódu.

Windows.Media.Capture.CameraCaptureUI ccui;

private async void Button_Click_3(object sender, RoutedEventArgs e)
{
    ccui = new Windows.Media.Capture.CameraCaptureUI();

    await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal,
        () => {
            ccui.PhotoSettings.AllowCropping = true;
        });
}

Dim ccui As Windows.Media.Capture.CameraCaptureUI

Private Async Sub Button_Click_3(sender As Object, e As RoutedEventArgs)

    ccui = New Windows.Media.Capture.CameraCaptureUI()

    Await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal,
                                Sub()
                                    ccui.PhotoSettings.AllowCropping = True
                                End Sub)
End Sub

Objekty z komponenty prostředí Windows Runtime napsané v jazyce C++

Ve výchozím nastavení jsou třídy v komponentě, které lze aktivovat, agilní. Jazyk C++ však umožňuje značné množství kontroly nad modely podprocesů a řízením přenosu. Jak je popsáno výše v tomto článku, CLR rozpozná agilní třídy, pokusí se zařadit volání, pokud třídy nejsou agilní, a vyvolá System.InvalidCastException výjimku, pokud třída neobsahuje žádné informace o zařazování.

U objektů, které běží ve vlákně uživatelského rozhraní a vyvolávají výjimky, když jsou volány z jiného vlákna než z vlákna uživatelského rozhraní, můžete použít objekt CoreDispatcher vlákna uživatelského rozhraní k odeslání volání.

Viz také

Průvodce jazykem C#

Průvodce jazykem Visual Basic