DarioSantarelli.Blog("UgiDotNet");

<sharing mode=”On” users=”*” />
posts - 176, comments - 105, trackbacks - 3

My Links

News


This is my personal blog. These postings are provided "AS IS" with no warranties, and confer no rights.




Tag Cloud

Archives

Post Categories

My English Blog

[WPF] Window non rettangolari

La possibilità di creare Window di forma irregolare costituisce a mio modo di vedere uno dei più divertenti nonché semplici vantaggi di WPF.
In genere, ogni tecnica di realizzazione di Window dalla forma completamente personalizzata si basa sulla valorizzazione preliminare di tre proprietà:

In questo modo siamo subito svincolati sia dalla forma rettangolare standard della nostra Window, che dalla barra standard del titolo. Si aprono quindi diverse possibilità di sviluppo. E’ possibile ad esempio sfruttare immagini semitrasparenti come background della Window (scelta semplice e di veloce realizzazione, ma non consigliabile in WPF dal momento che la Window subirebbe un rendering con più pixel in sistemi con maggiori DPIs). Una soluzione sicuramente più potente sfrutta invece il programming model che WPF ci mette a disposizione relativamente alla grafica vettoriale: in altre parole, per creare una Window dai bordi arrotondati basta partire dall’elemento Border.
Vorrei riportare un esempio che mi è rimasto impresso dopo aver letto il libro “Pro WPF in C# 2008” : creare una Window dalla forma irregolare, con bordi arrotondati.
N.B.: tralascio volutamente ogni questione di carattere architetturale ( es. realizzazione di custom control template per le nostre Window ).


 

Codice XAML:

<Window x:Class="WPF_Demo.ShapedWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        ...     
       
AllowsTransparency
="True" WindowStyle="None" Background="Transparent" ResizeMode="CanResizeWithGrip">
       
<Border ... CornerRadius="0,20,30,20">      
       
<Grid>
         
<Grid.RowDefinitions>
            
<RowDefinition Height="Auto"></RowDefinition>
            
<RowDefinition></RowDefinition>
            
<RowDefinition Height="Auto"></RowDefinition>
         
</Grid.RowDefinitions>    
        
       
<TextBlock Text="Title" ... MouseLeftButtonDown="WindowDragMove"></TextBlock>
       
<Button ... Command="Close">
          
<Button.Content>
             
<Image Source="..." Stretch="Fill"></Image>
          
</Button.Content>
       
</Button>

       
<Grid Grid.Row="1" Background="White">
           
<Rectangle Grid.RowSpan="3" Width="5" VerticalAlignment="Stretch" HorizontalAlignment="Right"
                      
Cursor="SizeWE" Fill="Transparent"
                      
MouseLeftButtonDown="BeginWindowResize"
                      
MouseLeftButtonUp="EndWindowResize"
                      
MouseMove="WindowResize">                   
            
</Rectangle>
            
<TextBlock VerticalAlignment="Center" HorizontalAlignment="Center"...>Body</TextBlock>
       
</Grid>
       
<TextBlock Grid.Row="2" Text="Footer" ...></TextBlock>
     
</Grid>
   
</Border>
</Window>


Code-behind (interaction logic):

public partial class ShapedWindow : Window
{
 
private bool _isResizing = false;
 
public ShapedWindow()
 
{
   
InitializeComponent();
   
CommandBinding binding = new CommandBinding(ApplicationCommands.Close);
   
binding.Executed += CloseWindow;
   
this.CommandBindings.Add(binding);
 
}

 
private void CloseWindow(object sender, RoutedEventArgs e) { this.Close(); }

 
private void BeginWindowResize(object sender, MouseButtonEventArgs e) { _isResizing = true; }

 
private void EndWindowResize(object sender, MouseButtonEventArgs e)
 
{
   
_isResizing = false;
   
Rectangle rectangle = (Rectangle)sender;
   
rectangle.ReleaseMouseCapture();
 
}       

 
private void WindowResize(object sender, MouseEventArgs e)
 
{
   
Rectangle rectangle = (Rectangle)sender;
   
if (_isResizing)
   
{
     
rectangle.CaptureMouse();
     
double newWidth = e.GetPosition(this).X + 5;
     
if (newWidth > 0) this.Width = newWidth;
   
}
  
}

 
private void WindowDragMove(object sender, MouseButtonEventArgs e)
 
{           
   
if (e.ClickCount == 2) this.WindowState = (this.WindowState == WindowState.Maximized) ? WindowState.Normal : WindowState.Maximized;
   
else this.DragMove();   
 
}      
}


Si nota subito che in una soluzione di questo tipo (non poteva essere altrimenti) è compito dello sviluppatore gestire sia il resize che il move della Window, dal momento che è assente la barra del titolo standard che l’utente usa comunemente per interagire con la finestra stessa.
Differentemente dal mondo Windows Forms, in WPF è possibile gestire la modalità di dragging della Window semplicemente invocando il metodo Window.DragMove() , che in questo caso specifico viene usato in corrispondenza dell’evento MouseLeftButtonDown scatenato sul TextBlock che funge da barra del titolo ( due click consecutivi invece “massimizzano” o “normalizzano” la finestra ;) ).
Per quanto riguarda invece il resize, la questione diventa un po’ più “complessa”. Anzitutto, impostare la proprietà Window.ResizeMode a CanResizeWithGrip significa far apparire il sizing grip nell’angolo in basso a destra assumendo che la window sia comunque rettangolare. Questo significa quindi che esso può apparire o troppo distante o addirittura sopra l’effettivo bordo della Window. 
Se non si vuole scegliere questo tipo di approccio, bensì si desidera poter ridimensionare manualmente la finestra interagendo con i suoi bordi effettivi, esistono due strade: o si utilizzano P/Invoke che inviano messaggi Win32 per ridimensionare la window, oppure più semplicemente (come in questo caso) si gestisce la posizione e l’azione scatenata dal mouse in ogni bordo che si vuole utilizzare per ridimensionare la finestra, andando poi a gestire di conseguenza la proprietà Width.
Nell’esempio, si è scelto di posizionare un Rectangle trasparente di larghezza 5 in corrsipondenza del lato destro della finestra. In questo modo gli opportuni event handler (MouseLeftButtonDown, MouseLeftButtonUp, MouseMove) ci permettono di gestire il resize manuale della window ogni volta che il mouse interagisce con il bordo destro della stessa.

 

Technorati Tag:

Print | posted on sabato 26 settembre 2009 16:23 | Filed Under [ WPF ]

Comments have been closed on this topic.

Powered by:
Powered By Subtext Powered By ASP.NET