¿Cómo crear una ventana WPF sin un borde que se pueda cambiar de tamaño solo mediante un pinzamiento?

94

Si establece ResizeMode="CanResizeWithGrip"un WPF Window, se muestra un control de cambio de tamaño en la esquina inferior derecha, como se muestra a continuación:

Si también configura WindowStyle="None", la barra de título desaparece pero el borde biselado gris permanece hasta que lo configura ResizeMode="NoResize". Desafortunadamente, con esta combinación de propiedades establecida, el control de cambio de tamaño también desaparece.

He anulado el Windowde a ControlTemplatetravés de un archivo personalizado Style. Quiero especificar el borde de la ventana yo mismo, y no necesito que los usuarios puedan cambiar el tamaño de la ventana desde los cuatro lados, pero necesito un control de cambio de tamaño.

¿Alguien puede detallar una forma sencilla de cumplir con todos estos criterios?

  1. No tengo un borde Windowaparte del que yo mismo especifico en a ControlTemplate.
  2. No tener un control de cambio de tamaño de trabajo en la esquina inferior derecha.
  3. No tiene barra de título.
Dibujó Noakes
fuente
3
Tenga en cuenta que Allowtransperency crea pérdida de memoria. Así que evita usarlo. Consulte social.msdn.microsoft.com/Forums/en/wpf/thread/…
Dipesh Bhatt
1
@DipeshBhatt No pude encontrar ninguna explicación a esa afirmación en el enlace que proporcionó. tal vez quisiste publicar el enlace social.msdn.microsoft.com/Forums/vstudio/en-US/…
itsho
Estaba frente al borde gris en la parte superior aunque había configurado el estilo de la ventana en Ninguno. ResizeMode = "NoResize" resolvió mi problema.
Surendra Shrestha

Respuestas:

180

Si establece la AllowsTransparencypropiedad en Window(incluso sin establecer ningún valor de transparencia), el borde desaparece y solo puede cambiar el tamaño a través del pinzamiento.

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

El resultado se parece a:

ZombieOvejas
fuente
Pura casualidad, lo sabía: estaba jugando con el mismo control que yo mismo esta tarde. :)
ZombieSheep
2
Vaya, no esperaría esto, pero es muy útil para hacer tus propias notas post-it en 5 minutos, gracias :)
Tomáš Kafka
4
Sin embargo, AllowTransparency tiene varias fallas, Windows ya no puede albergar controles de subventanas como WebBrowser, generalmente fuerza la renderización de software, ha informado pérdidas de memoria. Vea mi solución a continuación.
Wobbles
Solo necesita WindowStyle = "None" para deshacerse de los bordes; AllowsTransparency solo lo requiere, pero no afecta los bordes ..
Grault
2
@Grault eso elimina el encabezado de la ventana, pero todavía hay un borde sólido alrededor del formulario. AllowsTransparency elimina los bordes.
Wobbles
79

Estaba intentando crear una ventana sin bordes con WindowStyle="None"pero cuando la probé, parece que aparece una barra blanca en la parte superior, después de investigar un poco parece ser un "Borde de cambio de tamaño", aquí hay una imagen (comenté en amarillo):

El reto

Después de investigar un poco en Internet y muchas soluciones difíciles que no son xaml, todas las soluciones que encontré eran código subyacente en C # y muchas líneas de código, encontré indirectamente la solución aquí: La ventana personalizada máxima pierde el efecto de sombra paralela

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

Nota : Necesita usar .NET 4.5 framework, o si está usando una versión anterior use WPFShell, simplemente haga referencia al shell y use Shell:WindowChrome.WindowChromeen su lugar.

Usé la WindowChromepropiedad de Window, si usas esto, ese "borde de cambio de tamaño" blanco desaparece, pero necesitas definir algunas propiedades para que funcione correctamente.

CaptionHeight: esta es la altura del área de subtítulos (barra de encabezado) que permite el ajuste Aero, el comportamiento de doble clic como lo hace una barra de título normal. Establezca esto en 0 (cero) para que los botones funcionen.

ResizeBorderThickness: este es el grosor en el borde de la ventana, que es donde puede cambiar el tamaño de la ventana. Puse 5 porque me gusta ese número, y porque si pones cero es difícil cambiar el tamaño de la ventana.

Después de usar este código corto, el resultado es este:

La solución

Y ahora, el borde blanco desapareció sin usar ResizeMode="NoResize"y AllowsTransparency="True", además, muestra una sombra en la ventana.

