2012-11-16 15 views
7

ho creato una finestra senza bordi WPF impostando le seguenti proprietà della finestra in XAML:problemi WPF bordi della finestra: Aero Snap & Massimizzare

... WindowStyle="None" AllowsTransparency="True" ... 

Questo provoca una serie di questioni:

1) Risolto: Non ha più alcuna funzionalità di ridimensionamento incorporata

2) Risolto: Non ha più bu ILT-in funzionalità di trascinamento

3) risolto: Senza barra degli strumenti superiore, essa non ha più pulsanti di chiusura

4) risolto minimizzare/massimizzare/restore /: Massimizzare tramite scatto aero o impostazione impedisce WindowState da unsnapping.

5) Ingrandimento tramite snap aerodinamico o impostazione WindowState utilizzerà l'intero schermo come contorno, sovrapponendosi alla barra degli strumenti di Windows.

6) Massimizzazione tramite snap aerodinamico o impostazione WindowState sembra includere un margine -7, dando alla finestra 7 pixel su ciascun lato oltre i bordi della finestra.

1-3 sono stati risolti creando un modello di finestra xaml. Ho usato rettangoli invisibili come regioni di handle e un codice dietro a quello è stato applicato tramite l'override di OnApplyTemplate() per collegare le funzionalità tramite user32.dll SendMessage (...) per ridimensionare/spostare/minimizzare/ingrandire/ripristinare/chiudere.

ho trovato la risposta alla # 4 here

Ho provato a risolvere i 5-6 intercettando il messaggio di ingrandimento tramite WndProc e impostando le dimensioni/posizione manualmente, ma questo ha avuto il problema della sovrascrittura del RestoreRegion alle dimensioni massimizzata/position, rimuovendo la possibilità di ripristinare la finestra.

Ciò che è davvero strano è che il ridimensionamento della finestra dal bordo superiore alla parte superiore dello schermo fa scattare lo snap aero a tutta altezza senza problemi.

Quindi, ho fatto molta strada, ma il 5-6 è ancora un problema ... esiste un modo per specificare manualmente la regione di ingrandimento? Oppure, c'è un modo per impostare le dimensioni della finestra senza influenzare la proprietà restoreregion?

+0

Sarebbe bello se si aggiunge la soluzione 1-4 in una risposta .. – CularBytes

+0

distaccato, mi piacerebbe molto avere la risposta per # 4 – mgarant

risposta

2

È possibile specificare la regione ingrandimento gestendo il messaggio WM_GETMINMAXINFO Win32. Il codice here mostra come farlo. Risolverà i problemi n. 5 e n. 6.

Si noti che ci sono alcune cose che vorrei fare in modo diverso, ad esempio restituire IntPtr.Zero anziché (System.IntPtr) 0 in WindowProc e rendere MONITOR_DEFAULTTONEAREST una costante. Ma questo è solo la codifica delle modifiche di stile e non influisce sul risultato netto.

Assicurarsi inoltre di prestare attenzione all'aggiornamento in cui il WindowProc viene agganciato durante l'evento SourceInitialized anziché OnApplyTemplate. Questo è il posto migliore per farlo. Se stai implementando una classe derivata da Window, un'altra opzione è di ignorare OnSourceInitialized per agganciare lo WindowProc invece di collegarlo all'evento. Questo è quello che faccio normalmente.

3

Per Punto numero 5, utilizzare questo:

public WindowName() // Constructor for your window 
{ 
this.MaxHeight = SystemParameters.WorkArea.Height; 
this.MaxWidth = SystemParameters.WorkArea.Width; 
} 

Questo farà sì che la finestra non si sovrapporrà barra delle applicazioni quando ingrandita.

+2

Funziona solo se (a) si dispone di un solo monitor e (b) la barra delle applicazioni si trova sul bordo inferiore del monitor. Qualsiasi altra configurazione e fallisce. –

5

soluzione più facile completa

Ciao, La seguente soluzione fissa tutti i problemi descritti in tua domanda nel modo più semplice possibile, e funziona su Windows 10 utilizzando WPF e l'ultima versione del linguaggio C# e .NET framework. Questo è il 15/03/2017. Per favore fatemi sapere se smette di funzionare.

