Comment créer une fenêtre WPF sans bordure qui peut être redimensionnée via une poignée uniquement?

94

Si vous définissez ResizeMode="CanResizeWithGrip"sur un WPF, Windowune poignée de redimensionnement est affichée dans le coin inférieur droit, comme ci-dessous:

Si vous définissez WindowStyle="None"également la barre de titre disparaît mais le bord biseauté gris reste jusqu'à ce que vous définissiez ResizeMode="NoResize". Malheureusement, avec cette combinaison de propriétés définie, la poignée de redimensionnement disparaît également.

J'ai remplacé les Windows ControlTemplatevia une coutume Style. Je veux spécifier moi-même la bordure de la fenêtre et je n'ai pas besoin que les utilisateurs puissent redimensionner la fenêtre des quatre côtés, mais j'ai besoin d'une poignée de redimensionnement.

Quelqu'un peut-il détailler un moyen simple de répondre à tous ces critères?

  1. Ne pas avoir de bordure en Windowdehors de celle que je me précise dans un ControlTemplate.
  2. Ayez une poignée de redimensionnement fonctionnelle dans le coin inférieur droit.
  3. N'a pas de barre de titre.
Drew Noakes
la source
3
Veuillez noter que Allowtransperency crée une fuite de mémoire. Alors évitez de l'utiliser. Veuillez vous référer à social.msdn.microsoft.com/Forums/en/wpf/thread/…
Dipesh Bhatt
1
@DipeshBhatt Je n'ai trouvé aucune explication à cette affirmation dans le lien que vous avez fourni. peut-être que vous vouliez publier le lien social.msdn.microsoft.com/Forums/vstudio/en-US
...
J'étais face au bord gris en haut bien que j'avais défini le style de fenêtre sur Aucun. ResizeMode = "NoResize" a résolu mon problème.
Surendra Shrestha

Réponses:

180

Si vous définissez la AllowsTransparencypropriété sur Window(même sans définir de valeurs de transparence), la bordure disparaît et vous ne pouvez redimensionner que via la poignée.

<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>

Le résultat ressemble à:

ZombieMouton
la source
Par hasard, je le savais - je jouais avec le même contrôle que moi-même cet après-midi. :)
ZombieSheep
2
Wow, je ne m'attendais pas à cela, mais c'est totalement pratique pour créer vos propres post-it-notes en 5 minutes, merci :)
Tomáš Kafka
4
AllowTransparency a cependant plusieurs inconvénients, Windows ne peut plus héberger les contrôles de sous-fenêtre tels que WebBrowser, force généralement le rendu logiciel, a signalé des fuites de mémoire. Voir ma solution de contournement ci-dessous.
Wobbles
Vous n'avez besoin que de WindowStyle = "None" pour vous débarrasser des bordures; AllowsTransparency arrive seulement à l'exiger, mais n'affecte pas les frontières ..
Grault
2
@Grault qui se débarrasse de l'en-tête de la fenêtre, mais il y a toujours une bordure solide autour du formulaire. AllowsTransparency supprime les bordures.
Wobbles
78

J'essayais de créer une fenêtre sans bordure avec WindowStyle="None"mais quand je l'ai testé, il semble qu'une barre blanche apparaisse en haut, après quelques recherches, il semble que ce soit un "Redimensionner la bordure", voici une image (j'ai remarqué en jaune):

Le défi

Après quelques recherches sur Internet et de nombreuses solutions non xaml difficiles, toutes les solutions que j'ai trouvées étaient du code en C # et beaucoup de lignes de code, j'ai trouvé indirectement la solution ici: la fenêtre personnalisée maximale perd l'effet d'ombre portée

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

Remarque : vous devez utiliser le framework .NET 4.5, ou si vous utilisez une version plus ancienne, utilisez WPFShell, référencez simplement le shell et utilisez à la Shell:WindowChrome.WindowChromeplace.

J'ai utilisé la WindowChromepropriété de Window, si vous l'utilisez, la "bordure de redimensionnement" blanche disparaît, mais vous devez définir certaines propriétés pour fonctionner correctement.

CaptionHeight: Il s'agit de la hauteur de la zone de légende (barre d'en-tête) qui permet le comportement d'accrochage Aero, double-clic comme le fait une barre de titre normale. Réglez-le sur 0 (zéro) pour que les boutons fonctionnent.

ResizeBorderThickness: Il s'agit de l'épaisseur au bord de la fenêtre où vous pouvez redimensionner la fenêtre. Je mets 5 parce que j'aime ce nombre, et parce que si vous mettez zéro, il est difficile de redimensionner la fenêtre.

Après avoir utilisé ce code court, le résultat est le suivant:

La solution

Et maintenant, la bordure blanche a disparu sans utiliser ResizeMode="NoResize"et AllowsTransparency="True", elle montre également une ombre dans la fenêtre.

