Bagaimana cara membuat Jendela WPF tanpa pembatas yang dapat diubah ukurannya hanya melalui pegangan?

94

Jika Anda mengatur ResizeMode="CanResizeWithGrip"pada WPF Windowmaka pegangan pengubah ukuran ditampilkan di sudut kanan bawah, seperti di bawah ini:

Jika Anda juga menyetel WindowStyle="None"bilah judul menghilang tetapi tepi miring abu-abu tetap ada hingga Anda menyetelnya ResizeMode="NoResize". Sayangnya, dengan kombinasi set properti ini, pegangan pengubah ukuran juga menghilang.

Saya telah mengganti Window's ControlTemplatemelalui kebiasaan Style. Saya ingin menentukan sendiri batas jendela, dan saya tidak membutuhkan pengguna untuk dapat mengubah ukuran jendela dari keempat sisi, tetapi saya membutuhkan pegangan pengubah ukuran.

Bisakah seseorang merinci cara sederhana untuk memenuhi semua kriteria ini?

  1. Jangan beri batas di bagian Windowsamping dari yang saya tentukan sendiri di a ControlTemplate.
  2. Apakah memiliki pegangan pengubah ukuran yang berfungsi di sudut kanan bawah.
  3. Tidak memiliki bilah judul.
Drew Noakes
sumber
3
Harap dicatat bahwa Allowtransperency menciptakan kebocoran memori. Jadi hindari menggunakannya. Silakan merujuk ke social.msdn.microsoft.com/Forums/en/wpf/thread/…
Dipesh Bhatt
1
@DipeshBhatt Saya tidak dapat menemukan penjelasan apa pun atas klaim tersebut di tautan yang Anda berikan. mungkin Anda bermaksud untuk memposting tautan social.msdn.microsoft.com/Forums/vstudio/en-US/…
itsho
Saya menghadap tepi abu-abu di bagian atas meskipun saya telah mengatur gaya jendela ke Tidak Ada. ResizeMode = "NoResize" menyelesaikan masalah saya.
Surendra Shrestha

Jawaban:

180

Jika Anda menyetel AllowsTransparencyproperti pada Window(bahkan tanpa menyetel nilai transparansi apa pun) batasnya menghilang dan Anda hanya dapat mengubah ukurannya melalui pegangan.

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

Hasilnya terlihat seperti:

ZombieSheep
sumber
Kebetulan saja Saya tahu ini - Saya bermain dengan kontrol yang sama yang saya set sendiri sore ini. :)
ZombieSheep
2
Wow, saya tidak akan mengharapkan ini, tetapi ini sangat berguna untuk membuat-catatan-tempel-Anda-sendiri-dalam-5-menit, terima kasih :)
Tomáš Kafka
4
AllowTransparency memiliki beberapa downfalls meskipun, Windows tidak dapat lagi menjadi tuan rumah kontrol sub jendela seperti WebBrowser, Biasanya memaksa rendering perangkat lunak, telah melaporkan kebocoran memori. Lihat solusi saya di bawah ini.
Berguncang pada
Anda hanya perlu WindowStyle = "Tidak ada" untuk menghilangkan perbatasan; AllowsTransparency kebetulan hanya membutuhkannya, tetapi tidak mempengaruhi perbatasan ..
Grault
2
@Grault thats menghilangkan header jendela, tapi masih ada batas padat di sekitar formulir. AllowsTransparency menghilangkan perbatasan.
Goyangan
79

Saya mencoba membuat jendela tanpa bingkai dengan WindowStyle="None"tetapi ketika saya mengujinya, tampaknya muncul bilah putih di bagian atas, setelah beberapa penelitian tampaknya menjadi "Ubah ukuran bingkai", berikut adalah gambar (saya berkomentar dengan warna kuning):

Tantangan

Setelah beberapa penelitian melalui internet, dan banyak solusi non xaml yang sulit, semua solusi yang saya temukan adalah kode di belakang dalam C # dan banyak baris kode, saya menemukan secara tidak langsung solusinya di sini: Jendela kustom maksimum kehilangan efek bayangan drop

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

Catatan : Anda perlu menggunakan kerangka kerja .NET 4.5, atau jika Anda menggunakan versi yang lebih lama gunakan WPFShell, cukup rujuk shell dan gunakan Shell:WindowChrome.WindowChromesebagai gantinya.

Saya menggunakan WindowChromeproperti Window, jika Anda menggunakan ini, "batas ubah ukuran" putih menghilang, tetapi Anda perlu menentukan beberapa properti untuk bekerja dengan benar.

CaptionHeight: Ini adalah ketinggian area teks (headerbar) yang memungkinkan Aero snap, perilaku klik ganda seperti yang dilakukan bilah judul normal. Setel ini ke 0 (nol) untuk membuat tombol berfungsi.

ResizeBorderThickness: Ini adalah ketebalan di tepi jendela tempat Anda dapat mengubah ukuran jendela. Saya menempatkan 5 karena saya suka angka itu, dan karena jika Anda meletakkan nol sulit untuk mengubah ukuran jendela.

Setelah menggunakan kode singkat ini hasilnya adalah:

Solusinya