Fase 1: per affrontare le questioni 1, 2 e 4, i tuoi <Window ... > </Window> tag nella XAML della vostra applicazione, incollare questo in, in alto o in basso:

<WindowChrome.WindowChrome> 
    <WindowChrome CaptionHeight="35"/> 
<WindowChrome.WindowChrome> 

CaptionHeight è la altezza desiderata dell'area di trascinamento della finestra.

Passaggio 2: Per risolvere il problema 3, è necessario creare la barra del titolo e la didascalia, nonché i controlli della finestra. Per fare questo, devi semplicemente dare gli elementi della barra del titolo desiderati ciascuno di un VerticalAlignment of Top, o metterli in una griglia con il suo VerticalAlignment impostato su Top, che lo farà per tutti loro, ma assicurati che le loro altezze non siano superiore alla proprietà CaptionHeight sull'elemento WindowChrome dichiarato in XAML, dal passaggio 1. Per tutti i pulsanti, è necessario assegnare loro, o il loro contenitore, la proprietà WindowChrome.IsHitTestVisibleInChrome="True". Ecco un esempio:

<Grid VerticalAlignment="Top" Background="White" Name="TitleBar" Height="35"> 
    <Label Content="Borderless Window Test" VerticalAlignment="Center" HorizontalAlignment="Left"/> 
    <StackPanel WindowChrome.IsHitTestVisibleInChrome="True" VerticalAlignment="Center" HorizontalAlignment="Right" Orientation="Horizontal" Name="WindowControls"> 
     <Button Height="35" Width="35" Content="-" Padding="0" Name="MinimizeButton"/> 
     <Button Height="35" Width="35" Content="+" Padding="0" Name="MaximizeButton"/> 
     <Button Height="35" Width="35" Content="x" Padding="0" Name="CloseButton"/> 
    </StackPanel> 
</Grid> 

Ora, per aggiungere la corretta funzionalità per i pulsanti di controllo della finestra, all'interno della MainWindow() costruttore della vostra codebehind, il codice sorgente C# dell'applicazione, incolla il seguente in, dopo la chiamata a InitializeComponent();:

CloseButton.Click += (s, e) => Close(); 
MaximizeButton.Click += (s, e) => WindowState = WindowState == WindowState.Normal ? WindowState.Maximized : WindowState.Normal; 
MinimizeButton.Click += (s, e) => WindowState = WindowState.Minimized; 

Fase 3: per affrontare le questioni 5 e 6, è necessario collegare in WmGetMinMaxInfo. Per fare ciò, vai al tuo codebehind, quindi copia e incolla tutto da questo Pastebin nella tua classe Window.Ora, all'interno del vostro MainWindow() costruttore, pasta:

SourceInitialized += (s, e) => 
{ 
    IntPtr handle = (new WindowInteropHelper(this)).Handle; 
    HwndSource.FromHwnd(handle).AddHook(new HwndSourceHook(WindowProc)); 
}; 

Via Project > Add References nel menu file, assicurarsi di avere i riferimenti a:

System.Management 
System.Windows.Interop 
System.Security.Principal 
System.Runtime.InteropServices 
Microsoft.Win32 

Il modo migliore per controllare è quello di fare clic sulla scheda Assemblies in in alto a sinistra, quindi selezionare Framework, quindi utilizzare la casella di ricerca nell'angolo in alto a destra della finestra. A questo punto aggiungere tutte queste usings (namespace) alla parte superiore del vostro codebehind:

using System.Management; 
using System.Windows.Interop; 
using System.Security.Principal; 
using System.Runtime.InteropServices; 
using Microsoft.Win32; 

Questo dovrebbe coprire tutto. Spero che aiuti!

+0

Anche se personalmente ritengo che il riferimento a 'Microsoft.Win32' debba essere evitato (per motivi di trasferibilità, se non altro), apprezzo questa risposta. Sapevo di 'WindowChrome', ma solo il tuo post mi ha fatto capire che è molto più semplice da usare di quanto pensassi. – Informagic

+0

Non completamente perfetto in un multi monitor con diverse impostazioni di risoluzione, ma di gran lunga la soluzione migliore trovata finora! Mi è piaciuta molto la roba di WindowChrome in particolare – Bruno

0

