Come creare una finestra WPF senza un bordo che può essere ridimensionato solo tramite un grip?


94

Se si imposta ResizeMode="CanResizeWithGrip"su un WPF, Windowviene visualizzato un grip di ridimensionamento nell'angolo inferiore destro, come di seguito:

Se si imposta WindowStyle="None"anche la barra del titolo scompare ma il bordo smussato grigio rimane finché non si imposta ResizeMode="NoResize". Sfortunatamente, con questa combinazione di proprietà impostata, scompare anche il grip di ridimensionamento.

Ho sovrascritto il Window's ControlTemplatetramite un'usanza Style. Desidero specificare personalmente il bordo della finestra e non ho bisogno che gli utenti siano in grado di ridimensionare la finestra da tutti e quattro i lati, ma ho bisogno di un grip di ridimensionamento.

Qualcuno può descrivere un modo semplice per soddisfare tutti questi criteri?

  1. Non ho un bordo a Windowparte quello che mi specifico in a ControlTemplate.
  2. Avere un grip di ridimensionamento funzionante nell'angolo inferiore destro.
  3. Non hai una barra del titolo.

3
Tieni presente che Allowtransperency crea una perdita di memoria. Quindi evita di usarlo. Fare riferimento a social.msdn.microsoft.com/Forums/en/wpf/thread/…
Dipesh Bhatt

1
@DipeshBhatt Non sono riuscito a trovare alcuna spiegazione a tale affermazione nel collegamento che hai fornito. forse intendevi pubblicare il link social.msdn.microsoft.com/Forums/vstudio/en-US/…
itsho

Ero rivolto verso il bordo grigio in alto anche se avevo impostato lo stile della finestra su Nessuno. ResizeMode = "NoResize" ha risolto il mio problema.
Surendra Shrestha

Risposte:


180

Se si imposta la AllowsTransparencyproprietà su Window(anche senza impostare alcun valore di trasparenza) il bordo scompare e si può ridimensionare solo tramite il grip.

<Window
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Width="640" Height="480" 
    WindowStyle="None"
    AllowsTransparency="True"
    ResizeMode="CanResizeWithGrip">

    <!-- Content -->

</Window>

Il risultato è simile a:


Puro colpo di fortuna, lo sapevo: stavo giocando con lo stesso controllo impostato per me questo pomeriggio. :)
ZombieSheep

2
Wow, non me lo sarei aspettato, ma è totalmente utile per creare post-it-notes-in-5-minuti, grazie :)
Tomáš Kafka

4
Tuttavia, AllowTransparency presenta diversi inconvenienti, Windows non può più ospitare i controlli della finestra secondaria come il browser Web, di solito forza il rendering del software, ha segnalato perdite di memoria. Vedi la mia soluzione alternativa di seguito.
Oscilla il

Hai solo bisogno di WindowStyle = "Nessuno" per eliminare i bordi; La trasparenza accade solo per richiederla, ma non influisce sui bordi ..
Grault

2
@ Grault thats elimina l'intestazione della finestra, ma c'è ancora un bordo solido attorno al modulo. AllowsTransparency elimina i confini.
Oscilla il

78

Stavo cercando di creare una finestra senza bordi con WindowStyle="None"ma quando l'ho testata, sembra che appaia una barra bianca in alto, dopo alcune ricerche sembra essere un "Ridimensiona bordo", ecco un'immagine (ho notato in giallo):

La sfida

Dopo alcune ricerche su Internet e molte soluzioni difficili non xaml, tutte le soluzioni che ho trovato erano codice dietro in C # e molte righe di codice, ho trovato indirettamente la soluzione qui: La finestra personalizzata massima perde l'effetto ombra esterna

<WindowChrome.WindowChrome>
    <WindowChrome 
        CaptionHeight="0"
        ResizeBorderThickness="5" />
</WindowChrome.WindowChrome>

Nota : è necessario utilizzare il framework .NET 4.5 o, se si utilizza una versione precedente, utilizzare WPFShell, fare riferimento alla shell e utilizzare Shell:WindowChrome.WindowChromeinvece.

Ho usato la WindowChromeproprietà Finestra, se la usi quel "bordo di ridimensionamento" bianco scompare, ma devi definire alcune proprietà per funzionare correttamente.

