Como criar uma janela WPF sem uma borda que pode ser redimensionada apenas por meio de uma alça?

94

Se você definir ResizeMode="CanResizeWithGrip"um WPF Window, uma alça de redimensionamento será mostrada no canto inferior direito, conforme abaixo:

Se você definir WindowStyle="None"também, a barra de título desaparecerá, mas a borda chanfrada cinza permanecerá até que você defina ResizeMode="NoResize". Infelizmente, com essa combinação de propriedades definidas, a alça de redimensionamento também desaparece.

Substituí o Windowde ControlTemplatepor meio de um costume Style. Eu mesmo quero especificar a borda da janela e não preciso que os usuários possam redimensionar a janela dos quatro lados, mas preciso de uma alça de redimensionamento.

Alguém pode detalhar uma maneira simples de atender a todos esses critérios?

  1. Não tem uma fronteira à Windowparte daquela que me especifico em a ControlTemplate.
  2. Tenha uma alça de redimensionamento funcional no canto inferior direito.
  3. Não tem uma barra de título.
Drew Noakes
fonte
3
Observe que Allowtransperency cria vazamento de memória. Portanto, evite usá-lo. Consulte social.msdn.microsoft.com/Forums/en/wpf/thread/…
Dipesh Bhatt
1
@DipeshBhatt Não consegui encontrar nenhuma explicação para essa afirmação no link que você forneceu. talvez você pretendesse postar o link social.msdn.microsoft.com/Forums/vstudio/en-US/…
itsho
Eu estava de frente para a borda cinza na parte superior, embora tivesse definido o estilo da janela como Nenhum. ResizeMode = "NoResize" resolveu meu problema.
Surendra Shrestha

Respostas:

180

Se você definir a AllowsTransparencypropriedade em Window(mesmo sem definir nenhum valor de transparência), a borda desaparece e você só pode redimensionar por meio da alça.

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

O resultado parece:

ZombieSheep
fonte
Pura sorte, eu sabia disso - eu estava jogando com o mesmo conjunto de controle esta tarde. :)
ZombieSheep
2
Uau, eu não esperava isso, mas é totalmente útil para fazer suas próprias notas de post-it em 5 minutos, obrigado :)
Tomáš Kafka
4
AllowTransparency tem várias quedas, porém, o Windows não pode mais hospedar controles de subjanela como WebBrowser, geralmente força a renderização de software, relatou vazamentos de memória. Veja minha solução alternativa abaixo.
Wobbles
Você só precisa de WindowStyle = "None" para eliminar as bordas; AllowsTransparency só passa a exigir, mas não afeta as bordas.
Grault 01 de
2
@Grault isso remove o cabeçalho da janela, mas ainda há uma borda sólida ao redor do formulário. AllowsTransparency elimina as fronteiras.
Wobbles em
78

Eu estava tentando criar uma janela sem WindowStyle="None"borda com mas quando testei, parece que aparece uma barra branca no topo, depois de algumas pesquisas parece ser uma "borda de redimensionamento", aqui está uma imagem (comentei em amarelo):

O desafio

Depois de algumas pesquisas na Internet e de muitas soluções difíceis não xaml, todas as soluções que encontrei eram code behind em C # e muitas linhas de código, encontrei indiretamente a solução aqui: Janela customizada máxima perde efeito de sombra projetada

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

Observação : você precisa usar a estrutura .NET 4.5 ou, se estiver usando uma versão mais antiga, use WPFShell, basta fazer referência ao shell e usá-lo Shell:WindowChrome.WindowChrome.

Eu usei a WindowChromepropriedade Window, se você usar essa "borda de redimensionamento" branca desaparece, mas você precisa definir algumas propriedades para funcionar corretamente.

CaptionHeight: Esta é a altura da área da legenda (barra de cabeçalho) que permite o snap Aero, clicando duas vezes como uma barra de título normal. Defina como 0 (zero) para fazer os botões funcionarem.

ResizeBorderThickness: Esta é a espessura na borda da janela, onde você pode redimensionar a janela. Eu coloquei 5 porque gosto desse número, e porque se você colocar zero fica difícil redimensionar a janela.

Depois de usar este código curto, o resultado é este:

A solução

E agora, a borda branca desapareceu sem usar ResizeMode="NoResize"e AllowsTransparency="True", também mostra uma sombra na janela.

