1. 程式人生 > >WPF 自定義窗體實現拖動邊框改變窗體大小(2種方法)

WPF 自定義窗體實現拖動邊框改變窗體大小(2種方法)

方式一:呼叫user32.dllAPI

這種方式在網上有很多,這裡只是按步驟重新建立一次。讀者只需要跟著做就行。

第一步:建立一個WPF專案:WpfResizeWithoutBorder,右鍵專案檔案---->新增----->資源字典,並命名為:WindowsResizeBorderTemplete.xaml。

第二步:在剛剛建立的資原始檔(WindowsResizeBorderTemplete.xaml)中複製如下程式碼:

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

    <ControlTemplate x:Key="CustomWindowTemplete" TargetType="Window">
        <Border BorderBrush="Transparent" BorderThickness="12" x:Name="outBorder">
            <Border.Effect>
                <DropShadowEffect BlurRadius="15" Color="#000000" Opacity=".25" Direction="90" ShadowDepth="1"/>
            </Border.Effect>
            <Grid>
                <Grid.RowDefinitions>
                    <RowDefinition Height="1"/>
                    <RowDefinition/>
                    <RowDefinition Height="1"/>
                </Grid.RowDefinitions>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="1"/>
                    <ColumnDefinition/>
                    <ColumnDefinition Width="1"/>
                </Grid.ColumnDefinitions>
                <Grid Grid.Row="1" Grid.Column="1" Background="White" >
                    <AdornerDecorator>
                        <ContentPresenter></ContentPresenter>
                    </AdornerDecorator>
                </Grid>
                <Rectangle Name="ResizeTopLeft" Fill="Red" Grid.Row="0" Grid.Column="0" Opacity=".25"/>
                <Rectangle Name="ResizeTop" Fill="Red" Grid.Row="0" Grid.Column="1" Opacity=".25"/>
                <Rectangle Name="ResizeTopRight" Fill="Red" Grid.Row="0" Grid.Column="2" Opacity=".25"/>
                <Rectangle Name="ResizeLeft" Fill="Red" Grid.Row="1" Grid.Column="0" Opacity=".25"/>
                <Rectangle Name="ResizeRight" Fill="Red" Grid.Row="1" Grid.Column="2" Opacity=".25"/>
                <Rectangle Name="ResizeBottomLeft" Fill="Red" Grid.Row="2" Grid.Column="0" Opacity=".25"/>
                <Rectangle Name="ResizeBottom" Fill="Red" Grid.Row="2" Grid.Column="1" Opacity=".25"/>
                <Rectangle Name="ResizeBottomRight" Fill="Red" Grid.Row="2" Grid.Column="2" Opacity=".25"/>
            </Grid>
        </Border>
    </ControlTemplate>

    <Style x:Key="CustomWindow" TargetType="Window">
        <Setter Property="AllowsTransparency" Value="True"/>
        <Setter Property="WindowStyle" Value="None"/>
        <Setter Property="Template" Value="{StaticResource CustomWindowTemplete}"></Setter>
    </Style>

</ResourceDictionary>

 

第三步:新增一個類檔案:VcreditWindowBehindCode.cs,複製程式碼如下:

///Editor:Mey Eaphone
///Date:20180929
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Interop;
using System.Windows.Media;
using System.Windows.Shapes;

namespace WpfResizeWithoutBorder
{
    public class VcreditWindowBehindCode : Window
    {
        public const int WM_SYSCOMMAND = 0x112;
        public HwndSource HwndSource;

        public Dictionary<ResizeDirection, Cursor> cursors = new Dictionary<ResizeDirection, Cursor>
        {
            {ResizeDirection.Top, Cursors.SizeNS},
            {ResizeDirection.Bottom, Cursors.SizeNS},
            {ResizeDirection.Left, Cursors.SizeWE},
            {ResizeDirection.Right, Cursors.SizeWE},
            {ResizeDirection.TopLeft, Cursors.SizeNWSE},
            {ResizeDirection.BottomRight, Cursors.SizeNWSE},
            {ResizeDirection.TopRight, Cursors.SizeNESW},
            {ResizeDirection.BottomLeft, Cursors.SizeNESW}
        };

