WPF制作无边框窗体、圆角窗体、支持改变大小、拖动分屏等(二)

上节回顾

上节已经说到如何创建一个无边框窗体,那么这节就说说如何创建圆角窗体。


开整(分割线搞个仪式)


制作圆角窗体

思路:

圆角窗体比较麻烦,网上的实现思路也五花八门,例如:WinApi直接设置窗口句柄、双窗体重叠、透明窗体+Border等。本文得思路就是透明窗体+Border,因为在本猿测试的时候发现第一种方法很容易出错,句柄不兼容等,第二种方法在Tab切换视图的时候很容易看出来,而且拖动的时候有重影。所以选择第三种,但是第三种也不是最优方案,因为透明窗体很消耗性能,尤其是在窗口上布置很多动画的时候,所以最优方案就是不使用圆角窗体,哈哈哈,但是既然讲到了,那就先做做看吧,因为圆角窗体毕竟很好看。

圆角及阴影

实现圆角的思路采用透明窗体+Border,那么首先第一步需要把窗体变透明,通过设置WindowStyle=“None” ,AllowsTransparency=“True” ,Background=“Transparent”,然后在内容上设置一个Border,然后设置其背景颜色和圆角。阴影的实现就是给Border设置Effect属性,这样不仅可以设置阴影的颜色,还能设置阴影的范围,值得注意的是,阴影的范围应该小于Border的Margin的值,因为不管是什么内容,都不得超出Window的范围。

<Window x:Class="WpfApp1.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:local="clr-namespace:WpfApp1"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:window="若汝棋茗_Windows"
        Height="450"
        Width="800"
        Icon="{x:Null}"
        WindowStyle="None" AllowsTransparency="True" Background="Transparent"
        mc:Ignorable="d">
    <Border Background="White" CornerRadius="10" Margin="5">
        <Border.Effect>
            <DropShadowEffect ShadowDepth="0"/>
        </Border.Effect>
    </Border>
</Window>

窗体拖动、拖动分屏

拖动操作和上节讲的基本一样,这里就不累述了。

窗体改变尺寸

在上节讲到窗体改变尺寸的操作时,因为Window自带的Border还在,所以这块不需要我们关心,但是在圆角窗体中,这个操作就得自己执行了。我们的实现思路就是追加8个Rect,分别为上、下、左、右、左上、左下、右上、右下,然后每个Rect有自己的执行指令,最后利用WinMessage改变窗口尺寸。当然为以后window重写模板考虑,该处理应该在后台代码实现。
在这里插入图片描述

<Window x:Class="WpfApp1.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:local="clr-namespace:WpfApp1"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:window="若汝棋茗_Windows"
        Height="450"
        Width="800"
        AllowsTransparency="True"
        Background="Transparent"
        Icon="{x:Null}"
        WindowStyle="None"
        mc:Ignorable="d">
    <Grid x:Name="windowGrid">
        <Border x:Name="mainBorder" Margin="5" Background="White" CornerRadius="10">
            <Border.Effect>
                <DropShadowEffect ShadowDepth="0" />
            </Border.Effect>
        </Border>
    </Grid>

