Utilizando ChildWindows de forma síncrona
Um problema que me deparo constantemente é a necessidade de abrir um ChildWindow qualquer e continuar a execução do código a partir do retorno deste. Claro que é possível fazer isto utilizando Actions e eventos, mas não seria muito melhor que trabalhasse de forma semelhante ao MessageBox do WinForms?
Antes de começar é necessário instalar o Visual Studio Async CTP pois ele nos da a possibilidade de trabalhar de forma Assíncrona/Síncrona.
Primeiro criaremos um novo projeto com o template Silverlight Application. Dentro do projeto crie um novo item utilizando o template ChildWindow, e de-lhe o nome de ChildWindowSync.
Criaremos então um método estático que será responsável por mostrar a nossa window conforme o código abaixo:
public static Task<bool> ShowSync()
{
var tcs = new TaskCompletionSource<bool>();
var window = new ChildWindowSync();
window.Closed += (sender, e) => {
tcs.TrySetResult(window.DialogResult.Value);
};
window.Show();
return tcs.Task;
}
Veja que é bastante simples, criamos um objeto TaskCompletionSource que será a task retornada quando nossa window for fechada, após este passo a janela é criada e adicionamos um eventHandler ao evento de closed. Dentro deste handler setamos o dialogResult que foi definido pelos métodos de button click do Ok e Cancel;
Neste momento seu código deve estar parecido com o abaixo:
public partial class ChildWindowSync : ChildWindow
{
public ChildWindowSync()
{
InitializeComponent();
}
private void OKButton_Click(object sender, RoutedEventArgs e)
{
this.DialogResult = true;
}
private void CancelButton_Click(object sender, RoutedEventArgs e)
{
this.DialogResult = false;
}
public static Task<bool> ShowSync()
{
var tcs = new TaskCompletionSource<bool>();
var window = new ChildWindowSync();
window.Closed += (sender, e) => {
tcs.TrySetResult(window.DialogResult.Value);
};
window.Show();
return tcs.Task;
}
}
Agora criaremos um botão na MainPage.xaml que irá chamar nossa ChildWindowSync.
<UserControl x:Class="SilverlightApplication2.MainPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 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="LayoutRoot" Background="White"> <Button x:Name="testebtn" Content="Open window" Click="testebtn_Click" VerticalAlignment="Center" HorizontalAlignment="Center"/> </Grid> </UserControl>
O async ctp exige que seja utilizado a palavra reservada “async” nos métodos que utilizam chamadas assíncronas em seu corpo. No caso a assinatura do método testbtn_Click fica da seguinte forma:
private async void testebtn_Click(object sender, RoutedEventArgs e)
então colocamos o corpo do nosso método para esperar ate que a childWindow seja fechada e retornar se o DialogResult foi True ou False
private async void testebtn_Click(object sender, RoutedEventArgs e)
{
bool teste = await ChildWindowSync.ShowSync();
if (teste)
{
MessageBox.Show("Você Clicou em Ok!");
}
else
{
MessageBox.Show("Você clicou em Cancel!");
}
}
Rode a aplicação e veja o resultado. Você verá que ao clicar no nosso botão de teste a child window é exibida e o resultado é exibido somente depois da janela ter um resultado: true se for clicado em Ok e False se for clicado em Cancel ou fechar a janela pelo X.
O código fonte deste exemplo pode ser baixado aqui.