        public enum ResizeDirection
        {
            Left = 1,
            Right = 2,
            Top = 3,
            TopLeft = 4,
            TopRight = 5,
            Bottom = 6,
            BottomLeft = 7,
            BottomRight = 8,
        }

        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        public static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);


        public VcreditWindowBehindCode()
        {
            this.SourceInitialized += VcreditWindowBehindCode_SourceInitialized;
            this.Loaded += VcreditWindowBehindCode_Loaded;
            this.MouseMove += VcreditWindowBehindCode_MouseMove;
        }

        private void VcreditWindowBehindCode_MouseMove(object sender, MouseEventArgs e)
        {
            if (Mouse.LeftButton != MouseButtonState.Pressed)
            {
                FrameworkElement element = e.OriginalSource as FrameworkElement;
                if (element != null && !element.Name.Contains("Resize"))
                {
                    this.Cursor = Cursors.Arrow;
                }
            }
        }

        private void VcreditWindowBehindCode_SourceInitialized(object sender, EventArgs e)
        {
            this.HwndSource = PresentationSource.FromVisual((Visual)sender) as HwndSource;
        }

        private void VcreditWindowBehindCode_Loaded(object sender, RoutedEventArgs e)
        {
            ControlTemplate customWindowTemplate = App.Current.Resources["CustomWindowTemplete"] as ControlTemplate;
            if (customWindowTemplate != null)
            {
                var TopLeft = customWindowTemplate.FindName("ResizeTopLeft", this) as Rectangle;
                TopLeft.MouseMove += ResizePressed;
                TopLeft.MouseDown += ResizePressed;
                var Top = customWindowTemplate.FindName("ResizeTop", this) as Rectangle;
                Top.MouseMove += ResizePressed;
                Top.MouseDown += ResizePressed;
                var TopRight = customWindowTemplate.FindName("ResizeTopRight", this) as Rectangle;
                TopRight.MouseMove += ResizePressed;
                TopRight.MouseDown += ResizePressed;
                var Left = customWindowTemplate.FindName("ResizeLeft", this) as Rectangle;
                Left.MouseMove += ResizePressed;
                Left.MouseDown += ResizePressed;
                var Right = customWindowTemplate.FindName("ResizeRight", this) as Rectangle;
                Right.MouseMove += ResizePressed;
                Right.MouseDown += ResizePressed;
                var BottomLeft = customWindowTemplate.FindName("ResizeBottomLeft", this) as Rectangle;
                BottomLeft.MouseMove += ResizePressed;
                BottomLeft.MouseDown += ResizePressed;
                var Bottom = customWindowTemplate.FindName("ResizeBottom", this) as Rectangle;
                Bottom.MouseMove += ResizePressed;
                Bottom.MouseDown += ResizePressed;
                var BottomRight = customWindowTemplate.FindName("ResizeBottomRight", this) as Rectangle;
                BottomRight.MouseMove += ResizePressed;
                BottomRight.MouseDown += ResizePressed;
            }
        }

        public void ResizePressed(object sender, MouseEventArgs e)
        {
            FrameworkElement element = sender as FrameworkElement;
            ResizeDirection direction = (ResizeDirection)Enum.Parse(typeof(ResizeDirection), element.Name.Replace("Resize", ""));
            this.Cursor = cursors[direction];
            if (e.LeftButton == MouseButtonState.Pressed)
            {
                ResizeWindow(direction);
            }
        }

        public void ResizeWindow(ResizeDirection direction)
        {
            SendMessage(HwndSource.Handle, WM_SYSCOMMAND, (IntPtr)(61440 + direction), IntPtr.Zero);
        }
    }
}

第四步:再右鍵專案檔案,新增一個窗體,命名為Window3.xaml。並在檔案資源管理器中找到Window3.xaml.cs並點選刪除。然後在建立一個類檔案Window3.cs。此時專案結構如下所示。

第五步:開啟Window3.xaml檔案,將複製程式碼如下:

<local:VcreditWindowBehindCode  x:Class="WpfResizeWithoutBorder.Window3"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WpfResizeWithoutBorder"
        Title="MainWindow" Height="350" Width="525"
        WindowStyle="None" ResizeMode="CanResizeWithGrip" AllowsTransparency="True"
                                 Style="{StaticResource CustomWindow}"           
        >

    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="50"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        <Canvas Name="nav_Bar" Grid.Row="0" Background="Blue">
            <Button Name="btnMax" Content="Max" Canvas.Left="375" Canvas.Top="10" Width="75"/>
        </Canvas>
    </Grid>
</local:VcreditWindowBehindCode>

 

第六步:開啟Window3.cs檔案,然後將程式碼複製如下

///Editor:Mey Eaphone
///Date:20180929
using System.Windows.Controls;
using System.Windows.Input;
namespace WpfResizeWithoutBorder
{
    /// <summary>
    /// 
    /// </summary>
    public partial class Window3:VcreditWindowBehindCode
    {
        /// <summary>
        /// 
        /// </summary>
        public Window3()
        {
            InitializeComponent();
            InitializeRouted();
        }

        /// <summary>
        /// 初始化事件
        /// </summary>
        private void InitializeRouted()
        {
            nav_Bar.AddHandler(Canvas.MouseDownEvent, new MouseButtonEventHandler(Window3_MouseMove),true);
            btnMax.AddHandler(Button.MouseDoubleClickEvent, new MouseButtonEventHandler(Window3_Maxied), true);
        }

        /// <summary>
        /// 最大普通化
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Window3_Maxied(object sender, MouseButtonEventArgs e)
        {
            if (this.WindowState == System.Windows.WindowState.Normal)
            {
                this.WindowState = System.Windows.WindowState.Maximized;
            }
            else
            {
                this.WindowState = System.Windows.WindowState.Normal;
            }
        }

        /// <summary>
        /// 窗體拖動
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Window3_MouseMove(object sender, System.Windows.Input.MouseEventArgs e)
        {
            this.DragMove();
        }        
    }
}

第七步:開啟App.xaml檔案,將複製程式碼,修改為:

<Application x:Class="WpfResizeWithoutBorder.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             StartupUri="Window3.xaml">
    <Application.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="WindowsResizeBorderTemplete.xaml"/>
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Application.Resources>
</Application>

最後F5檢視效果。

 

方式二:直接使用WindowChrome(.Net4.5.1以上)

第一種方式非常複雜,在.net4.5.1之後,迎來了革新的東西——WindowChrome,使用方法很簡單。

第一步:新建窗體Window1.xaml,開啟檔案,並複製程式碼如下:

<Window x:Class="WpfResizeWithoutBorder.Window1"
        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:WpfResizeWithoutBorder"
        mc:Ignorable="d"
        Title="Window1" Height="450" Width="800">
    <Window.Style>
        <Style TargetType="Window">
            <Setter Property="Background" Value="Transparent" />
            <Setter Property="WindowStyle" Value="None" />
            <Setter Property="ResizeMode" Value="CanResize" />
            <Setter Property="AllowsTransparency" Value="True" />
            <Setter Property="WindowChrome.WindowChrome">
                <Setter.Value>
                    <WindowChrome CaptionHeight="80" ResizeBorderThickness="20" />
                </Setter.Value>
            </Setter>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="Window">
                        <Border Padding="10">
                            <Border Background="White"
                                    BorderBrush="Black"
                                    BorderThickness="1"
                                    CornerRadius="4"
                                    SnapsToDevicePixels="True">
                                <!--陰影效果-->
                                <!--<Border.Effect>
                                    <DropShadowEffect BlurRadius="10"
                                                      Direction="0"
                                                      ShadowDepth="0" />
                                </Border.Effect>-->
                                <ContentPresenter />
                            </Border>
                        </Border>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </Window.Style>
</Window>

第二步:修改App.xaml檔案的啟動連結,複製程式碼如下:

<Application x:Class="WpfResizeWithoutBorder.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             StartupUri="Window1.xaml">
    <Application.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="WindowsResizeBorderTemplete.xaml"/>
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Application.Resources>
</Application>

最後F5,出現的效果是不是你想要的,是不是很簡單。

 

總結:

1.方法一比較複雜,但是我們很清楚從無到有的整個過程,值得我們深入學習研究。

2.方法二簡單粗暴,使用.net新屬性,分分鐘搞定,實用性高。