Plus tard, j'expliquerai comment faire fonctionner les boutons (je n'ai pas utilisé d'images pour les boutons) facilement avec un code simple et court, je suis nouveau et je pense que je peux poster sur codeproject, car ici je n'ai pas trouvé l'endroit pour publier le tutoriel.

Peut-être qu'il y a une autre solution (je sais qu'il y a des solutions dures et difficiles pour les noobs comme moi) mais cela fonctionne pour mes projets personnels.

Voici le code complet

<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>

Je vous remercie!

Fernando Aguirre
la source
3
Eh bien, bravo pour celui-ci! C'est de loin la réponse la plus simple / sans compromis de ce fil! Devrait obtenir beaucoup plus de votes «up». Je dois admettre que j'étais un peu septique à ce sujet, surtout à propos de ce qui se passait sous le capot. J'ai même vérifié l'arborescence du PAM et il semble que la transparence ne soit pas ajoutée. Même les contrôles délicats comme l'affichage «WebBrowser» très bien. J'ai eu un problème de gel du rendu en utilisant la transparence lorsque l'application était soumise à beaucoup de stress ... Eh bien, cela ne se produit pas avec cette solution. Je pense qu'il est peut-être temps de retirer la solution @Wobbles!
VeV
1
On dirait que cela peut encore avoir besoin d'interopérabilité pour le glissement de fenêtre si j'interprète Rectangle_PreviewMouseDowncorrectement l'utilisation de l' événement.
Wobbles
Cela peut ne pas fonctionner dans <= Win 8.1, vu des résultats étranges dans ma VM. Windows 7 et 8 sont les principales préoccupations car ils font la stupide chose de frontière Aero.
Wobbles
Merci pour votre réponse
Fernando Aguirre
Salut @FernandoAguirre, j'ai posté cette question connexe et je vous serais reconnaissant d'avoir une réponse.
sampathsris
39

Bien que la réponse acceptée soit très vraie, je tiens simplement à souligner que AllowTransparency a quelques inconvénients. Il ne permet pas aux contrôles de fenêtre enfant de s'afficher, c'est-à-dire WebBrowser, et il force généralement le rendu logiciel qui peut avoir des effets négatifs sur les performances.

Il y a un meilleur travail autour cependant.

Lorsque vous souhaitez créer une fenêtre sans bordure redimensionnable et capable d'héberger un contrôle WebBrowser ou un contrôle Frame pointé vers une URL que vous ne pouvez tout simplement pas, le contenu dudit contrôle apparaît vide.

J'ai trouvé une solution de contournement cependant; dans la fenêtre, si vous définissez WindowStyle sur None, ResizeMode sur NoResize (supportez-moi, vous serez toujours en mesure de redimensionner une fois terminé), puis assurez-vous que vous avez UNCHECKED AllowsTransparency, vous aurez une fenêtre de taille statique sans bordure et affichera le contrôle du navigateur.

Maintenant, vous voulez probablement toujours pouvoir redimensionner correctement? Eh bien, nous pouvons faire cela avec un appel d'interopérabilité:

    [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);
    }

Et voilà, une fenêtre WPF sans bordure et toujours déplaçable et redimensionnable sans perdre la compatibilité avec des contrôles comme WebBrowser

Vacille
la source
Comment devrions-nous procéder si nous voulons redimensionner de tous les côtés, pas seulement en bas à droite, mais ne voulons toujours pas de bordure visible?
Daniel
6
Voici les autres valeurs de wParam, attribuez simplement de nouveaux événements aux nouveaux objets d'interface utilisateur en les utilisant au besoinprivate enum ResizeDirection { Left = 61441, Right = 61442, Top = 61443, TopLeft = 61444, TopRight = 61445, Bottom = 61446, BottomLeft = 61447, BottomRight = 61448, }
Wobbles
Cela fonctionne très bien pour moi, à une exception près, mais une fois que vous avez NoResize, vous ne pouvez plus casser la fenêtre en la faisant glisser vers le haut.
CJK
2
@CJK C'est vrai, mais vous pouvez sans aucun doute accrocher les messages Windows pour cela et le gérer.
Wobbles
Je ne peux pas faire glisser la fenêtre. une idée pourquoi? (le redimensionnement fonctionne comme un charme)
Li3ro
5

Échantillon ici:

<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>
Kebes
la source
23
Vous devez inclure une brève explication du fonctionnement du code.
M456
0

J'avais du mal à obtenir la réponse de @ fernando-aguirre en utilisant WindowChromepour travailler. Cela ne fonctionnait pas dans mon cas car je remplaçais OnSourceInitializeddans le MainWindowet n'appelais pas la méthode de classe de base.

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

Cela m'a laissé perplexe pendant très longtemps.

Mike Ward
la source