Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
In diesem Artikel wird erläutert, wie .NET Framework Aufrufe von C#- und Visual Basic-Code für Objekte verarbeitet, die von der Windows-Runtime oder von Komponenten für Windows-Runtime bereitgestellt werden.
Im .NET Framework können Sie standardmäßig auf jedes Objekt aus mehreren Threads zugreifen, ohne dass spezielle Verarbeitung erfolgt. Sie benötigen lediglich einen Verweis auf das Objekt. In der Windows-Runtime werden solche Objekte agilegenannt. Die meisten Windows-Runtime-Klassen sind flexibel, aber einige Klassen sind es nicht, und selbst flexible Klassen erfordern möglicherweise eine spezielle Behandlung.
Nach Möglichkeit behandelt die Common Language Runtime (CLR) Objekte aus anderen Quellen, z. B. die Windows-Runtime, als wären sie .NET Framework-Objekte:
Wenn das Objekt die IAgileObject--Schnittstelle implementiert oder das MarshalingBehaviorAttribute--Attribut mit MarshalingType.Agileaufweist, behandelt die CLR es als agil.
Wenn CLR einen Aufruf vom Thread, in dem er ausgeführt wurde, in den Threadingkontext des Zielobjekts übertragen kann, geschieht dies transparent.
Wenn das Objekt das MarshalingBehaviorAttribute Attribut mit MarshalingType.Noneaufweist, stellt die Klasse keine Marshallinginformationen bereit. Die CLR kann den Aufruf nicht marshallen, daher wird eine InvalidCastException-Ausnahme mit einer Meldung ausgelöst, die angibt, dass das Objekt nur im Thread-Kontext verwendet werden kann, in dem es erstellt wurde.
In den folgenden Abschnitten werden die Auswirkungen dieses Verhaltens auf Objekte aus verschiedenen Quellen beschrieben.
Objekte aus einer Komponente für Windows-Runtime, die in C# oder Visual Basic geschrieben wurde
Alle Typen in der Komponente, die aktiviert werden können, sind standardmäßig agil.
Hinweis
Agilität impliziert keine Threadsicherheit. Sowohl in der Windows-Runtime als auch im .NET Framework sind die meisten Klassen nicht threadsicher, da die Threadsicherheit leistungseinbußen hat, und die meisten Objekte werden nie von mehreren Threads aufgerufen. Es ist effizienter, den Zugriff auf einzelne Objekte oder die Verwendung threadsicherer Klassen nur bei Bedarf zu synchronisieren.
Wenn Sie eine Komponente für Windows-Runtime erstellen, können Sie die Standardeinstellung außer Kraft setzen. Siehe die ICustomQueryInterface Schnittstelle und die IAgileObject Schnittstelle.
Objekte aus der Windows-Runtime
Die meisten Klassen in der Windows-Runtime sind agil, und die CLR betrachtet sie als solche. Die Dokumentation für diese Klassen listet "MarshalingBehaviorAttribute(Agile)" unter den Klassenattributen auf. Jedoch lösen die Mitglieder einiger dieser agilen Klassen, wie etwa den XAML-Steuerelementen, Ausnahmen aus, wenn sie nicht im UI-Thread aufgerufen werden. Der folgende Code versucht beispielsweise, einen Hintergrundthread zu verwenden, um eine Eigenschaft der Schaltfläche festzulegen, auf die geklickt wurde. Die Eigenschaft "Content" der Schaltfläche löst eine Ausnahme aus.
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
Sie können sicher auf die Schaltfläche zugreifen, indem Sie dessen Dispatcher--Eigenschaft oder die Dispatcher
-Eigenschaft eines Objekts verwenden, das im Kontext des UI-Threads vorhanden ist (z. B. die Seite, auf der sich die Schaltfläche befindet). Der folgende Code verwendet die
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
Hinweis
Die Dispatcher
Eigenschaft löst keine Ausnahme aus, wenn sie von einem anderen Thread aufgerufen wird.
Die Lebensdauer eines Windows-Runtime-Objekts, das im UI-Thread erstellt wird, ist an die Lebensdauer des Threads gebunden. Versuchen Sie nicht, auf Objekte in einem UI-Thread zuzugreifen, nachdem das Fenster geschlossen wurde.
Wenn Sie ein eigenes Steuerelement erstellen, indem Sie ein XAML-Steuerelement erben oder eine Gruppe von XAML-Steuerelementen erstellen, ist Ihr Steuerelement agil, da es sich um ein .NET Framework-Objekt handelt. Wenn Sie jedoch Member der Basisklasse oder der bestandteilenden Klassen aufrufen oder geerbte Member aufrufen, lösen diese Member Ausnahmen aus, wenn sie von einem beliebigen Thread außer dem UI-Thread aufgerufen werden.
Klassen, die nicht gemarstet werden können
Windows-Runtime-Klassen, die keine Marshaling-Informationen bereitstellen, weisen das MarshalingBehaviorAttribute Attribut mit MarshalingType.Noneauf. Die Dokumentation für eine solche Klasse listet "MarshalingBehaviorAttribute(None)" unter seinen Attributen auf.
Der folgende Code erstellt ein CameraCaptureUI--Objekt im UI-Thread und versucht dann, eine Eigenschaft des Objekts aus einem Threadpoolthread festzulegen. Die CLR kann den Aufruf nicht marshallen und löst eine System.InvalidCastException Ausnahme mit einer Meldung aus, die angibt, dass das Objekt nur im Threadingkontext verwendet werden kann, in dem es erstellt wurde.
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
Die Dokumentation für CameraCaptureUI- listet auch "ThreadingAttribute(STA)" unter den Attributen der Klasse auf, da sie in einem Single-Thread-Kontext wie dem UI-Thread erstellt werden muss.
Wenn Sie von einem anderen Thread aus auf das CameraCaptureUI-Objekt zugreifen möchten, können Sie das CoreDispatcher-Objekt für den UI-Thread zwischenspeichern und später verwenden, um den Aufruf für diesen Thread zu verteilen. Oder Sie können den Dispatcher von einem XAML-Objekt wie einer Seite abrufen, wie im folgenden Code dargestellt.
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
Objekte aus einer Komponente für Windows-Runtime, die in C++ geschrieben wurde
Standardmäßig sind Klassen in der Komponente, die aktiviert werden können, agil. C++ ermöglicht jedoch eine erhebliche Kontrolle über Threadingmodelle und Marshallingverhalten. Wie weiter oben in diesem Artikel beschrieben, erkennt die CLR agile Klassen, versucht, Aufrufe zu marshallen, wenn Klassen nicht agil sind, und löst eine System.InvalidCastException Ausnahme aus, wenn eine Klasse keine Marshaling-Informationen enthält.
Bei Objekten, die im UI-Thread ausgeführt werden und Ausnahmen auslösen, wenn sie von einem anderen Thread als dem UI-Thread aufgerufen werden, können Sie das CoreDispatcher-Objekt des UI-Threads verwenden, um den Aufruf zu verteilen.