Ho appena passato tutta questa cosa da solo. È stata una vera fatica, perché devi tener conto manualmente di così tanto. È divertente, diamo tanto per scontato in questi giorni, con qualcosa di semplice come funziona una finestra di base. Ma uno sguardo a questo esempio di codice che sto fornendo è una buona indicazione di quanto realmente vada in questo problema.

Spero che questo aiuti, poiché mi ci è voluto un po 'di tempo per arrivare da me.

MainWindow.xaml

<Window x:Class="WpfApp1.MainWindow" 
    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" 
    xmlns:local="clr-namespace:WpfApp1" 
    Background="Transparent" 
    WindowStartupLocation="CenterScreen" 
    ResizeMode="CanResizeWithGrip" 
    AllowsTransparency="True" 
    WindowStyle="None" 
    mc:Ignorable="d" 
    Title="Test Window Behavior" Height="768" Width="1024" StateChanged="Window_StateChanged" PreviewMouseLeftButtonDown="Window_PreviewMouseLeftButtonDown"> 

<Grid> 
    <DockPanel Grid.Column="1" Grid.Row="1"> 
     <DockPanel x:Name="titleBar" Background="White" DockPanel.Dock="Top"> 
      <Rectangle Width="32" Height="32" DockPanel.Dock="Left" Fill="Red" Margin="2"/> 
      <StackPanel Orientation="Horizontal" DockPanel.Dock="Right" Margin="2"> 

       <!-- Minimize Button --> 
       <Border Width="24" Height="24" Margin="2" HorizontalAlignment="Right" MouseLeftButtonUp="OnMinimizeWindow" Grid.Column="2"> 
        <Border.Style> 
         <Style TargetType="Border"> 
          <Setter Property="Background" Value="Transparent" /> 
          <Style.Triggers> 
           <Trigger Property="IsMouseOver" Value="True"> 
            <Setter Property="Background" Value="#FFD0D0D0" /> 
           </Trigger> 
          </Style.Triggers> 
         </Style> 
        </Border.Style> 
        <TextBlock FontSize="14" HorizontalAlignment="Center" VerticalAlignment="Center" Text="0" FontFamily="Webdings" /> 
       </Border> 

       <!-- Maximize Button --> 
       <Border Width="24" Height="24" Margin="2" HorizontalAlignment="Right" MouseLeftButtonUp="OnMaximizeWindow" Grid.Column="3"> 
        <Border.Style> 
         <Style TargetType="Border"> 
          <Setter Property="Background" Value="Transparent" /> 
          <Style.Triggers> 
           <Trigger Property="IsMouseOver" Value="True"> 
            <Setter Property="Background" Value="#FFD0D0D0" /> 
           </Trigger> 
          </Style.Triggers> 
         </Style> 
        </Border.Style> 
        <TextBlock x:Name="IsMaximized" FontSize="14" HorizontalAlignment="Center" VerticalAlignment="Center" FontFamily="Webdings"> 
         <TextBlock.Style> 
          <Style TargetType="TextBlock"> 
           <Setter Property="Text" Value="1" /> 
           <Style.Triggers> 
            <DataTrigger Binding="{Binding Path=InternalWindowState, RelativeSource={RelativeSource FindAncestor, AncestorType=Window}}" Value="Maximized"> 
             <Setter Property="Text" Value="2" /> 
            </DataTrigger> 
           </Style.Triggers> 
          </Style> 
         </TextBlock.Style> 
        </TextBlock> 
       </Border> 

       <!-- Close Button --> 
       <Border Width="24" Height="24" Margin="2" HorizontalAlignment="Right" MouseLeftButtonUp="OnCloseWindow" Grid.Column="4"> 
        <Border.Style> 
         <Style TargetType="Border"> 
          <Setter Property="Background" Value="Transparent" /> 
          <Style.Triggers> 
           <Trigger Property="IsMouseOver" Value="True"> 
            <Setter Property="Background" Value="Red" /> 
           </Trigger> 
          </Style.Triggers> 
         </Style> 
        </Border.Style> 
        <TextBlock FontSize="14" HorizontalAlignment="Center" VerticalAlignment="Center" Text="r" FontFamily="Webdings" /> 
       </Border> 
      </StackPanel> 

      <Label MouseLeftButtonDown="OnDragMoveWindow" MouseDoubleClick="OnMaximizeWindow" Margin="8 0 0 0" FontSize="12" VerticalContentAlignment="Center" Content="{Binding Path=Title, RelativeSource={RelativeSource FindAncestor, AncestorType=Window}, FallbackValue='Main Window'}" /> 
     </DockPanel> 

     <Grid Background="White" DockPanel.Dock="Bottom" Height="32"> 
      <Label VerticalContentAlignment="Center" Content="Statusbar Text Goes Here ..." /> 
     </Grid> 

     <Grid> 
      <Grid.ColumnDefinitions> 
       <ColumnDefinition Width="100" /> 
       <ColumnDefinition Width="*" /> 
       <ColumnDefinition Width="100" /> 
      </Grid.ColumnDefinitions> 
      <Grid.RowDefinitions> 
       <RowDefinition Height="100" /> 
       <RowDefinition Height="*" /> 
       <RowDefinition Height="100" /> 
      </Grid.RowDefinitions> 

      <!-- Top 3 --> 
      <Border Background="Gray" Grid.Row="0" Grid.Column="0" /> 
      <Border Background="Gray" Grid.Row="0" Grid.Column="1" BorderBrush="Black" BorderThickness="0 0 0 1" /> 
      <Border Background="Gray" Grid.Row="0" Grid.Column="2" /> 

      <!-- Middle 2 --> 
      <Border Background="Gray" Grid.Row="1" Grid.Column="0" BorderBrush="Black" BorderThickness="0 0 1 0" /> 
      <Border Background="Gray" Grid.Row="1" Grid.Column="2" BorderBrush="Black" BorderThickness="1 0 0 0" /> 

      <!-- Bottom 3 --> 
      <Border Background="Gray" Grid.Row="2" Grid.Column="0" /> 
      <Border Background="Gray" Grid.Row="2" Grid.Column="1" BorderBrush="Black" BorderThickness="0 1 0 0" /> 
      <Border Background="Gray" Grid.Row="2" Grid.Column="2" /> 
     </Grid> 
    </DockPanel> 
    <Grid> 
     <Grid.Resources> 
      <Style TargetType="Thumb"> 
       <Style.Setters> 
        <Setter Property="Template"> 
         <Setter.Value> 
          <ControlTemplate> 
           <Border Background="Transparent" /> 
          </ControlTemplate> 
         </Setter.Value> 
        </Setter> 
       </Style.Setters> 
      </Style> 
     </Grid.Resources> 
     <Grid.ColumnDefinitions> 
      <ColumnDefinition Width="25" /> 
      <ColumnDefinition Width="*" /> 
      <ColumnDefinition Width="25" /> 
     </Grid.ColumnDefinitions> 
     <Grid.RowDefinitions> 
      <RowDefinition Height="25" /> 
      <RowDefinition Height="*" /> 
      <RowDefinition Height="25" /> 
     </Grid.RowDefinitions> 

     <!-- Top/Left --> 
     <DockPanel LastChildFill="False" Grid.Row="0" Grid.Column="0"> 
      <Thumb DockPanel.Dock="Left" Width="4" Cursor="SizeNWSE" Tag="0" DragDelta="Thumb_DragDelta" /> 
      <Thumb DockPanel.Dock="Top" Height="4" Cursor="SizeNWSE" Tag="0" DragDelta="Thumb_DragDelta" /> 
     </DockPanel> 

     <!-- Top/Right --> 
     <DockPanel LastChildFill="False" Grid.Row="0" Grid.Column="2"> 
      <Thumb DockPanel.Dock="Right" Width="4" Cursor="SizeNESW" Tag="0" DragDelta="Thumb_DragDelta" /> 
      <Thumb DockPanel.Dock="Top" Height="4" Cursor="SizeNESW" Tag="0" DragDelta="Thumb_DragDelta" /> 
     </DockPanel> 

     <!-- Bottom/Left --> 
     <DockPanel LastChildFill="False" Grid.Row="2" Grid.Column="0"> 
      <Thumb DockPanel.Dock="Left" Width="4" Cursor="SizeNESW" Tag="1" DragDelta="Thumb_DragDelta" /> 
      <Thumb DockPanel.Dock="Bottom" Height="4" Cursor="SizeNESW" Tag="1" DragDelta="Thumb_DragDelta" /> 
     </DockPanel> 

     <!-- Bottom/Right --> 
     <DockPanel LastChildFill="False" Grid.Row="2" Grid.Column="2"> 
      <Thumb DockPanel.Dock="Right" Width="4" Cursor="SizeNWSE" Tag="1" DragDelta="Thumb_DragDelta" /> 
      <Thumb DockPanel.Dock="Bottom" Height="4" Cursor="SizeNWSE" Tag="1" DragDelta="Thumb_DragDelta" /> 
     </DockPanel> 

     <!-- Left --> 
     <Thumb Grid.Row="1" Grid.Column="0" Width="4" Cursor="SizeWE" Tag="0" HorizontalAlignment="Left" DragDelta="Thumb_DragDelta" /> 

     <!-- Top --> 
     <Thumb Grid.Row="0" Grid.Column="1" Height="4" Cursor="SizeNS" Tag="0" VerticalAlignment="Top" DragDelta="Thumb_DragDelta" /> 

     <!-- Right --> 
     <Thumb Grid.Row="1" Grid.Column="2" Width="4" Cursor="SizeWE" Tag="1" HorizontalAlignment="Right" DragDelta="Thumb_DragDelta" /> 

     <!-- Bottom --> 
     <Thumb Grid.Row="2" Grid.Column="1" Height="4" Cursor="SizeNS" Tag="1" VerticalAlignment="Bottom" DragDelta="Thumb_DragDelta" /> 
    </Grid> 
