Nota
O acesso a esta página requer autorização. Pode tentar iniciar sessão ou alterar os diretórios.
O acesso a esta página requer autorização. Pode tentar alterar os diretórios.
Este artigo discute a maneira como o .NET Framework lida com chamadas de código C# e Visual Basic para objetos fornecidos pelo Tempo de Execução do Windows ou por componentes do Tempo de Execução do Windows.
No .NET Framework, você pode acessar qualquer objeto de vários threads por padrão, sem manipulação especial. Tudo o que você precisa é de uma referência ao objeto. No Windows Runtime, tais objetos são chamados de agile. A maioria das classes do Tempo de Execução do Windows é ágil, mas algumas classes não são, e até mesmo as classes ágeis podem exigir tratamento especial.
Sempre que possível, o Common Language Runtime (CLR) trata objetos de outras fontes, como o Tempo de Execução do Windows, como se fossem objetos do .NET Framework:
Se o objeto implementa a interface IAgileObject ou tem o atributo MarshalingBehaviorAttribute com MarshalingType.Agile, o CLR o trata como ágil.
Se o CLR puder organizar uma chamada do thread onde ela foi feita para o contexto de threading do objeto de destino, ele o fará de forma transparente.
Se o objeto tiver o atributo MarshalingBehaviorAttribute com MarshalingType.None, a classe não fornecerá informações de marshaling. O CLR não pode organizar a chamada, portanto, ele lança uma exceção InvalidCastException com uma mensagem indicando que o objeto pode ser usado somente no contexto de threading onde foi criado.
As seções a seguir descrevem os efeitos desse comportamento em objetos de várias fontes.
Objetos de um componente do Tempo de Execução do Windows escrito em C# ou Visual Basic
Todos os tipos no componente que podem ser ativados são ágeis por padrão.
Observação
Agilidade não implica segurança de fios. No Windows Runtime e no .NET Framework, a maioria das classes não é thread-safe porque a segurança de execução tem um custo de desempenho, e a maioria dos objetos nunca é acessada por vários threads. É mais eficiente sincronizar o acesso a objetos individuais (ou usar classes thread-safe) apenas conforme necessário.
Ao criar um componente do Tempo de Execução do Windows, pode-se sobrescrever o padrão. Consulte a interface ICustomQueryInterface e a interface IAgileObject.
Objetos do Tempo de Execução do Windows
A maioria das classes no Tempo de Execução do Windows é ágil e o CLR as trata como ágeis. A documentação para essas classes lista "MarshalingBehaviorAttribute(Agile)" entre os atributos de classe. No entanto, os membros de algumas dessas classes ágeis, como controles XAML, lançam exceções se não forem chamados no thread da interface do usuário. Por exemplo, o código a seguir tenta usar um thread em segundo plano para definir uma propriedade do botão que foi clicado. A propriedade Content do botão gera uma exceção.
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
Você pode acessar o botão com segurança usando sua propriedade
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
Observação
A propriedade Dispatcher não lança uma exceção quando é chamada de outro thread.
O tempo de vida de um objeto do Tempo de Execução do Windows criado no thread da interface do usuário é limitado pelo tempo de vida do thread. Não tente acessar objetos em um thread da interface do usuário depois que a janela for fechada.
Se você criar seu próprio controle herdando um controle XAML ou compondo um conjunto de controles XAML, seu controle será ágil porque é um objeto do .NET Framework. No entanto, se ele chamar membros de sua classe base ou classes constituintes, ou se você chamar membros herdados, esses membros lançarão exceções quando forem chamados de qualquer thread, exceto o thread da interface do usuário.
Classes que não podem ser organizadas
As classes do Tempo de Execução do Windows que não fornecem informações de marshaling têm o atributo MarshalingBehaviorAttribute com MarshalingType.None. A documentação para tal classe lista "MarshalingBehaviorAttribute(None)" entre seus atributos.
O código a seguir cria um objeto CameraCaptureUI no thread da interface do usuário e, em seguida, tenta definir uma propriedade do objeto a partir de um thread do pool de threads. O CLR não consegue organizar a chamada e lança uma exceção System.InvalidCastException com uma mensagem indicando que o objeto pode ser usado somente no contexto de threading onde foi criado.
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
A documentação do CameraCaptureUI também lista "ThreadingAttribute(STA)" entre os atributos da classe, porque esta deve ser criada em um contexto de thread único, como o thread da interface do utilizador.
Se quiser acessar o objeto CameraCaptureUI do
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
Objetos de um componente do Tempo de Execução do Windows escrito em C++
Por padrão, as classes no componente que podem ser ativadas são ágeis. No entanto, o C++ permite uma quantidade significativa de controle sobre modelos de threading e comportamento de marshaling. Conforme descrito anteriormente neste artigo, o CLR reconhece classes ágeis, tenta gerir chamadas quando as classes não são ágeis e lança uma exceção System.InvalidCastException quando uma classe não tem informações de marshalização.
Para objetos que são executados no thread da interface do usuário e lançam exceções quando são chamados de um thread diferente do thread da interface do usuário, você pode usar o objeto CoreDispatcher CoreDispatcher do thread da interface do usuário para despachar a chamada.
Ver também
Guia C#