Как создать окно WPF без рамки, размер которой можно изменить только с помощью ручки?

95

Если вы настроили ResizeMode="CanResizeWithGrip"WPF, Windowв правом нижнем углу отображается ручка изменения размера, как показано ниже:

Если вы WindowStyle="None"также установили, строка заголовка исчезнет, ​​но серый скошенный край останется, пока вы не установите ResizeMode="NoResize". К сожалению, при установке этой комбинации свойств ручка изменения размера также исчезает.

Я переопределил Window's ControlTemplateчерез custom Style. Я хочу сам указать границу окна, и мне не нужно, чтобы пользователи могли изменять размер окна со всех четырех сторон, но мне нужна ручка изменения размера.

Может ли кто-нибудь подробно описать простой способ соответствовать всем этим критериям?

  1. Не иметь границы, Windowкроме той, которую я сам указал в ControlTemplate.
  2. У вас есть рабочая ручка изменения размера в правом нижнем углу.
  3. Нет строки заголовка.
Дрю Ноукс
источник
3
Обратите внимание, что Allowtransperency создает утечку памяти. Так что избегайте его использования. См. Social.msdn.microsoft.com/Forums/en/wpf/thread/…
Дипеш Бхатт,
1
@DipeshBhatt Я не смог найти никакого объяснения этому утверждению в предоставленной вами ссылке. возможно, вы хотели опубликовать ссылку social.msdn.microsoft.com/Forums/vstudio/en-US/…
itsho
Я смотрел на серый край вверху, хотя я установил стиль окна на Нет. ResizeMode = "NoResize" решил мою проблему.
Сурендра Шреста

Ответы:

184

Если вы установите AllowsTransparencyсвойство на Window(даже без установки каких-либо значений прозрачности), граница исчезнет, ​​и вы сможете изменить размер только с помощью ручки.

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

Результат выглядит так:

ЗомбиОвца
источник
Чистая случайность. Я знал это - сегодня днем ​​я играл с той же системой управления. :)
ZombieSheep 04
2
Ого, я бы этого не ожидал, но это очень удобно для создания собственных заметок за 5 минут, спасибо :)
Томаш Кафка
4
Однако у AllowTransparency есть несколько недостатков: Windows больше не может размещать элементы управления подокнами, такие как WebBrowser, обычно принудительно выполняет программный рендеринг, сообщает об утечках памяти. См. Мой обходной путь ниже.
Wobbles
Вам нужно только WindowStyle = "None", чтобы избавиться от границ; AllowsTransparency только требует этого, но не влияет на границы ..
Граулт
2
@Grault избавляется от заголовка окна, но форма все еще остается сплошной рамкой. AllowsTransparency избавляется от границ.
Колебался
81

Я пытался создать окно без полей, WindowStyle="None"но когда я его протестировал, кажется, что вверху появляется белая полоса, после некоторых исследований она выглядит как «Изменение размера границы», вот изображение (я отметил желтым):

Соревнование

После некоторых исследований в Интернете и множества сложных решений, отличных от xaml, все решения, которые я нашел, были кодом на C # и множеством строк кода, я косвенно нашел решение здесь: максимальное настраиваемое окно теряет эффект тени

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

Примечание . Вам необходимо использовать платформу .NET 4.5. Если вы используете более старую версию, используйте WPFShell, просто укажите оболочку и используйте Shell:WindowChrome.WindowChromeвместо нее .

Я использовал WindowChromeсвойство Window, если вы используете его, белая «рамка изменения размера» исчезает, но вам нужно определить некоторые свойства для правильной работы.

CaptionHeight: это высота области заголовка (панель заголовка), которая позволяет выполнять привязку Aero, двойной щелчок, как это делает обычная строка заголовка. Установите значение 0 (ноль), чтобы кнопки работали.

ResizeBorderThickness: это толщина на краю окна, где вы можете изменить размер окна. Я поставил 5, потому что мне нравится это число, и потому что, если поставить ноль, трудно изменить размер окна.

После использования этого короткого кода результат будет следующим:

Решение

И вот белая рамка исчезла без использования ResizeMode="NoResize"и AllowsTransparency="True", также показывает тень в окне.