</Window>
namespace WpfApp1
{
    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            this.SourceInitialized += MainWindow_SourceInitialized;
        }
        private enum ResizeDirection
        {
            Left = 1,
            Right = 2,
            Top = 3,
            TopLeft = 4,
            TopRight = 5,
            Bottom = 6,
            BottomLeft = 7,
            BottomRight = 8,
        }
        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();
           
            RowDefinition row0 = new RowDefinition();
            row0.Height = new GridLength(10);
            RowDefinition row1 = new RowDefinition();
            RowDefinition row2 = new RowDefinition();
            row2.Height = new GridLength(10);

            ColumnDefinition column0 = new ColumnDefinition();
            column0.Width = new GridLength(10);
            ColumnDefinition column1 = new ColumnDefinition();
            ColumnDefinition column2 = new ColumnDefinition();
            column2.Width = new GridLength(10);

            windowGrid.RowDefinitions.Add(row0);
            windowGrid.RowDefinitions.Add(row1);
            windowGrid.RowDefinitions.Add(row2);
            windowGrid.ColumnDefinitions.Add(column0);
            windowGrid.ColumnDefinitions.Add(column1);
            windowGrid.ColumnDefinitions.Add(column2);

            mainBorder.SetValue(Grid.RowProperty, 0);
            mainBorder.SetValue(Grid.ColumnProperty, 0);
            mainBorder.SetValue(Grid.RowSpanProperty, 3);
            mainBorder.SetValue(Grid.ColumnSpanProperty, 3);

            AddResizeRectangle();
        }
        protected override void OnPreviewMouseMove(MouseEventArgs e)
        {
            base.OnPreviewMouseMove(e);
            if (e.LeftButton != MouseButtonState.Pressed)
                Cursor = Cursors.Arrow;
        }
        private void AddResizeRectangle()
        {
            Rectangle rect1 = new Rectangle() { Name = "TopLeft", Fill = Brushes.Transparent };
            rect1.SetValue(Grid.RowProperty, 0);
            rect1.SetValue(Grid.ColumnProperty, 0);

            Rectangle rect2 = new Rectangle() { Name = "Top", Fill = Brushes.Transparent };
            rect2.SetValue(Grid.RowProperty, 0);
            rect2.SetValue(Grid.ColumnProperty, 1);

            Rectangle rect3 = new Rectangle() { Name = "TopRight", Fill = Brushes.Transparent };
            rect3.SetValue(Grid.RowProperty, 0);
            rect3.SetValue(Grid.ColumnProperty, 2);

            Rectangle rect4 = new Rectangle() { Name = "Right", Fill = Brushes.Transparent };
            rect4.SetValue(Grid.RowProperty, 1);
            rect4.SetValue(Grid.ColumnProperty, 2);

            Rectangle rect5 = new Rectangle() { Name = "BottomRight", Fill = Brushes.Transparent };
            rect5.SetValue(Grid.RowProperty, 2);
            rect5.SetValue(Grid.ColumnProperty, 2);

            Rectangle rect6 = new Rectangle() { Name = "Bottom", Fill = Brushes.Transparent };
            rect6.SetValue(Grid.RowProperty, 2);
            rect6.SetValue(Grid.ColumnProperty, 1);

            Rectangle rect7 = new Rectangle() { Name = "BottomLeft", Fill = Brushes.Transparent };
            rect7.SetValue(Grid.RowProperty, 2);
            rect7.SetValue(Grid.ColumnProperty, 0);

            Rectangle rect8 = new Rectangle() { Name = "Left", Fill = Brushes.Transparent };
            rect8.SetValue(Grid.RowProperty, 1);
            rect8.SetValue(Grid.ColumnProperty, 0);

            windowGrid.Children.Add(rect1);
            windowGrid.Children.Add(rect2);
            windowGrid.Children.Add(rect3);
            windowGrid.Children.Add(rect4);
            windowGrid.Children.Add(rect5);
            windowGrid.Children.Add(rect6);
            windowGrid.Children.Add(rect7);
            windowGrid.Children.Add(rect8);

            foreach (var item in windowGrid.Children)
            {
                if (item is Rectangle)
                {
                    Rectangle resizeRectangle = (Rectangle)item;
                    resizeRectangle.PreviewMouseDown += ResizeRectangle_PreviewMouseDown;
                    resizeRectangle.MouseMove += ResizeRectangle_MouseMove;
                }
            }
        }
        private void ResizeRectangle_PreviewMouseDown(object sender, MouseButtonEventArgs e)
        {
            if (this.WindowState == WindowState.Maximized)
            {
                return;
            }
            Rectangle rectangle = sender as Rectangle;

            if (rectangle != null)
            {
                switch (rectangle.Name)
                {
                    case "Top":
                        Cursor = Cursors.SizeNS;
                        ResizeWindow(ResizeDirection.Top);
                        break;

                    case "Bottom":
                        Cursor = Cursors.SizeNS;
                        ResizeWindow(ResizeDirection.Bottom);
                        break;

                    case "Left":
                        Cursor = Cursors.SizeWE;
                        ResizeWindow(ResizeDirection.Left);
                        break;

                    case "Right":
                        Cursor = Cursors.SizeWE;
                        ResizeWindow(ResizeDirection.Right);
                        break;

                    case "TopLeft":
                        Cursor = Cursors.SizeNWSE;
                        ResizeWindow(ResizeDirection.TopLeft);
                        break;

                    case "TopRight":
                        Cursor = Cursors.SizeNESW;
                        ResizeWindow(ResizeDirection.TopRight);
                        break;

                    case "BottomLeft":
                        Cursor = Cursors.SizeNESW;
                        ResizeWindow(ResizeDirection.BottomLeft);
                        break;

                    case "BottomRight":
                        Cursor = Cursors.SizeNWSE;
                        ResizeWindow(ResizeDirection.BottomRight);
                        break;

                    default:
                        break;
                }
            }
        }
        private void ResizeRectangle_MouseMove(object sender, MouseEventArgs e)
        {
            if (this.WindowState == WindowState.Maximized)
            {
                return;
            }
            Rectangle rectangle = sender as Rectangle;

            if (rectangle != null)
            {
                switch (rectangle.Name)
                {
                    case "Top":
                        Cursor = Cursors.SizeNS;
                        break;

                    case "Bottom":
                        Cursor = Cursors.SizeNS;
                        break;

                    case "Left":
                        Cursor = Cursors.SizeWE;
                        break;

                    case "Right":
                        Cursor = Cursors.SizeWE;
                        break;

                    case "TopLeft":
                        Cursor = Cursors.SizeNWSE;
                        break;

                    case "TopRight":
                        Cursor = Cursors.SizeNESW;
                        break;

                    case "BottomLeft":
                        Cursor = Cursors.SizeNESW;
                        break;

                    case "BottomRight":
                        Cursor = Cursors.SizeNWSE;
                        break;

                    default:
                        break;
                }
            }
        }
        private HwndSource _hwndSource;
        private void MainWindow_SourceInitialized(object sender, EventArgs e)
        {
            _hwndSource = (HwndSource)PresentationSource.FromVisual(this);
        }
        private void ResizeWindow(ResizeDirection direction)
        {
            SendMessage(_hwndSource.Handle, 0x112, (IntPtr)(61440 + direction), IntPtr.Zero);
        }
        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        private static extern IntPtr SendMessage(IntPtr hWnd, UInt32 msg, IntPtr wParam, IntPtr lParam);
    }


}

