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>

image

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>

image

 

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.

 

 

 

Technorati Tags: ,