Más adelante explicaré cómo hacer que funcionen los botones (no usé imágenes para los botones) fácilmente con código simple y corto, soy nuevo y creo que puedo publicar en codeproject, porque aquí no encontré el lugar para publicar el tutorial.

Tal vez haya otra solución (sé que hay soluciones difíciles y difíciles para novatos como yo) pero esto funciona para mis proyectos personales.

Aquí está el código 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>

¡Gracias!

Fernando Aguirre
fuente
3
Bueno, ¡Felicitaciones por este! ¡Esta es, con mucho, la respuesta más simple / sin intercambios de este hilo! Debería recibir muchos más votos "a favor". Tengo que admitir que estaba un poco séptico al respecto, especialmente sobre lo que estaba sucediendo debajo del capó. Incluso revisé el árbol de WFP y seguro que parece que la transparencia no se ha vuelto a agregar. Incluso los controles complicados como el 'WebBrowser' se muestran bien. Tuve un problema de congelación de renderizado usando transparencia cuando la aplicación estaba bajo mucho estrés ... Bueno, esto no está sucediendo con esta solución. ¡Creo que podría ser el momento de retirar la solución @Wobbles!
VeV
1
Parece que esto aún puede necesitar interoperabilidad para arrastrar la ventana si interpreto el uso del Rectangle_PreviewMouseDownevento correctamente.
Wobbles
Es posible que esto no funcione en <= Win 8.1, vi algunos resultados extraños en mi VM. Windows 7 y 8 son las principales preocupaciones, ya que hacen lo estúpido de Aero Border.
Wobbles
Gracias por su respuesta
Fernando Aguirre
Hola @FernandoAguirre, publiqué esta pregunta relacionada y te agradecería que tuvieras una respuesta.
sampathsris
40

Si bien la respuesta aceptada es muy cierta, solo quiero señalar que AllowTransparency tiene algunas desventajas. No permite que aparezcan los controles secundarios de la ventana, es decir, WebBrowser, y normalmente fuerza la representación del software, lo que puede tener efectos negativos en el rendimiento.

Sin embargo, hay una solución mejor.

Cuando desee crear una ventana sin borde que se pueda cambiar de tamaño y sea capaz de alojar un control WebBrowser o un control Frame apuntando a una URL que simplemente no pudo, el contenido de dicho control se mostraría vacío.

Sin embargo, encontré una solución alternativa; en la ventana, si establece WindowStyle en None, ResizeMode en NoResize (tenga paciencia conmigo, aún podrá cambiar el tamaño una vez hecho), luego asegúrese de haber DESCONECTADO AllowsTransparency, tendrá una ventana de tamaño estático sin borde y se mostrará el control del navegador.

Ahora, probablemente todavía quieras poder cambiar el tamaño, ¿verdad? Bueno, podemos hacerlo con una llamada de interoperabilidad:

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

Y listo, una ventana WPF sin borde y aún móvil y redimensionable sin perder compatibilidad con controles como WebBrowser

Bamboleo
fuente
¿Cómo deberíamos actuar si queremos cambiar el tamaño desde todos los lados, no solo desde la parte inferior derecha, pero aún no queremos que el borde sea visible?
Daniel
6
Aquí están los otros valores de wParam, simplemente asigne nuevos eventos a los nuevos Objetos de IU usándolos según sea necesarioprivate enum ResizeDirection { Left = 61441, Right = 61442, Top = 61443, TopLeft = 61444, TopRight = 61445, Bottom = 61446, BottomLeft = 61447, BottomRight = 61448, }
Wobbles
Esto funciona muy bien para mí, con una excepción, aunque una vez que tenga NoResize ya no puede ajustar la ventana arrastrándola hacia la parte superior.
CJK
2
@CJK Es cierto, pero sin duda puede conectar los mensajes de Windows para eso también y manejarlo.
Wobbles
No puedo arrastrar la ventana. alguna idea de por qué? (el cambio de tamaño funciona como un encanto)
Li3ro
5

Muestra aquí:

<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
fuente
23
Debe incluir una breve explicación de cómo funciona el código.
M456
0

Estaba teniendo dificultades para obtener la respuesta de @ fernando-aguirre usando WindowChromepara trabajar. No estaba funcionando en mi caso porque estaba anulando OnSourceInitializeden el MainWindowy no llamando al método de la clase base.

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

Esto me dejó perplejo durante mucho tiempo.

Mike Ward
fuente