效果图如下:

实现思路:

1.继承Window类

2.为自定义的CustomWindow类设计窗体样式(使用Blend很方便!)

3.为窗体增加最大最小化和关闭按钮,并实现鼠标拖拽改变窗体大小(使用Derek Bartram的WindowResizer.dll库)

代码说明:

1.继承Window类

创建CustomWindow类,继承自System.Window

代码

public class CustomWindow : Window
{
    public CustomWindow()
    {
        // 加载样式
        InitializeStyle();          // 加载事件委托
        this.Loaded += delegate { InitializeEvent(); };         // 解决最大化覆盖任务栏问题
        this.SourceInitialized += new EventHandler(win_SourceInitialized);
    }
}
代码

<src:CustomWindow
    x:Class="windowStyle1.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:src="clr-namespace:windowStyle1"
    Title="CustomWindow" 
    Height="358" Width="649" AllowsTransparency="True" WindowStyle="None">

2.为自定义的CustomWindow类设计窗体样式

窗体样式的设计可以使用Expression Blend来进行可视化开发,非常方便

Blend会自动生成样式的xmal文件:

代码

<ResourceDictionary 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" xmlns:Microsoft_Windows_Themes="clr-namespace:Microsoft.Windows.Themes;assembly=PresentationFramework.Luna">
   
    <ControlTemplate x:Key="WindowTemplateKey" TargetType="{x:Type Window}">
        <Border Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}">
            <Grid>
                <AdornerDecorator>
                    <ContentPresenter/>
                </AdornerDecorator>
                <ResizeGrip x:Name="WindowResizeGrip" HorizontalAlignment="Right" VerticalAlignment="Bottom" IsTabStop="false" Visibility="Collapsed"/>
            </Grid>
        </Border>
        <ControlTemplate.Triggers>
            <MultiTrigger>
                <MultiTrigger.Conditions>
                    <Condition Property="ResizeMode" Value="CanResizeWithGrip"/>
                    <Condition Property="WindowState" Value="Normal"/>
                </MultiTrigger.Conditions>
                <Setter Property="Visibility" TargetName="WindowResizeGrip" Value="Visible"/>
            </MultiTrigger>
        </ControlTemplate.Triggers>
    </ControlTemplate>

3.为窗体增加最大最小化和关闭按钮,并实现鼠标拖拽改变窗体大小

按钮事件比较简单,通过分别为三个按钮添加Click事件即可

代码

/// <summary>
/// 加载按钮事件委托
/// </summary>
private void InitializeEvent()
{
    ControlTemplate baseWindowTemplate = (ControlTemplate)App.Current.Resources["CustomWindowControlTemplate"];     Button minBtn = (Button)baseWindowTemplate.FindName("btnMin", this);
    minBtn.Click += delegate
    {
        this.WindowState = WindowState.Minimized;
    };     Button maxBtn = (Button)baseWindowTemplate.FindName("btnMax", this);
    maxBtn.Click += delegate
    {
        this.WindowState = (this.WindowState == WindowState.Normal ? WindowState.Maximized : WindowState.Normal);
    };     Button closeBtn = (Button)baseWindowTemplate.FindName("btnClose", this);
    closeBtn.Click += delegate
    {
        this.Close();
    };     Border tp = (Border)baseWindowTemplate.FindName("topborder", this);     tp.MouseLeftButtonDown += delegate
    {
        this.DragMove();
    };
}

仅仅这样实现的话还不够,因为窗体最大化后会覆盖任务栏,这是我们不希望看到的,所以还必须通过WINDOW API的窗口句柄来定义最大化后的尺寸

代码

/// <summary>
/// 重绘窗体大小
/// </summary>
void win_SourceInitialized(object sender, EventArgs e)
{
    System.IntPtr handle = (new WinInterop.WindowInteropHelper(this)).Handle;
    WinInterop.HwndSource.FromHwnd(handle).AddHook(new WinInterop.HwndSourceHook(WindowProc));
}
...
[DllImport("user32")]
internal static extern bool GetMonitorInfo(IntPtr hMonitor, MONITORINFO lpmi); [DllImport("User32")]
internal static extern IntPtr MonitorFromWindow(IntPtr handle, int flags);
...
private static 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;
    }
    return (System.IntPtr)0;
}

最后是实现用鼠标拖拽改变窗体大小

然后在Windows1这个CustomWindow类的实例中绘制左右及底部5个拖拽热区(矩形)

最后在Window1.xaml.cs中添加事件委托即可

代码

/// <summary>
/// 加载Resize委托
/// </summary>
public void InitializeResizeHandle()
{
    WindowResizer wr = new WindowResizer(this);
    wr.addResizerRight(right);
    wr.addResizerLeft(left);
    wr.addResizerDown(bottom);
    wr.addResizerLeftDown(leftbottom);
    wr.addResizerRightDown(rightbottom);
    //wr.addResizerUp(topSizeGrip);
    //wr.addResizerLeftUp(topLeftSizeGrip);
    //wr.addResizerRightUp(topRightSizeGrip);
}

大功告成了!