Posteriormente explicarei como fazer funcionar os botões (não usei imagens para os botões) facilmente com código simples e curto, sou novo e acho que posso postar no codeproject, pois aqui não encontrei o lugar para postar o tutorial.

Talvez haja outra solução (eu sei que existem soluções difíceis e difíceis para novatos como eu), mas isso funciona para meus projetos pessoais.

Aqui está o 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>

Obrigado!

Fernando aguirre
fonte
3
Bem, parabéns por este! Esta é de longe a resposta mais simples / sem trocas deste tópico! Deveria estar recebendo muito mais votos "positivos". Tenho que admitir que fiquei meio séptico sobre isso, especialmente sobre o que estava acontecendo sob o capô. Eu até verifiquei a árvore WFP e parece que a transparência não foi adicionada de volta. Mesmo controles complicados, como o 'WebBrowser', são exibidos perfeitamente. Tive um problema de congelamento de renderização usando transparência quando o aplicativo estava sob muito estresse ... Bem, isso não está acontecendo com esta solução. Acho que está na hora de aposentar a solução @Wobbles!
VeV
1
Parece que isso ainda pode precisar de interoperabilidade para arrastar a janela se eu interpretar o uso do Rectangle_PreviewMouseDownevento corretamente.
Wobbles
Isso pode não funcionar no <= Win 8.1, vi alguns resultados estranhos na minha VM. O Windows 7 e 8 são as principais preocupações, pois fazem a estúpida coisa da fronteira do Aero.
Wobbles
Obrigado pelas suas respostas
Fernando Aguirre
Olá @FernandoAguirre, postei esta questão relacionada e ficaria grato se você tiver uma resposta.
sampathsris
39

Embora a resposta aceita seja muito verdadeira, só quero salientar que AllowTransparency tem algumas desvantagens. Não permite que os controles da janela filho apareçam, ou seja, WebBrowser, e geralmente força a renderização do software, o que pode ter efeitos negativos no desempenho.

No entanto, existe uma solução melhor.

Quando você deseja criar uma janela sem borda redimensionável e capaz de hospedar um controle WebBrowser ou um controle Frame apontado para uma URL que você simplesmente não pode, o conteúdo do referido controle aparecerá vazio.

Eu encontrei uma solução alternativa; na janela, se você definir WindowStyle como None, ResizeMode como NoResize (tenha paciência, você ainda será capaz de redimensionar uma vez feito), então certifique-se de UNCHECKED AllowsTransparency, você terá uma janela de tamanho estático sem borda e mostrará o controle do navegador.

Agora, você provavelmente ainda deseja redimensionar, certo? Bem, podemos fazer isso com uma chamada de interoperabilidade:

    [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 pronto, uma janela WPF sem borda e ainda móvel e redimensionável sem perder compatibilidade com controles como o WebBrowser

Wobbles
fonte
O que devemos fazer se quisermos redimensionar de todos os lados, não apenas o canto inferior direito, mas ainda assim não queremos nenhuma borda visível?
Daniel
6
Aqui estão os outros valores de wParam, apenas atribua novos eventos a novos Objetos de IU usando-os conforme necessárioprivate enum ResizeDirection { Left = 61441, Right = 61442, Top = 61443, TopLeft = 61444, TopRight = 61445, Bottom = 61446, BottomLeft = 61447, BottomRight = 61448, }
Wobbles
Isso funciona muito bem para mim, com uma exceção, embora uma vez que você tenha o NoResize, você não pode mais ajustar a janela arrastando-a para o topo.
CJK
2
@CJK Verdadeiro, mas sem dúvida você também pode ligar as mensagens do Windows para isso e lidar com isso.
Wobbles
Não consigo arrastar a janela. alguma ideia do porquê? (redimensionar funciona
perfeitamente
5

Amostra aqui:

<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
fonte
23
Você deve incluir uma breve explicação de como o código funciona.
M456 de
0

Eu estava tendo dificuldade em obter a resposta de @fernando-aguirre usando WindowChromepara trabalhar. Não estava funcionando no meu caso porque eu estava substituindo OnSourceInitializedno MainWindowe não chamando o método da classe base.

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

Isso me deixou perplexo por muito tempo.

Mike Ward
fonte