CaptionHeight: questa è l'altezza dell'area della didascalia (barra dell'intestazione) che consente lo snap Aero, facendo doppio clic sul comportamento di una normale barra del titolo. Impostalo su 0 (zero) per far funzionare i pulsanti.

ResizeBorderThickness: Questo è lo spessore sul bordo della finestra che è dove puoi ridimensionare la finestra. Metto a 5 perché mi piace quel numero e perché se metti zero è difficile ridimensionare la finestra.

Dopo aver utilizzato questo codice breve il risultato è questo:

La soluzione

E ora, il bordo bianco è scomparso senza utilizzare ResizeMode="NoResize"e AllowsTransparency="True", mostra anche un'ombra nella finestra.

Più avanti spiegherò come far funzionare i pulsanti (non ho usato immagini per i pulsanti) facilmente con un codice semplice e breve, sono nuovo e penso di poter postare in codeproject, perché qui non ho trovato il posto per pubblicare il tutorial.

Forse c'è un'altra soluzione (so che ci sono soluzioni difficili e difficili per i niubbi come me) ma funziona per i miei progetti personali.

Ecco il codice completo

<Window x:Class="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:Concursos"
    mc:Ignorable="d"
    Title="Concuros" Height="350" Width="525"
    WindowStyle="None"
    WindowState="Normal" 
    ResizeMode="CanResize"
    >
<WindowChrome.WindowChrome>
    <WindowChrome 
        CaptionHeight="0"
        ResizeBorderThickness="5" />
</WindowChrome.WindowChrome>

    <Grid>

    <Rectangle Fill="#D53736" HorizontalAlignment="Stretch" Height="35" VerticalAlignment="Top" PreviewMouseDown="Rectangle_PreviewMouseDown" />
    <Button x:Name="Btnclose" Content="r" HorizontalAlignment="Right" VerticalAlignment="Top" Width="35" Height="35" Style="{StaticResource TempBTNclose}"/>
    <Button x:Name="Btnmax" Content="2" HorizontalAlignment="Right" VerticalAlignment="Top" Margin="0,0,35,0" Width="35" Height="35" Style="{StaticResource TempBTNclose}"/>
    <Button x:Name="Btnmin" Content="0" HorizontalAlignment="Right" VerticalAlignment="Top" Margin="0,0,70,0" Width="35" Height="35" Style="{StaticResource TempBTNclose}"/>

</Grid>

Grazie!


3
Bene, complimenti per questo! Questa è di gran lunga la risposta più semplice / senza compromessi di questo thread! Dovrebbe essere molto più "alto" il voto. Devo ammettere che ero un po 'settico al riguardo, soprattutto riguardo a quello che stava succedendo sotto il cofano. Ho anche controllato l'albero del WFP e sembra che la trasparenza non sia stata aggiunta di nuovo. Perfino i controlli complicati come il display "WebBrowser" vanno bene. Ho avuto un problema di congelamento del rendering utilizzando la trasparenza quando l'app era molto stressata ... Beh, questo non accade con questa soluzione. Penso che potrebbe essere il momento di ritirare la soluzione @Wobbles!
VeV

1
Sembra che questo possa ancora richiedere l'interoperabilità per il trascinamento della finestra se interpreto Rectangle_PreviewMouseDowncorrettamente l'uso dell'evento.
Oscilla

Questo potrebbe non funzionare in <= Win 8.1, ha visto alcuni risultati strani nella mia VM. Windows 7 e 8 sono le preoccupazioni principali in quanto fanno la stupida cosa del confine Aero.
Oscilla

Grazie per la tua risposta
Fernando Aguirre

Ciao @FernandoAguirre, ho pubblicato questa domanda correlata e ti sarei grato se avessi una risposta.
sampathsris

39

Sebbene la risposta accettata sia molto vera, voglio solo sottolineare che AllowTransparency ha alcuni difetti. Non consente la visualizzazione dei controlli della finestra figlio, ad esempio WebBrowser, e di solito forza il rendering del software che può avere effetti negativi sulle prestazioni.

Tuttavia, c'è una soluzione migliore.

Quando si desidera creare una finestra senza bordo che sia ridimensionabile ed è in grado di ospitare un controllo WebBrowser o un controllo Frame puntato a un URL che semplicemente non è possibile, il contenuto di tale controllo verrà visualizzato vuoto.

Tuttavia ho trovato una soluzione alternativa; nella finestra, se imposti WindowStyle su Nessuno, ResizeMode su NoResize (abbi pazienza, sarai ancora in grado di ridimensionare una volta fatto) quindi assicurati di avere UNCHECKED AllowsTransparency avrai una finestra di dimensioni statiche senza bordo e mostrerà il controllo del browser.

Ora, probabilmente vuoi ancora essere in grado di ridimensionare, giusto? Bene, possiamo farlo con una chiamata di interoperabilità:

    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    private static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);

    [DllImportAttribute("user32.dll")]
    public static extern bool ReleaseCapture();

    //Attach this to the MouseDown event of your drag control to move the window in place of the title bar
    private void WindowDrag(object sender, MouseButtonEventArgs e) // MouseDown
    {
        ReleaseCapture();
        SendMessage(new WindowInteropHelper(this).Handle,
            0xA1, (IntPtr)0x2, (IntPtr)0);
    }

    //Attach this to the PreviewMousLeftButtonDown event of the grip control in the lower right corner of the form to resize the window
    private void WindowResize(object sender, MouseButtonEventArgs e) //PreviewMousLeftButtonDown
    {
        HwndSource hwndSource = PresentationSource.FromVisual((Visual)sender) as HwndSource;
        SendMessage(hwndSource.Handle, 0x112, (IntPtr)61448, IntPtr.Zero);
    }

