2

首先是窗口本身的 XAML 代码:

<!-- Window Main -->
<Window
    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" mc:Ignorable="d" x:Name="Window_Main" x:Class="WPF_Test.General_Window"
    Title="General_Window" Height="500" Width="1000" BorderThickness="30"  ResizeMode="CanResizeWithGrip" AllowsTransparency="True" WindowStyle="None" StateChanged="Window_Main_StateChanged">
<!-- Effects -->
<Window.Effect>
    <DropShadowEffect x:Name="Border_Effect" ShadowDepth="0" BlurRadius="30" Direction="0" Opacity="0.5"/>
</Window.Effect>
<!-- Border Main -->
<Border x:Name="Border_Main" BorderBrush="Gray" BorderThickness="1">
    <!-- Panel Main -->
    <DockPanel x:Name="Panel_Main">
        <DockPanel x:Name="Panel_Title" Height="25" LastChildFill="False" Background="#FFEEEEEE" MouseDown="Panel_Title_MouseDown" VerticalAlignment="Top" DockPanel.Dock="Top">

        </DockPanel>
        <DockPanel x:Name="Panel_Secondary" LastChildFill="true" Background="#FFEEEEEE"/>
    </DockPanel>
</Border>

这是该窗口的构造函数的 C# 代码,我在其中明确定义了窗口的最小大小,但是在重新调整大小时它们仍然被忽略:

public void Window_Init()
    {

        Window_Main.MinHeight = Window_Minimum_Height + Window_Thickness * 2;
        Window_Main.MinWidth = Window_Minimum_Width + Window_Thickness * 2;
        Window_Main.BorderThickness = new Thickness( Window_Thickness );
    }

因此,当我使用ResizeGrip(由CanResizeWithGrip属性提供)重新调整窗口大小时,窗口本身将在达到最小宽度和高度时停止重新调整大小。虽然完全包含窗口的渲染区域仍然可以重新调整到更小的尺寸,所以它看起来就像桌面上窗口的截断图像。

4

1 回答 1

5

I've resolved the bug. You can use the grip resizer or create your own resizing controls , Using OnMouseDown event to send a message to HWND to resize the window while it doesn't pass the minimum sizes you have previously defined for the window. This code will limit the window size when maximizing as well to ensure that the window will never be outside of the screen or rendered over the task-bar.