</Grid> 

MainWindow.xaml.cs

using System; 
using System.Collections.Generic; 
using System.Diagnostics; 
using System.Linq; 
using System.Text; 
using System.Threading.Tasks; 
using System.Windows; 
using System.Windows.Controls; 
using System.Windows.Controls.Primitives; 
using System.Windows.Data; 
using System.Windows.Documents; 
using System.Windows.Input; 
using System.Windows.Media; 
using System.Windows.Media.Imaging; 
using System.Windows.Navigation; 
using System.Windows.Shapes; 

namespace WpfApp1 
{ 
    public partial class MainWindow : Window 
    { 
     #region --- Declarations --- 
     private Rect _location { get; set; } 
     #endregion 

     #region --- Constructors --- 
     public MainWindow() 
     { 
      InitializeComponent(); 
     } 
     #endregion 

     #region --- Properties --- 
     private Rect DesktopArea 
     { 
      get 
      { 
       var c = System.Windows.Forms.Cursor.Position; 
       var s = System.Windows.Forms.Screen.FromPoint(c); 
       var a = s.WorkingArea; 
       return new Rect(a.Left, a.Top, a.Width, a.Height); 
      } 
     } 
     #endregion 

     #region --- Dependency Properties --- 
     public static readonly DependencyProperty InternalWindowStateProperty = DependencyProperty.Register("InternalWindowState", typeof(WindowState), typeof(MainWindow), new PropertyMetadata(WindowState.Normal, new PropertyChangedCallback(OnInternalWindowStateChanged))); 

