Durante lo sviluppo di un applicazione Silverlight 2.0 è probabile che vi siate trovati di fronte alla necessità di visualizzare all’utente una dialog-window.
Quello che in WPF si realizza con una semplice chiamata al metodo ShowDialog in Silverlight richiede un pò di lavoro in quanto è necessario visualizzare un popup posizionandolo sopra la finestra attuale.
Visto che anche in Silverlight è applicabile il pattern Model-View-ViewModel, perchè non approfittarne?
Definiamo il ViewModel che governerà la vita della nostra finestra, popup incluso:
public class PopupViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private string name = "Hello!";
private bool isOpen;
public PopupViewModel()
{
App.Current.Host.Content.Resized += this.HandleContentResized;
this.IsOpen = false;
}
public double CurrentWidth { get; set; }
public double CurrentHeight { get; set; }
public bool IsEnabled { get; set; }
public bool IsOpen
{
get { return isOpen; }
set
{
this.isOpen = value;
this.IsEnabled = !this.isOpen;
this.OnPropertyChanged(null);
}
}
public string Name
{
get { return name; }
set
{
name = value;
this.OnPropertyChanged("Name");
}
}
protected void OnPropertyChanged(string propertyName)
{
if (this.PropertyChanged != null) this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
private void HandleContentResized(object sender, System.EventArgs e)
{
this.CurrentWidth = App.Current.Host.Content.ActualWidth;
this.CurrentHeight = App.Current.Host.Content.ActualHeight;
this.OnPropertyChanged(null);
}
}
Il ViewModel espone le proprietà:
- Open
- Determina quando il popup deve essere visualizzato.
- Name
- Una semplice informazione condivisa tra il chiamante e la dialog-window.
- IsEnabled
- E’ la negazione di IsOpen, server per disabilitare il chiamante cosi che non riceva il focus quando il popup è aperto e l’utente preme Tab (In Silverlight non è possibile usare l’attached property KeyboardNavigation.TabNavigation )
- CurrentWidth e CurrentHeight
- Rappresentano l’attuale dimensione della browser client area
Definiamo ora il popup:
<UserControl x:Class="PopupWindow.PopupDialog"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="Auto" Height="Auto">
<Grid Background="#80000000" x:Name="LayoutRoot">
<Grid.RowDefinitions>
<RowDefinition Height="0.5*"/>
<RowDefinition Height="Auto" />
<RowDefinition Height="0.5*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.4*"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="0.4*"/>
</Grid.ColumnDefinitions>
<Border Grid.Column="1" Grid.Row="1" Background="#FF0A1972" BorderBrush="#FFFAB40E" BorderThickness="3,3,3,3" CornerRadius="10,10,10,10">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="0.5*"/>
<RowDefinition Height="0.5*"/>
</Grid.RowDefinitions>
<ToggleButton IsChecked="{Binding Mode=TwoWay, Path=IsOpen}"
HorizontalAlignment="Stretch" Margin="104,24,104,24" Grid.Row="1" Content="Ok" />
<TextBox Text="{Binding Name, Mode=TwoWay}" Margin="68,25,68,25" />
</Grid>
</Border>
</Grid>
</UserControl>
Per semplicità ho usato un ToggleButton così da evitare l’implementazione di ICommand in Silverlight, ho bindato la textbox alla proprietà Name del ViewModel e ho impostato il canale Alpha del Background a 0x80 per dare l’effetto “semitrasparente” visto che, a tutti gli effetti, lo UserControl popup andrà a coprire interamente il chiamante.
Dall’immagine a fianco, che rappresenta lo xaml precedente, notate come le colonne della griglia siano configurate in modo da occupare tutta l’area disponibile.
A questo punto non ci rimane che implementare il chiamante della dialog-window:
<UserControl x:Class="PopupWindow.Page"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:this="clr-namespace:PopupWindow"
IsEnabled="{Binding IsEnabled}" >
<UserControl.DataContext>
<this:PopupViewModel />
</UserControl.DataContext>
<Grid x:Name="LayoutRoot" Background="White" Width="Auto" Height="Auto" >
<TextBlock Text="{Binding Name}"
Height="Auto" Margin="18,26,18,0" VerticalAlignment="Top" TextAlignment="Center" />
<ToggleButton IsChecked="{Binding Path=IsOpen, Mode=TwoWay}"
Width="150" Height="50"
Margin="151,109,147,116"
Content="Click to open" />
<Popup x:Name="popupDialog" IsOpen="{Binding IsOpen}">
<Grid>
<this:PopupDialog Width="{Binding CurrentWidth}"
Height="{Binding CurrentHeight}" />
</Grid>
</Popup>
</Grid>
</UserControl>
Anche in questo caso il ToggleButton è bindato alla proprietà IsOpen dell’istanza del ViewModel associato al DataContext dello UserControl così come lo è la proprietà IsOpen del Popup simulando sotto certi aspetti l’ Element Binding di WPF (non presente in Silverlight)
A questo punto, lanciando il progetto basta premere il button per aprire il popup e premere Ok per richiuderlo.