WPF设计の自定义窗体的更多相关文章

  1. WPF 之 自定义窗体标题栏

    在WPF中自定义窗体标题栏,首先需要将窗体的WindowStyle属性设置为None,隐藏掉WPF窗体的自带标题栏.然后可以在窗体内部自定义一个标题栏. 例如,标题栏如下: <WrapPanel ...

  2. WPF 创建自定义窗体

    在前面的一篇博客"WPF 自定义Metro Style窗体",展示了如何创建一个类似于Metro Style的Window,并在程序中使用.但是这个窗体不能够自由的改变大小.今天的 ...

  3. WPF设计の不规则窗体

    我们在工作中,经常会需要画一些不规则的窗体,现在总结如下. 一.利用VisualBrush实现.这依赖于VisualBrush的特性,任何控件可以作为画刷,而画刷又可以作为背景. 此种方法可以用于实现 ...

  4. WPF自定义控件与样式(13)-自定义窗体Window & 自适应内容大小消息框MessageBox

    一.前言 申明:WPF自定义控件与样式是一个系列文章,前后是有些关联的,但大多是按照由简到繁的顺序逐步发布的等,若有不明白的地方可以参考本系列前面的文章,文末附有部分文章链接. 本文主要内容: 自定义 ...

  5. WPF移动Window窗体(鼠标点击左键移动窗体自定义行为)

    XAML代码部分:1.引用System.Windows.Interactivity 2.为指定的控件添加一个拖动的行为 3.很简单的了解行为的作用和用法 <Window xmlns=" ...

  6. WPF中自定义标题栏时窗体最大化处理之WindowChrome

    注意: 本文方法基础是WindowChrome,而WindowChrome在.NET Framework 4.5之后才集成发布的.见:WindowChrome Class 在.NET Framewor ...

  7. 【转】WPF自定义控件与样式(13)-自定义窗体Window & 自适应内容大小消息框MessageBox

    一.前言 申明:WPF自定义控件与样式是一个系列文章,前后是有些关联的,但大多是按照由简到繁的顺序逐步发布的等. 本文主要内容: 自定义Window窗体样式: 基于自定义窗体实现自定义MessageB ...

  8. wpf 自定义窗体的实现

    首先创建自定义窗体的资源文件 <ControlTemplate x:Key="BaseWindowControlTemplate" TargetType="Wind ...

  9. [WPF自定义控件]?Window(窗体)的UI元素及行为

    原文:[WPF自定义控件]?Window(窗体)的UI元素及行为 1. 前言 本来打算写一篇<自定义Window>的文章,但写着写着发觉内容太多,所以还是把使用WindowChrome自定 ...

随机推荐

  1. mybatis_05动态SQL_if和where

    If标签:作为判断入参来使用的,如果符合条件,则把if标签体内的SQL拼接上. 注意:用if进行判断是否为空时,不仅要判断null,也要判断空字符串‘’: Where标签:会去掉条件中的第一个and符 ...

  2. java_自定义标签运行原理

    一.自定义标签运行原理: 二.文字说明 1.IE->web服务器 2.Web服务器->jsp 3.遇到自定义标签,首先实例化标签所对应的标签处理器类 4.调用setPageContext方 ...

  3. Fundebug累计处理1000万条错误事件!

    摘要上线半年时间,Fundebug累计处理1000万条错误事件.10000000啊! 自从去年双11[正式上线](https://blog.fundebug.com/2016/11/11/fundeb ...

  4. if判断

    <!-- 查询用户信息 --> <select id="queryUser3" parameterType="org.pine.mybatis.util ...

  5. angular ng-repeat出来的数据 每条修改数据后返回给接口 如何取到每个对应修改的值

    接口结构 $scope.DataList = [ { "dataA":"numA", "dataB":"numB"a } ...

  6. JMeter java.net.SocketException:Operationnotsupported:connect解决方案

    java.net.SocketException: Operation not supported: connect解决方案   by:授客 QQ:1033553122 测试环境 apache-jme ...

  7. C# 实现FTP客户端

    本文是利用C# 实现FTP客户端的小例子,主要实现上传,下载,删除等功能,以供学习分享使用. 思路: 通过读取FTP站点的目录信息,列出对应的文件及文件夹. 双击目录,则显示子目录,如果是文件,则点击 ...

  8. Visual Studio未能加载“XX”包的解决方案

    1.打开命令行(管理员) 2.进入到devenv.exe所在的目录u 3.输入devenv,会出现帮助提示 4.将所有带“Reset..”的命令执行一遍 5.OK 我尝试过使用修复功能,貌似没有作用. ...

  9. (后台)SQL Server 代理(已禁用代理 XP) 怎么解决(转)

    百度知道搜索的答案: 在SQL Server Management Studio中连接到SQL Server实例后,会显示“SQL Server 代理”节点.如果当前该实例的Agent服务没有启动,“ ...

  10. 使用MUI/html5plus集成微信支付需要注意的几点问题

    1)需要在服务器根目录放上证书,从微信开放平台下载 2)客户端组件目录名一定要按照微信要求