     public WindowState InternalWindowState 
     { 
      get { return (WindowState)GetValue(InternalWindowStateProperty); } 
      set { SetValue(InternalWindowStateProperty, value); } 
     } 

     private static void OnInternalWindowStateChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
     { 
      MainWindow instance = (MainWindow)d; 
      instance.SetInternalWindowState((WindowState)e.NewValue); 
     } 
     #endregion 

     #region --- Private Methods --- 
     private void StoreLocation() 
     { 
      _location = new Rect(this.Left, this.Top, this.Width, this.Height); 
     } 

     private void RestoreLocation() 
     { 
      this.Width = _location.Width; 
      this.Height = _location.Height; 
      this.Top = _location.Top >= 0 ? _location.Top : 0; 
      this.Left = _location.Left; 
     } 

     private void SetMaximizedState() 
     { 
      this.Width = DesktopArea.Width; 
      this.Height = DesktopArea.Height; 
      this.Top = DesktopArea.Top; 
      this.Left = DesktopArea.Left; 
     } 

     private void SetInternalWindowState(WindowState state) 
     { 
      InternalWindowState = state; 

      switch (InternalWindowState) 
      { 
       case WindowState.Normal: 
        this.WindowState = WindowState.Normal; 
        RestoreLocation(); 
        break; 
       case WindowState.Maximized: 
        this.WindowState = WindowState.Normal; 
        SetMaximizedState(); 
        break; 
       case WindowState.Minimized: 
        this.WindowState = WindowState.Minimized; 
        break; 
      } 
     } 
     #endregion 