窗体功能按钮

圆角窗体的功能按钮的创建方式和上节讲的一样,这里也就不累述了。

使用RRQMSkin创建圆角窗体

同样的,以上代码只能实现比较简单的功能,并不完全具备普适性,所以圆角窗体也已经被本猿封装到了RRQMSkin中,如果大家想直接使用的话直接在Nuget搜索RRQMSkin即可,具体操作如下:
在这里插入图片描述
在这里插入图片描述
添加好引用后,在主窗体替换继承类为RRQMEffectWindow即可(包括后台代码)。

<window:RRQMEffectWindow x:Class="WpfApp1.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:local="clr-namespace:WpfApp1"
                   xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
                   xmlns:window="若汝棋茗_Windows"
                   CornerRadius="10"
                   Height="450"
                   Width="800"
                   mc:Ignorable="d">
    <Grid />
</window:RRQMEffectWindow>

namespace WpfApp1
{
    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : RRQMSkin.Windows.RRQMEffectWindow
    {
        public MainWindow()
        {
            InitializeComponent();
        }
    }
}

结束

OK,一个圆角窗体就创建完成了,今天的分享就到这里吧。

最后希望这篇博客能帮到各位猿友,当然如果还有什么不明白的,可以私信本猿哦,QQ群:234762506

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: WPF(Windows Presentation Foundation)是一种用于创建Windows上交互式应用程序的框架,它支持窗体和页面的开发。在WPF中,我们可以让页面随窗体大小变化而自适应。 首先,我们需要将页面的布局定义为相对布局(Relative Layout),这样页面中的元素将根据相对位置和比例来排列。可以使用Grid控件或其他容器控件来实现。 其次,我们可以使用控件的布局属性和绑定来实现页面元素的自适应。比如,可以使用HorizontalAlignment和VerticalAlignment属性来控制元素在页面中的水平和垂直位置;使用Width和Height属性来控制元素的大小;使用Margin属性来设置元素与页面边界的距离等等。 另外,我们还可以使用响应式设计的思想来实现页面的自适应。通过在页面中定义样式和触发器,我们可以根据窗体大小改变样式或重新布局页面元素。可以使用VisualStateManager和VisualState来定义不同的视觉状态,并在窗体大小变化时自动切换。 最后,为了确保页面随窗体大小变化而自适应,我们还可以使用事件或命令来处理窗体大小变化的通知。WPF提供了SizeChanged事件,我们可以在事件处理程序中更新页面布局或元素的大小。 总结来说,WPF的页面可以通过相对布局、布局属性和绑定、响应式设计以及事件处理来实现随窗体大小变化而自适应。这样可以确保应用程序在不同的窗体大小下都能提供良好的用户体验。 ### 回答2: WPF页面(Page)随窗体大小的变化可以通过使用WPF自带的布局容器来实现。WPF提供了多种布局容器,常用的有Grid、StackPanel和DockPanel等。 使用Grid布局容器是一种常见的做法。在Grid中,可以将页面的各个元素放置在不同的行和列中,设置宽度和高度的比例或者绝对值等。当窗体大小变化时,Grid会根据行和列的定义自动调整元素的大小和位置,从而实现页面随窗体大小的变化。 另一种常见的做法是使用StackPanel布局容器。StackPanel会根据方向(水平或垂直)将页面的元素一次排列在一起。当窗体大小变化时,StackPanel会自动调整元素的大小和位置,保持元素的排列顺序不变,并根据需要将元素放置在新的行或列中。 DockPanel布局容器是将页面的元素放置在不同的方位(上、下、左、右和中间)中。通过设置元素在DockPanel中的Dock属性,可以确定元素相对于DockPanel的位置。当窗体大小变化时,DockPanel会自动调整元素的大小和位置,保持元素的位置不变。 总之,通过合理使用WPF的布局容器,可以实现WPF页面随窗体大小的变化。无论是使用Grid、StackPanel还是DockPanel等布局容器,都需要根据页面的组成和需要来选择合适的布局容器,并设置元素的大小和位置,以实现页面随窗体大小的变化。 ### 回答3: WPF(Windows Presentation Foundation)是一种用于创建具有丰富用户界面的应用程序的技术。在WPF中,Page是一种用来构建独立页面的控件。当Page随窗体大小变化时,可以采用以下方法进行处理: 1. 动态布局:在设计Page时,可以使用WPF的布局控件(如Grid、StackPanel等)来对页面中的元素进行布局。通过设置不同的布局属性,例如HorizontalAlignment和VerticalAlignment等,可以使页面中的元素根据窗体大小自动调整其位置和大小。 2. 控件的自适应:使用WPF的控件,例如TextBox、Button等,在其属性中可以设置一些适应性的特性,例如Stretch、MinHeight、MinWidth等。通过设置这些属性,可以使控件在窗体大小变化时自动调整自身的大小和显示。 3. 响应窗体大小变化的事件:WPF中的Page可以订阅窗体大小变化事件,例如SizeChanged事件。通过处理该事件,可以在窗体大小变化时执行一些特定的操作,例如重新计算页面中元素的布局、刷新页面内容等。 总结起来,要实现Page随窗体大小变化,可以采用动态布局、控件的自适应和处理窗体大小变化事件等方法。这些方法可以使页面中的元素根据窗体大小自动调整其位置和大小,从而适应不同大小窗体

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

若汝棋茗

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值