Confessions of a Dangerous Mind

Brain.FlushBuffer()
posts - 176, comments - 234, trackbacks - 93

WPF Cookbook: Vista Glass Effect!

Vi piace quell’effetto di vetro semitrasparente che contraddistingue l’interfaccia Aero di Windows Vista e di Windows 7? Con WPF è possibile utilizzarla nelle proprie applicazioni, per offrire una tocco in più che spesso fa innamorare  i nostri utenti… è necessario tirare fuori alcune API, ma non c’è nulla di veramente complicato. In effetti ci sono solamente due limiti all’utilizzo di questa funzionalità:

  • la “glass area” si estende sempre dai bordi della finestra verso l’interno della stessa;
  • non è possibile creare zone vetrificate isolate (a macchia di leopardo, tanto per intenderci) nella client area della finestra;

Vediamo per prima cosa le API da importare, che provengono dalla dll DwmApi.dll (non presente in Windows XP!)

   1: [StructLayout(LayoutKind.Sequential)]
   2: public struct Margins
   3: {
   4:     public int cxLeftWidth; 
   5:     public int cxRightWidth; 
   6:     public int cyTopHeight; 
   7:     public int cyBottomHeight; 
   8: }
   9:  
  10: [DllImport("DwmApi.dll")]
  11: private static extern int DwmExtendFrameIntoClientArea(IntPtr hwnd, ref Margins margins);

La chiamata alla DwmExtendFrameIntoClientArea consente di estendere i “bordi” della finestra all’interno della finestra stessa. I valori –1 dei margini hanno il particolare significato di estendere l’effetto vetro all’interno di tutta la client area della window.

Sempre nella classe Glassificator, ho creato due metodi:

  • il primo necessario per impostare correttamente i margini basandosi sui Dpi correnti del sistema;
  • il secondo è un helper che consente con una singola chiamata di impostare l’effetto vetro desiderato su una finestra;
   1: private static Margins GetDpiMargins(IntPtr hwnd, int left, int right, int top, int bottom)
   2: {
   3:     System.Drawing.Graphics g = System.Drawing.Graphics.FromHwnd(hwnd);
   4:     float _dpiX = g.DpiX;
   5:     float _dpiY = g.DpiY;
   6:  
   7:     Margins _margins = new Margins();
   8:     _margins.cxLeftWidth=Convert.ToInt32(left * (_dpiX / 96));
   9:     _margins.cxRightWidth=Convert.ToInt32(right * (_dpiX / 96));
  10:     _margins.cyTopHeight=Convert.ToInt32(top * (_dpiX / 96));
  11:     _margins.cyBottomHeight=Convert.ToInt32(bottom * (_dpiX / 96));
  12:  
  13:     return _margins;
  14: }
  15:  
  16: public static void Glassify(Window win, int left, int right, int top, int bottom)
  17: {
  18:     //Se siamo su Vista o Windows 7, allora possiamo procedere
  19:     if (Environment.OSVersion.Version.Major > 5)
  20:     {
  21:         WindowInteropHelper _helper = new WindowInteropHelper(win);
  22:         HwndSource _hSource = (HwndSource)HwndSource.FromHwnd(_helper.Handle);
  23:  
  24:         _hSource.CompositionTarget.BackgroundColor = Colors.Transparent;
  25:         win.Background = Brushes.Transparent;
  26:  
  27:         Margins _margins = GetDpiMargins(_helper.Handle, left, right, top, bottom);
  28:         int _retVal = DwmExtendFrameIntoClientArea(_helper.Handle, ref _margins);
  29:         if (_retVal < 0)
  30:             throw new NotSupportedException("Glassification not supported.");
  31:     }
  32: }

notare che è stata controllata la versione del sistema operativo in uso, in quanto se fossimo su Windows XP, questo effetto non sarebbe disponibile. Come utilizzare queste funzioni da una finestra? Molto semplice: creiamo una banale window senza preoccuparci del particolare effetto:

   1: <Window x:Class="GlassyWindow.Window1"
   2:     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   3:     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   4:     Title="Glass Window" Loaded="Window_Loaded" Width="300" Height="300">
   5:     <Grid>
   6:         <Button Content="Hello from the glass world!" Margin="50,100,50,100"/>
   7:     </Grid>
   8: </Window>

Nell’evento Loaded, interveniamo per modificare il comportamento della client area con una chiamata al metodo statico Glassify della classe Glassificator:

   1: public partial class Window1 : Window
   2: {
   3:    public Window1()
   4:    {
   5:        InitializeComponent();
   6:    }
   7:  
   8:    private void Window_Loaded(object sender, RoutedEventArgs e)
   9:    {
  10:        try
  11:        {
  12:            Glassificator.Glassify(this, -1, -1, -1, -1);
  13:        }
  14:        catch (Exception)
  15:        {
  16:            this.Background = Brushes.White;
  17:        }
  18:    }        
  19: }

Tutto qui! Come avete visto, quest’effetto piuttosto semplice da ottenere potrà sicuramente abbellire alcuni dei vostri progetti. Il codice del progetto lo potete trovare qui.

Print | posted on sabato 10 ottobre 2009 18:00 |

Comments have been closed on this topic.

Powered by:
Powered By Subtext Powered By ASP.NET