E voilà, una finestra WPF senza bordi e ancora mobile e ridimensionabile senza perdere la compatibilità con controlli come WebBrowser


Come dovremmo fare se vogliamo ridimensionare da tutti i lati, non solo in basso a destra, ma non vogliamo che il bordo sia visibile?
Daniel

6
Ecco gli altri valori di wParam, basta assegnare nuovi eventi a nuovi oggetti dell'interfaccia utente utilizzando questi secondo necessitàprivate enum ResizeDirection { Left = 61441, Right = 61442, Top = 61443, TopLeft = 61444, TopRight = 61445, Bottom = 61446, BottomLeft = 61447, BottomRight = 61448, }
Wobbles

Questo funziona alla grande per me, con un'eccezione anche se una volta che hai NoResize non puoi scattare la finestra trascinandola più in alto.
CJK

2
@CJK Vero, ma senza dubbio puoi agganciare i messaggi di Windows anche per questo e gestirlo.
Oscilla

Non riesco a trascinare la finestra. qualche idea del perché? (il ridimensionamento funziona a
meraviglia

5

Esempio qui:

<Style TargetType="Window" x:Key="DialogWindow">
        <Setter Property="AllowsTransparency" Value="True"/>
        <Setter Property="WindowStyle" Value="None"/>
        <Setter Property="ResizeMode" Value="CanResizeWithGrip"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type Window}">
                    <Border BorderBrush="Black" BorderThickness="3" CornerRadius="10" Height="{TemplateBinding Height}"
                            Width="{TemplateBinding Width}" Background="Gray">
                        <DockPanel>
                            <Grid DockPanel.Dock="Top">
                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition></ColumnDefinition>
                                    <ColumnDefinition Width="50"/>
                                </Grid.ColumnDefinitions>
                                <Label Height="35" Grid.ColumnSpan="2"
                                       x:Name="PART_WindowHeader"                                            
                                       HorizontalAlignment="Stretch" 
                                       VerticalAlignment="Stretch"/>
                                <Button Width="15" Height="15" Content="x" Grid.Column="1" x:Name="PART_CloseButton"/>
                            </Grid>
                            <Border HorizontalAlignment="Stretch" VerticalAlignment="Stretch" 
                                        Background="LightBlue" CornerRadius="0,0,10,10" 
                                        Grid.ColumnSpan="2"
                                        Grid.RowSpan="2">
                                <Grid>
                                    <Grid.ColumnDefinitions>
                                        <ColumnDefinition/>
                                        <ColumnDefinition Width="20"/>
                                    </Grid.ColumnDefinitions>
                                    <Grid.RowDefinitions>
                                        <RowDefinition Height="*"/>
                                        <RowDefinition Height="20"></RowDefinition>
                                    </Grid.RowDefinitions>
                                    <ResizeGrip Width="10" Height="10" Grid.Column="1" VerticalAlignment="Bottom" Grid.Row="1"/>
                                </Grid>
                            </Border>
                        </DockPanel>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

23
Dovresti includere una breve spiegazione di come funziona il codice.
M456

0

Ho avuto difficoltà a ottenere la risposta da @ fernando-aguirre utilizzando WindowChromeper lavorare. Non funzionava nel mio caso perché ero imperativi OnSourceInitializedin MainWindowe non chiamare il metodo della classe base.

protected override void OnSourceInitialized(EventArgs e)
{
    ViewModel.Initialize(this);
    base.OnSourceInitialized(e); // <== Need to call this!
}

Questo mi ha lasciato perplesso per molto tempo.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.