Wie erstelle ich ein WPF-Fenster ohne Rahmen, dessen Größe nur über einen Griff geändert werden kann?

94

Wenn Sie ResizeMode="CanResizeWithGrip"ein WPF Windowfestlegen, wird in der unteren rechten Ecke ein Größenänderungsgriff angezeigt (siehe unten):

Wenn Sie ebenfalls festlegen, WindowStyle="None"verschwindet die Titelleiste, aber die grau abgeschrägte Kante bleibt bis zum Festlegen erhalten ResizeMode="NoResize". Leider verschwindet mit dieser Kombination von Eigenschaften auch der Größenänderungsgriff.

Ich habe die Window's ControlTemplateüber einen Brauch überschrieben Style. Ich möchte den Rand des Fensters selbst angeben, und ich brauche keine Benutzer, um die Größe des Fensters von allen vier Seiten ändern zu können, aber ich brauche einen Griff zum Ändern der Größe.

Kann jemand einen einfachen Weg beschreiben, um all diese Kriterien zu erfüllen?

  1. Haben Sie keinen Rand Windowneben dem, den ich selbst in a angegeben habe ControlTemplate.
  2. Haben Sie in der unteren rechten Ecke einen funktionierenden Größenänderungsgriff.
  3. Ich habe keine Titelleiste.
Drew Noakes
quelle
3
Bitte beachten Sie, dass Allowtransperency einen Speicherverlust verursacht. Vermeiden Sie es also. Bitte beziehen Sie sich auf social.msdn.microsoft.com/Forums/en/wpf/thread/…
Dipesh Bhatt
1
@ DipeshBhatt Ich konnte in dem von Ihnen angegebenen Link keine Erklärung für diese Behauptung finden. Vielleicht wollten
itsho
Ich stand oben vor dem grauen Rand, obwohl ich den Fensterstil auf Keine gesetzt hatte. ResizeMode = "NoResize" hat mein Problem gelöst.
Surendra Shrestha

Antworten:

180

Wenn Sie die AllowsTransparencyEigenschaft auf festlegen Window(auch ohne Transparenzwerte festzulegen), verschwindet der Rahmen und Sie können die Größe nur über den Griff ändern.

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

Ergebnis sieht aus wie:

ZombieSheep
quelle
Reiner Zufall, das wusste ich - ich habe heute Nachmittag mit dem gleichen Kontrollsatz gespielt. :)
ZombieSheep
2
Wow, ich würde das nicht erwarten, aber es ist sehr praktisch, um in 5 Minuten eigene Post-It-Notizen zu machen, danke :)
Tomáš Kafka
4
AllowTransparency weist jedoch mehrere Nachteile auf. Windows kann keine Unterfenstersteuerelemente mehr hosten, z. B. WebBrowser, erzwingt normalerweise das Rendern von Software und hat Speicherlecks gemeldet. Siehe meine Problemumgehung unten.
Wobbles
Sie benötigen nur WindowStyle = "None", um die Ränder zu entfernen. AllowsTransparency erfordert es nur, wirkt sich aber nicht auf die Grenzen aus.
Grault
2
@Grault, das die Fensterüberschrift entfernt, aber es gibt immer noch einen festen Rand um das Formular. AllowsTransparency beseitigt die Grenzen.
Wobbles
78

Ich habe versucht, ein randloses Fenster mit zu erstellen, WindowStyle="None"aber als ich es getestet habe, scheint oben ein weißer Balken zu erscheinen. Nach einigen Recherchen scheint es sich um einen "Rand der Größe ändern" zu handeln. Hier ist ein Bild (ich habe es gelb bemerkt):

Die Herausforderung

Nach einigen Recherchen über das Internet und vielen schwierigen Nicht-XAML-Lösungen, allen Lösungen, die ich gefunden habe, war Code hinter C # und vielen Codezeilen, habe ich hier indirekt die Lösung gefunden: Maximales benutzerdefiniertes Fenster verliert Schlagschatteneffekt

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

Hinweis : Sie müssen das .NET 4.5-Framework verwenden. Wenn Sie eine ältere Version verwenden, verwenden Sie WPFShell. Verweisen Sie einfach auf die Shell und verwenden Sie Shell:WindowChrome.WindowChromestattdessen.

Ich habe die WindowChromeEigenschaft von Window verwendet. Wenn Sie diese Eigenschaft verwenden, verschwindet der weiße "Größenänderungsrand", aber Sie müssen einige Eigenschaften definieren, um korrekt zu funktionieren.

CaptionHeight: Dies ist die Höhe des Beschriftungsbereichs (Kopfleiste), die das Aero-Snap-Doppelklickverhalten wie bei einer normalen Titelleiste ermöglicht. Setzen Sie diesen Wert auf 0 (Null), damit die Tasten funktionieren.

ResizeBorderThickness: Dies ist die Dicke am Rand des Fensters, an der Sie die Größe des Fensters ändern können. Ich setze auf 5, weil ich diese Zahl mag und weil es schwierig ist, die Fenstergröße zu ändern, wenn man Null setzt.

Nach Verwendung dieses Funktionscodes ist das Ergebnis:

Die Lösung

Und jetzt verschwand der weiße Rand ohne Verwendung ResizeMode="NoResize"und AllowsTransparency="True"zeigt auch einen Schatten im Fenster.