Позже я объясню, как заставить работать кнопки (я не использовал изображения для кнопок) легко с помощью простого и короткого кода, я новичок, и я думаю, что могу опубликовать в codeproject, потому что здесь я не нашел места опубликовать учебник.

Возможно, есть другое решение (я знаю, что для таких новичков, как я, есть сложные и трудные решения), но это работает для моих личных проектов.

Вот полный код

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

Спасибо!

Фернандо Агирре
источник
3
Ну, Престижность для этого! Это, безусловно, самый простой ответ в этой ветке! Должно быть гораздо больше голосов «за». Я должен признать, что был в некотором роде по этому поводу, особенно по поводу того, что происходило под капотом. Я даже проверил дерево WFP, и похоже, что прозрачность не добавляется обратно. Даже сложные элементы управления, такие как «WebBrowser», отлично отображаются. У меня была проблема с зависанием отрисовки при использовании прозрачности, когда приложение находилось в сильном стрессе ... Что ж, с этим решением этого не происходит. Думаю, пора отказаться от решения @Wobbles!
VeV
1
Похоже, что для перетаскивания окна может потребоваться взаимодействие, если я Rectangle_PreviewMouseDownправильно интерпретирую использование события.
Wobbles
Это может не работать в <= Win 8.1, в моей виртуальной машине наблюдались странные результаты. Windows 7 и 8 являются основными проблемами, поскольку они делают глупую границу с Aero.
Wobbles
Спасибо за ваш ответ
Фернандо Агирре
Привет, @FernandoAguirre, я разместил этот связанный вопрос , и был бы признателен, если у вас есть ответ.
sampathsris
40

Хотя принятый ответ очень верен, просто хочу отметить, что у AllowTransparency есть некоторые недостатки. Он не позволяет отображать дочерние элементы управления окнами, то есть WebBrowser, и обычно вызывает программный рендеринг, что может отрицательно сказаться на производительности.

Однако есть способ лучше.

Если вы хотите создать окно без границы, размер которого можно изменять и в котором можно разместить элемент управления WebBrowser или элемент управления Frame, указывающий на URL-адрес, который вы просто не могли, содержимое указанного элемента управления будет пустым.

Однако я нашел обходной путь; в окне, если вы установите WindowStyle на None, ResizeMode на NoResize (терпите меня, вы все равно сможете изменить размер после этого), затем убедитесь, что у вас UNCHECKED AllowsTransparency, у вас будет окно статического размера без рамки и будет управление браузером.

Теперь вы, вероятно, все еще хотите иметь возможность изменять размер, верно? Что ж, мы можем сделать это с помощью вызова взаимодействия:

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

И вуаля, окно WPF без рамки, которое можно перемещать и изменять размер без потери совместимости с такими элементами управления, как WebBrowser.

Колебания
источник
Что делать, если мы хотим изменить размер со всех сторон, а не только справа внизу, но при этом не хотим, чтобы граница была видимой?
Даниэль
6
Вот другие значения wParam, просто назначьте новые события новым объектам пользовательского интерфейса, используя их по мере необходимостиprivate enum ResizeDirection { Left = 61441, Right = 61442, Top = 61443, TopLeft = 61444, TopRight = 61445, Bottom = 61446, BottomLeft = 61447, BottomRight = 61448, }
Wobbles
Это отлично работает для меня, за одним исключением, хотя, если у вас есть NoResize, вы больше не можете привязать окно, перетаскивая его наверх.
CJK,
2
@CJK Верно, но, без сомнения, вы также можете перехватить сообщения Windows и обработать это.
Wobbles
Я не могу перетащить окно. есть идеи почему? (изменение размера работает как шарм)
Li3ro
5

Образец здесь:

<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>
Кебес
источник
24
Вы должны включить краткое объяснение того, как работает код.
M456
0

Мне не удалось получить ответ от @ fernando-aguirre, который использовал WindowChromeна работе. Это не работает в моем случае , потому что я был переопределения OnSourceInitializedв MainWindowи не вызвать метод базового класса.

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

Это меня очень долго ставило в тупик.

Майк Уорд
источник