Kommentar
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
I den här artikeln beskrivs hur .NET Framework hanterar anrop från C# och Visual Basic-kod till objekt som tillhandahålls av Windows Runtime eller av Windows Runtime-komponenter.
I .NET Framework kan du komma åt alla objekt från flera trådar som standard, utan särskild hantering. Allt du behöver är en referens till objektet. I Windows Runtime kallas sådana objekt agile. De flesta Windows Runtime-klasser är flexibla, men några klasser är det inte, och även agila klasser kan kräva särskild hantering.
När det är möjligt behandlar CLR (Common Language Runtime) objekt från andra källor, till exempel Windows Runtime, som om de vore .NET Framework-objekt:
Om objektet implementerar IAgileObject-gränssnittet eller har attributet MarshalingBehaviorAttribute med MarshalingType.Agile behandlar CLR det som agilt.
Om CLR kan konvertera ett anrop från tråden där det gjordes till målobjektets trådkontext gör den det transparent.
Om objektet har attributet MarshalingBehaviorAttribute med MarshalingType.Nonetillhandahåller klassen inte information om marskalkning. CLR kan inte marshalla anropet, så det kastar ett InvalidCastException--undantag med ett meddelande som anger att objektet endast kan användas i den trådkontext där det skapades.
I följande avsnitt beskrivs hur det här beteendet påverkar objekt från olika källor.
Objekt från en Windows Runtime-komponent som är skriven i C# eller Visual Basic
Alla typer i komponenten som kan aktiveras är agila som standard.
Anmärkning
Flexibilitet innebär inte trådsäkerhet. I både Windows Runtime och .NET Framework är de flesta klasser inte trådsäkra eftersom trådsäkerhet har en prestandakostnad, och de flesta objekt används aldrig av flera trådar. Det är mer effektivt att synkronisera åtkomsten till enskilda objekt (eller endast använda trådsäkra klasser) efter behov.
När du skapar en Windows Runtime-komponent kan du åsidosätta standardinställningen. Se gränssnittet ICustomQueryInterface och gränssnittet IAgileObject .
Objekt från Windows Runtime
De flesta klasser i Windows Runtime är flexibla och CLR behandlar dem som flexibla. Dokumentationen för dessa klasser listar "MarshalingBehaviorAttribute(Agile)" bland klassattributen. Medlemmar i vissa av dessa agila klasser, till exempel XAML-kontroller, utlöser dock undantag om de inte anropas i användargränssnittstråden. Följande kod försöker till exempel använda en bakgrundstråd för att ange en egenskap för knappen som klickades. Knappens egenskap Content utlöser ett undantag.
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
Du kan komma åt knappen på ett säkert sätt med hjälp av dess Dispatcher-egenskap eller Dispatcher egenskapen för alla objekt som finns i kontexten för användargränssnittstråden (till exempel sidan som knappen är på). Följande kod använder CoreDispatcher-objektetsRunAsync-metod för att skicka anropet till användargränssnittstråden.
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
Anmärkning
Egenskapen Dispatcher utlöser inget undantag när den anropas från en annan tråd.
Livslängden för ett Windows Runtime-objekt som skapas i användargränssnittstråden begränsas av trådens livslängd. Försök inte komma åt objekt i en gränssnittstråd när fönstret har stängts.
Om du skapar en egen kontroll genom att ärva en XAML-kontroll, eller genom att skapa en uppsättning XAML-kontroller, är kontrollen flexibel eftersom den är ett .NET Framework-objekt. Men om den anropar medlemmar i dess basklass eller konstituerande klasser, eller om du anropar ärvda medlemmar, utlöser dessa medlemmar undantag när de anropas från alla trådar utom användargränssnittstråden.
Klasser som inte kan konverteras
Windows Runtime-klasser som inte tillhandahåller marskalkningsinformation har attributet MarshalingBehaviorAttribute med MarshalingType.None. Dokumentationen för en sådan klass listar "MarshalingBehaviorAttribute(None)" bland dess attribut.
Följande kod skapar ett CameraCaptureUI objekt i användargränssnittstråden och försöker sedan ange en egenskap för objektet från en tråd i trådpoolen. CLR kan inte konvertera anropet och genererar ett System.InvalidCastException undantag med ett meddelande som anger att objektet endast kan användas i trådkontexten där det skapades.
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
Dokumentationen för CameraCaptureUI visar även "ThreadingAttribute(STA)" bland klassens attribut, eftersom den måste skapas i en kontext med en tråd, till exempel användargränssnittstråden.
Om du vill komma åt CameraCaptureUI-objekt från en annan tråd kan du cachelagra CoreDispatcher-objektet för UI-tråden och använda det senare för att skicka anropet på den tråden. Eller så kan du hämta avsändaren från ett XAML-objekt, till exempel sidan, som du ser i följande kod.
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
Objekt från en Windows Runtime-komponent som är skriven i C++
Som standard är klasserna i komponenten som kan aktiveras flexibla. C++ tillåter dock en betydande mängd kontroll över trådningsmodeller och marskalkeringsbeteende. Som vi beskrev tidigare i den här artikeln identifierar CLR agila klasser, försöker marskalkera anrop när klasser inte är agila och genererar ett System.InvalidCastException-undantag när en klass saknar information om marskalkering.
För objekt som körs i användargränssnittstråden och utlöser undantag när de anropas från en annan tråd än användargränssnittstråden kan du använda UI-trådens CoreDispatcher-objekt för att skicka anropet.