Später werde ich erklären, wie man die Schaltflächen (ich habe keine Bilder für die Schaltflächen verwendet) einfach mit einfachem und kurzem Code bearbeitet. Ich bin neu und denke, dass ich in Codeprojekt posten kann, weil ich hier den Ort nicht gefunden habe um das Tutorial zu posten.

Vielleicht gibt es eine andere Lösung (ich weiß, dass es harte und schwierige Lösungen für Noobs wie mich gibt), aber dies funktioniert für meine persönlichen Projekte.

Hier ist der vollständige Code

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

Danke dir!

Fernando Aguirre
quelle
3
Nun, ein großes Lob für diesen! Dies ist bei weitem die einfachste / keine Kompromissantwort dieses Threads! Sollte weitaus mehr "up" stimmen. Ich muss zugeben, dass ich etwas septisch war, besonders was unter der Haube geschah. Ich habe sogar den WFP-Baum überprüft und es sieht sicher so aus, als würde die Transparenz nicht wieder hinzugefügt. Selbst knifflige Steuerelemente wie der 'WebBrowser' werden problemlos angezeigt. Ich hatte ein Problem beim Einfrieren beim Rendern mit Transparenz, als die App unter großem Stress stand ... Nun, das passiert mit dieser Lösung nicht. Ich denke, es könnte Zeit sein, die @ Wobbles-Lösung einzustellen!
VeV
1
Es sieht so aus, als ob dies noch Interop zum Ziehen von Fenstern benötigt, wenn ich die Verwendung des Rectangle_PreviewMouseDownEreignisses richtig interpretiere .
Wobbles
Dies funktioniert möglicherweise nicht in <= Win 8.1. In meiner VM wurden einige merkwürdige Ergebnisse erzielt. Windows 7 & 8 sind die Hauptanliegen, da sie die dumme Aero-Border-Sache machen.
Wobbles
Vielen Dank für Ihre Antwort
Fernando Aguirre
Hallo @FernandoAguirre, ich habe diese verwandte Frage gepostet und wäre dankbar, wenn Sie eine Antwort hätten.
Sampathsris
39

Obwohl die akzeptierte Antwort sehr wahr ist, möchte ich nur darauf hinweisen, dass AllowTransparency einige Nachteile hat. Untergeordnete Fenstersteuerelemente, z. B. WebBrowser, werden nicht angezeigt, und normalerweise wird das Rendern von Software erzwungen, was negative Leistungseffekte haben kann.

Es gibt jedoch eine bessere Lösung.

Wenn Sie ein Fenster ohne Rahmen erstellen möchten, dessen Größe geändert werden kann und das ein WebBrowser-Steuerelement oder ein Frame-Steuerelement hosten kann, das auf eine URL verweist, die Sie einfach nicht konnten, wird der Inhalt dieses Steuerelements leer angezeigt.

Ich habe jedoch eine Problemumgehung gefunden. Wenn Sie im Fenster den WindowStyle auf None, ResizeMode auf NoResize setzen (bitte beachten Sie, dass Sie die Größe nach Abschluss noch ändern können), stellen Sie sicher, dass Sie UNCHECKED AllowsTransparency haben. Sie haben ein statisch großes Fenster ohne Rahmen und werden angezeigt die Browsersteuerung.

Jetzt möchten Sie wahrscheinlich immer noch in der Lage sein, die Größe zu ändern, oder? Nun, dazu können wir mit einem Interop-Anruf:

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

Und voila, ein WPF-Fenster ohne Rand und dennoch beweglich und in der Größe veränderbar, ohne die Kompatibilität mit Steuerelementen wie WebBrowser zu verlieren

Wackelt
quelle
Wie sollen wir vorgehen, wenn wir die Größe von allen Seiten ändern möchten, nicht nur von rechts unten, sondern immer noch keinen sichtbaren Rand?
Daniel
6
Hier sind die anderen wParam-Werte. Weisen Sie neuen UI-Objekten neue Ereignisse zu, indem Sie diese nach Bedarf verwendenprivate enum ResizeDirection { Left = 61441, Right = 61442, Top = 61443, TopLeft = 61444, TopRight = 61445, Bottom = 61446, BottomLeft = 61447, BottomRight = 61448, }
Wobbles
Dies funktioniert hervorragend für mich, mit einer Ausnahme. Wenn Sie jedoch NoResize haben, können Sie das Fenster nicht mehr ausrichten, indem Sie es nach oben ziehen.
CJK
2
@CJK Stimmt, aber ohne Zweifel können Sie die Windows-Nachrichten auch dafür einbinden und damit umgehen.
Wobbles
Ich kann das Fenster nicht ziehen. Irgendeine Idee warum? (Größe ändern funktioniert wie ein Zauber)
Li3ro
5

Beispiel hier:

<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
quelle
23
Sie sollten eine kurze Erklärung der Funktionsweise des Codes beifügen.
M456
0

Ich hatte Schwierigkeiten, die Antwort von @ fernando-aguirre zu bekommen, um WindowChromezu arbeiten. Es war nicht in meinem Fall arbeiten , weil ich überschreiben OnSourceInitializedin der MainWindowund nicht die Basisklasse Methode aufrufen.

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

Das hat mich sehr lange verblüfft.

Mike Ward
quelle