Finestre Secondarie con XAML

Spesso, durante la creazione di un programma, sorge la necessità di avere più finestre per la gestione dello stesso (finestra impostazioni, oppure inserimento di dati). Un tempo era prassi creare form secondarie. Con wpf è possibile creare window secondarie. Un'altra alternativa sarebbe gestire il tutto tramite TAB. Quello che vi mostrerò ora è un diverso approccio che ho trovato girovagando su internet.

P.s. Questo metodo non vuole avere la presunzione di essere la migliore soluzione al problema delle doppie finestre, ma solamente una possibile alternativa alle altre.

Inizio con dire che questo metodo è indipendende dal linguaggio scelto. Si basa solamente su interfacce create con XAML. Per la spiegazione userò il c#, solo perchè la gestione devono essere gestiti 2 controlli da codice per attivare/disattivare la finestra.

Il trucco sta nel creare una GRID con visibilità Collapsed, in questo modo non sarà visibile nè presente (l'attributo Hidden sarebbe un errore perchè la renderebbe solo invisibile, ma sarebbe comunque presente, occupando spazio e coprendo gli altri controlli).

Per una questione estetica ed organizzativa ho preferito strutturare la window in questo modo:

1° Grid "Generale" , contenente a sua volta 2 Grid. La prima che conterrà i controlli per la finestra principale, la seconda che conterà la finestra secondaria.

<Window
    x:Class="WpfApp6.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:local="clr-namespace:WpfApp6"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    Title="MainWindow"
    Width="260"
    Height="200"
    mc:Ignorable="d">
    <Grid x:Name="Generale">
<!-- -->
    </Grid>
</Window>

La Grid "primaria" conterrà solamente 1 Label e 1 Button .

 <Grid x:Name="Primaria">
            <Label x:Name="label"
            Margin="10,10,0,0"
            HorizontalAlignment="Left"
            VerticalAlignment="Top"
            Content="FINESTRA PRIMARIA" />
            <Button x:Name="button"
            Margin="10,52,98.6,83.6"
            Click="button_Click"
            Content="Attiva Seconda Finestra" />
        </Grid>

La Grid "secondaria" è strutturata:

 <Grid x:Name="SecondaFinestra" Visibility="Collapsed">
            <!--  Questa Grid opacizza lo sfondo  -->
            <Grid Background="Black" Opacity="0.50" />

            <Border
                MinWidth="120"
                MinHeight="100"
                HorizontalAlignment="Center"
                VerticalAlignment="Center"
                Background="MediumSeaGreen"
                BorderBrush="Black"
                BorderThickness="3">

                <Grid>
                    <TextBlock
                        Name="Title"
                        Text="Finestra Secondaria"
                        TextAlignment="Center" />
                    <Button
                        Name="buttSecondario"
                        Margin="31,35,25.8,37.4"
                        Click="buttSecondario_Click"
                        Content="Disattiva 2° Finestra" />
                </Grid>
            </Border>
        </Grid>

Definizione di una grid con Name="Seconaria" e Visibility="Collapsed". Non ho messo altri attributi perchè potrebbero andare in contrasto con la sua funzionalità.

Una Grid quanto tutta la window che serve per opacizzare la Grid "Primaria", questa non è necessaria, ma visivamente può essere utile.

Stessa cosa per il Border, messo solo per ragione estetiche. Dopo ho creato un'ulteriore grid all'interno del Border per gestire i 2 controlli.

. Quando si crea la finestra, per vedere i risultati si può momentaneamente cmbiaere l'attributo visibility della Grid "secondaria" in visible. appena finite le modifiche rimetterlo su Collapsed. (Per precauzione potete pure inserire al momento del Load della window una riga di codice che porti la grid comunque con visibility=Collapsed). finita la progettazione, per rendere usabile la finestra ho inserito 2 eventi ButtonClick (voi potete usare gli eventi che preferite). Nella prima finestra, alla pressione del tasto, si imposterà la proprietà della Grid "Secondaria" su visible, rendendola visibile ed utilizzabile. successivamente la pressione del secondo Button renderà di nuovo la proprietà visibility della Grid "secondaria" su visibility="Collapsed. Nascondendo di fatto la Grid e permettendo di utilizzare la Grid "Primaria".

Ecco un esempio:

Gif d'esempio

Se si vuole dare un tocco stilistico più a forma di finestra è possibile tramite degli stacPanel inrerire una piccola barra con un pulsante di chiusura ed un titolo:

<Window
    x:Class="WpfApp6.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:local="clr-namespace:WpfApp6"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    Title="MainWindow"
    Width="413.6"
    Height="256"
    mc:Ignorable="d">
    <Grid x:Name="Generale">
        <Grid x:Name="Primaria" Margin="0,0,0.2,0.4">
            <Label x:Name="label"
            Margin="146,44,143,0"
            VerticalAlignment="Top"
            Content="FINESTRA PRIMARIA" d:LayoutOverrides="Width" />
            <Button x:Name="button"
            Margin="122,75,124,97"
            Click="button_Click"
            Content="Attiva Seconda Finestra" />
        </Grid>
        <!-- GESTIONE FFINESTRA SECONDARIA 
        Durante la progettazione renderla visibile-->
        <Grid x:Name="SecondaFinestra" Visibility="Visible">
            <!--  Questa Grid opacizza lo sfondo  -->
            <Grid Background="Black" Opacity="0.50" Margin="0,0,0.2,0.4" />

            <Border
                MinWidth="120"
                MinHeight="100"
                Background="MediumSeaGreen"
                BorderBrush="Black"
                BorderThickness="3" 
                HorizontalAlignment="Center"
                VerticalAlignment="Center" Width="224">
                <StackPanel>

                    <Border BorderBrush="Black" BorderThickness="1">
                        <StackPanel Background="AliceBlue" Height="14" Orientation="Horizontal"  >
                            <TextBlock 
                                Text="Finestra Secondaria"
                                FontSize="10" FontWeight="Black"
                                Width="200"></TextBlock>
                            <Button x:Name="xButton"
                                HorizontalAlignment="Right"
                                VerticalContentAlignment="Center"
                                HorizontalContentAlignment="Center"
                                Click="buttSecondario_Click"
                                
                                Content="X"  FontSize="9" FontWeight="ExtraBlack"
                                Width="16" Height="14" Margin="0,0,0,0.4"  />
                        </StackPanel>
                    </Border>

                    <Grid>


                    <TextBlock
                        x:Name="BarraButton"
                        Text="Finestra Secondaria"
                        TextAlignment="Center" Height="27" Margin="0,0,0.6,0" />

                    <Button
                        x:Name="buttSecondario"
                        Margin="31,35,25.8,37.4"
                        Click="buttSecondario_Click"
                        Content="Disattiva 2° Finestra" />
                    </Grid>

                </StackPanel>
            </Border>
        </Grid>
    </Grid>
</Window>

Lasciando stare la grafica, che può piacere o meno, e che sicuramente può essere migliorata, questo è un diverso modo per gestire le finestre. In più (vantaggio o svantaggio lo deciderete voi) in questo modo nelle gestioni risorse apparirà solo 1 processo anche all'apertura della 2° finestra.