This supposed to be at the bottom of your MainWindow.cs code:

        private const int WM_SYSCOMMAND = 0X112;
    private HwndSource hwndSource;
    enum SWP : uint
    {
        NOSIZE = 0x0001 ,
        NOMOVE = 0x0002 ,
        NOZORDER = 0x0004 ,
        NOREDRAW = 0x0008 ,
        NOACTIVATE = 0x0010 ,
        FRAMECHANGED = 0x0020 ,  
        SHOWWINDOW = 0x0040 ,
        HIDEWINDOW = 0x0080 ,
        NOCOPYBITS = 0x0100 ,
        NOOWNERZORDER = 0x0200 , 
        NOSENDCHANGING = 0x0400 , 
    }
    public override void OnApplyTemplate()
    {
        System.IntPtr handle = ( new WindowInteropHelper( this ) ).Handle;
        HwndSource.FromHwnd( handle ).AddHook( new HwndSourceHook( WindowProc ) );
    }
    private System.IntPtr WindowProc( System.IntPtr hwnd , int msg , System.IntPtr wParam , System.IntPtr lParam , ref bool handled )
    {
        switch ( msg )
        {
            case 0x0024:
                {
                    WmGetMinMaxInfo( hwnd , lParam );
                    handled = true;
                    break;
                }
            case 0x0046:
                {
                    WINDOWPOS pos = ( WINDOWPOS )Marshal.PtrToStructure( lParam , typeof( WINDOWPOS ) );
                    if ( ( pos.flags & ( int )(SWP.NOMOVE) ) != 0 )
                    {
                        return IntPtr.Zero;
                    }

                    Window wnd = ( Window )HwndSource.FromHwnd( hwnd ).RootVisual;
                    if ( wnd == null )
                    {
                        return IntPtr.Zero;
                    }

                    bool changedPos = false;
                    if ( pos.cx < MinWidth ) { pos.cx = (int)MinWidth; changedPos = true; }
                    if ( pos.cy < MinHeight ) { pos.cy = ( int )MinHeight; changedPos = true; }
                    if ( !changedPos )
                    {
                        return IntPtr.Zero;
                    }

                    Marshal.StructureToPtr( pos , lParam , true );
                    handled = true;
                    break;
                }
        }
        return ( System.IntPtr )0;
    }
    private void WmGetMinMaxInfo( System.IntPtr hwnd , System.IntPtr lParam )
    {
        MINMAXINFO mmi = ( MINMAXINFO )Marshal.PtrToStructure( lParam , typeof( MINMAXINFO ) );
        int MONITOR_DEFAULTTONEAREST = 0x00000002;
        System.IntPtr monitor = MonitorFromWindow( hwnd , MONITOR_DEFAULTTONEAREST );
        if ( monitor != System.IntPtr.Zero )
        {
            MONITORINFO monitorInfo = new MONITORINFO();
            GetMonitorInfo( monitor , monitorInfo );
            RECT rcWorkArea = monitorInfo.rcWork;
            RECT rcMonitorArea = monitorInfo.rcMonitor;
            mmi.ptMaxPosition.x = Math.Abs( rcWorkArea.left - rcMonitorArea.left );
            mmi.ptMaxPosition.y = Math.Abs( rcWorkArea.top - rcMonitorArea.top );
            mmi.ptMaxSize.x = Math.Abs( rcWorkArea.right - rcWorkArea.left );
            mmi.ptMaxSize.y = Math.Abs( rcWorkArea.bottom - rcWorkArea.top );
        }
        Marshal.StructureToPtr( mmi , lParam , true );
    }
    [StructLayout( LayoutKind.Sequential )]
    public struct POINT
    {
        public int x;
        public int y;
        public POINT( int x , int y )
        {
            this.x = x;
            this.y = y;
        }
    }
    [StructLayout( LayoutKind.Sequential )]
    public struct MINMAXINFO
    {
        public POINT ptReserved;
        public POINT ptMaxSize;
        public POINT ptMaxPosition;
        public POINT ptMinTrackSize;
        public POINT ptMaxTrackSize;
    };
    [StructLayout( LayoutKind.Sequential , CharSet = CharSet.Auto )]
    public class MONITORINFO
    {
        public int cbSize = Marshal.SizeOf( typeof( MONITORINFO ) );
        public RECT rcMonitor = new RECT();
        public RECT rcWork = new RECT();
        public int dwFlags = 0;
    }
    [StructLayout( LayoutKind.Sequential , Pack = 0 )]
    public struct RECT
    {
        public int left;
        public int top;
        public int right;
        public int bottom;
        public static readonly RECT Empty = new RECT();
        public int Width
        {
            get { return Math.Abs( right - left ); }
        }
        public int Height
        {
            get { return bottom - top; }
        }
        public RECT( int left , int top , int right , int bottom )
        {
            this.left = left;
            this.top = top;
            this.right = right;
            this.bottom = bottom;
        }
        public RECT( RECT rcSrc )
        {
            this.left = rcSrc.left;
            this.top = rcSrc.top;
            this.right = rcSrc.right;
            this.bottom = rcSrc.bottom;
        }
        public bool IsEmpty
        {
            get
            {
                return left >= right || top >= bottom;
            }
        }
        public override string ToString()
        {
            if ( this == RECT.Empty ) { return "RECT {Empty}"; }
            return "RECT { left : " + left + " / top : " + top + " / right : " + right + " / bottom : " + bottom + " }";
        }
        public override bool Equals( object obj )
        {
            if ( !( obj is Rect ) ) { return false; }
            return ( this == ( RECT )obj );
        }
        public override int GetHashCode()
        {
            return left.GetHashCode() + top.GetHashCode() + right.GetHashCode() + bottom.GetHashCode();
        }
        public static bool operator ==( RECT rect1 , RECT rect2 )
        {
            return ( rect1.left == rect2.left && rect1.top == rect2.top && rect1.right == rect2.right && rect1.bottom == rect2.bottom );
        }
        public static bool operator !=( RECT rect1 , RECT rect2 )
        {
            return !( rect1 == rect2 );
        }
    }
    [DllImport( "user32" )]
    internal static extern bool GetMonitorInfo( IntPtr hMonitor , MONITORINFO lpmi );
    [DllImport( "User32" )]
    internal static extern IntPtr MonitorFromWindow( IntPtr handle , int flags );
    [StructLayout( LayoutKind.Sequential )]
    internal struct WINDOWPOS
    {
        public IntPtr hwnd;
        public IntPtr hwndInsertAfter;
        public int x;
        public int y;
        public int cx;
        public int cy;
        public int flags;
    }
    private void InitializeWindowSource( object sender , EventArgs e )
    {
        hwndSource = PresentationSource.FromVisual( ( Visual )sender ) as HwndSource;
    }
    public enum ResizeDirection
    {
        Left = 1 ,
        Right = 2 ,
        Top = 3 ,
        TopLeft = 4 ,
        TopRight = 5 ,
        Bottom = 6 ,
        BottomLeft = 7 ,
        BottomRight = 8 ,
    }
    [DllImport( "user32" , CharSet = CharSet.Auto )]
    private static extern IntPtr SendMessage( IntPtr hWnd , uint Msg , IntPtr wParam , IntPtr lParam );
    private void ResizeWindow( ResizeDirection direction )
    {
        SendMessage( hwndSource.Handle , WM_SYSCOMMAND , ( IntPtr )( 61440 + direction ) , IntPtr.Zero );

    }

And do not forget to add this line to your window's constructor, otherwise nothing shall work:

SourceInitialized += new EventHandler( InitializeWindowSource );
于 2013-02-22T01:01:48.283 回答