     #region --- Sizing Routines --- 
     private void Thumb_DragDelta(object sender, System.Windows.Controls.Primitives.DragDeltaEventArgs e) 
     { 
      Thumb thumb = (Thumb)sender; 
      int tag = Convert.ToInt32(thumb.Tag); 
      if (thumb.Cursor == Cursors.SizeWE) HandleSizeWE(tag, e); 
      if (thumb.Cursor == Cursors.SizeNS) HandleSizeNS(tag, e); 
      if (thumb.Cursor == Cursors.SizeNESW) HandleSizeNESW(tag, e); 
      if (thumb.Cursor == Cursors.SizeNWSE) HandleSizeNWSE(tag, e); 
     } 

     private void HandleSizeNWSE(int tag, DragDeltaEventArgs e) 
     { 
      if (tag == 0) 
      { 
       this.Top += e.VerticalChange; 
       this.Height -= e.VerticalChange; 
       this.Left += e.HorizontalChange; 
       this.Width -= e.HorizontalChange; 
      } 
      else 
      { 
       this.Width += e.HorizontalChange; 
       this.Height += e.VerticalChange; 
      } 
     } 

     private void HandleSizeNESW(int tag, DragDeltaEventArgs e) 
     { 
      if (tag == 0) 
      { 
       this.Top += e.VerticalChange; 
       this.Height -= e.VerticalChange; 
       this.Width += e.HorizontalChange; 
      } 
      else 
      { 
       this.Left += e.HorizontalChange; 
       this.Width -= e.HorizontalChange; 
       this.Height += e.VerticalChange; 
      } 
     } 

     private void HandleSizeNS(int tag, DragDeltaEventArgs e) 
     { 
      if (tag == 0) 
      { 
       this.Top += e.VerticalChange; 
       this.Height -= e.VerticalChange; 
      } 
      else 
       this.Height += e.VerticalChange; 
     } 

     private void HandleSizeWE(int tag, DragDeltaEventArgs e) 
     { 
      if (tag == 0) 
      { 
       this.Left += e.HorizontalChange; 
       this.Width -= e.HorizontalChange; 
      } 
      else 
       this.Width += e.HorizontalChange; 
     } 
     #endregion 

     #region --- Event Handlers --- 
     private void OnDragMoveWindow(Object sender, MouseButtonEventArgs e) 
     { 
      if (this.InternalWindowState == WindowState.Maximized) 
      { 
       var c = System.Windows.Forms.Cursor.Position; 
       this.InternalWindowState = WindowState.Normal; 
       this.Height = _location.Height; 
       this.Width = _location.Width; 
       this.Top = c.Y - (titleBar.ActualHeight/2); 
       this.Left = c.X - (_location.Width/2); 
      } 
      this.DragMove(); 
     } 

     private void OnMaximizeWindow(Object sender, MouseButtonEventArgs e) 
     { 
      if (this.InternalWindowState == WindowState.Maximized) 
       this.InternalWindowState = WindowState.Normal; 
      else 
       this.InternalWindowState = WindowState.Maximized; 
     } 

     private void OnMinimizeWindow(Object sender, MouseButtonEventArgs e) 
     { 
      this.InternalWindowState = WindowState.Minimized; 
     } 

     private void OnCloseWindow(Object sender, MouseButtonEventArgs e) 
     { 
      Application.Current.Shutdown(); 
     } 

     private void Window_StateChanged(object sender, EventArgs e) 
     { 
      if (this.WindowState == WindowState.Maximized) 
      { 
       this.InternalWindowState = WindowState.Maximized; 
      } 
     } 

     private void Window_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e) 
     { 
      if (this.InternalWindowState != WindowState.Maximized) 
       StoreLocation(); 
     } 
     #endregion 
    } 
}