Dan sekarang, batas putih menghilang tanpa menggunakan ResizeMode="NoResize"dan AllowsTransparency="True", juga itu menunjukkan bayangan di jendela.

Nanti saya akan menjelaskan cara membuat tombol bekerja (saya tidak menggunakan gambar untuk tombol) dengan mudah dengan kode yang sederhana dan pendek, saya baru dan saya pikir saya dapat memposting ke codeproject, karena di sini saya tidak menemukan tempatnya untuk memposting tutorial.

Mungkin ada solusi lain (saya tahu bahwa ada solusi yang sulit dan sulit untuk pemula seperti saya) tetapi ini berfungsi untuk proyek pribadi saya.

Ini kode lengkapnya

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

Terima kasih!

Fernando Aguirre
sumber
3
Nah, Kudos untuk yang satu ini! Sejauh ini, ini adalah jawaban paling sederhana / tidak ada trade off dari utas ini! Harus mendapatkan lebih banyak suara 'naik'. Saya harus mengakui bahwa saya agak septik tentang itu, terutama tentang apa yang terjadi di bawah tenda. Saya bahkan memeriksa pohon WFP dan sepertinya transparansi tidak ditambahkan kembali. Bahkan kontrol rumit seperti tampilan 'WebBrowser' baik-baik saja. Saya mengalami masalah rendering pembekuan menggunakan transparansi saat aplikasi mengalami banyak tekanan ... Nah, ini tidak terjadi dengan solusi ini. Saya pikir mungkin sudah waktunya untuk menghentikan solusi @Wobbles!
VeV
1
Sepertinya ini masih perlu interop untuk menyeret jendela jika saya menafsirkan penggunaan Rectangle_PreviewMouseDownacara dengan benar.
Goyangan
Ini mungkin tidak berfungsi di <= Win 8.1, melihat beberapa hasil aneh di VM saya. Windows 7 & 8 adalah masalah utama karena mereka melakukan hal perbatasan Aero yang bodoh.
Goyangan
Terima kasih atas balasan Anda
Fernando Aguirre
Hai @FernandoAguirre, Saya memposting pertanyaan terkait ini , dan akan berterima kasih jika Anda memiliki jawabannya.
sampathsris
40

Meskipun jawaban yang diterima sangat benar, hanya ingin menunjukkan bahwa AllowTransparency memiliki beberapa kelemahan. Ini tidak mengizinkan kontrol jendela anak muncul, yaitu WebBrowser, dan biasanya memaksa rendering perangkat lunak yang dapat memiliki efek kinerja negatif.

Ada solusi yang lebih baik.

Saat Anda ingin membuat jendela tanpa batas yang dapat diubah ukurannya dan dapat menjadi tuan rumah kontrol WebBrowser atau kontrol Frame menunjuk ke URL yang tidak bisa Anda lakukan, konten kontrol tersebut akan ditampilkan kosong.

Saya menemukan solusi; di Window, jika Anda mengatur WindowStyle ke None, ResizeMode ke NoResize (bersabarlah, Anda masih dapat mengubah ukuran setelah selesai) maka pastikan Anda memiliki AllowsTransparency UNCHECKED Anda akan memiliki jendela berukuran statis tanpa batas dan akan ditampilkan kontrol browser.

Sekarang, Anda mungkin masih ingin mengubah ukuran, bukan? Kita bisa melakukannya dengan panggilan interop:

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

Dan voila, Jendela WPF tanpa batas dan masih dapat dipindahkan dan diubah ukurannya tanpa kehilangan kompatibilitas dengan kontrol seperti WebBrowser

Goyangan
sumber
Bagaimana kita melakukannya jika kita ingin mengubah ukuran dari semua sisi, bukan hanya kanan bawah, tetapi masih ingin tidak ada batas yang terlihat?
Daniel
6
Berikut adalah nilai wParam lainnya, cukup tetapkan acara baru ke Objek UI baru menggunakan ini sesuai kebutuhanprivate enum ResizeDirection { Left = 61441, Right = 61442, Top = 61443, TopLeft = 61444, TopRight = 61445, Bottom = 61446, BottomLeft = 61447, BottomRight = 61448, }
Wobbles
Ini berfungsi dengan baik untuk saya, dengan satu pengecualian meskipun begitu Anda memiliki NoResize, Anda tidak dapat menjepret jendela dengan menyeretnya ke atas lagi.
CJK
2
@CJK Benar, tetapi tidak diragukan lagi Anda dapat mengaitkan pesan windows untuk itu juga dan menanganinya.
Goyangan
Saya tidak bisa menyeret jendela. tahu kenapa? (ubah ukuran berfungsi seperti pesona)
Li3ro
5

Contoh di sini:

<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
sumber
23
Anda harus menyertakan penjelasan singkat tentang cara kerja kode.
M456
0

Saya mengalami kesulitan mendapatkan jawaban oleh @ fernando-aguirre menggunakan WindowChromeuntuk bekerja. Itu tidak bekerja dalam kasus saya karena saya meng-override OnSourceInitializeddalam MainWindowdan tidak memanggil metode kelas dasar.

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

Ini membuat saya bingung untuk waktu yang sangat lama.

Mike Ward
sumber