#region 窗口移动
private bool _isLeftButtonDown = false;

public const int HTCAPTION = 0x0002;

protected override void WndProc(ref System.Windows.Forms.Message m)
{
base.WndProc(ref m);

switch (m.Msg)
{
case WinApi.WM_LBUTTONDOWN:
case WinApi.WM_LBUTTONUP:

int lParam = m.LParam.ToInt32();
int x = lParam & 0xFFFF;
int y = (lParam >> 16);

switch (m.Msg)
{
case WinApi.WM_LBUTTONDOWN:
if (x < Width - 20 || y > 20)
{
this._isLeftButtonDown = true;
WinApi.ReleaseCapture();
WinApi.SendMessage(this.Handle, WinApi.WM_SYSCOMMAND, WinApi.SC_MOVE + HTCAPTION, 0);
}
break;
case WinApi.WM_LBUTTONUP:
if (this._isLeftButtonDown)
{
this._isLeftButtonDown = false;
if (x < Width - 20 || y > 20)
{
WinApi.ReleaseCapture();
SaveLocation();
}
}
break;
}
break;
}
}

/// <summary>
/// 保存窗口位置.
/// </summary>
private void SaveLocation()
{
if (this._isLeftButtonDown)
{
SavedLocation = this.Location;
}
}

/// <summary>
/// 引发 <see cref="E:System.Windows.Forms.Control.LocationChanged"/> 事件。
/// </summary>
/// <param name="e">包含事件数据的 <see cref="T:System.EventArgs"/>。</param>
protected override void OnLocationChanged(EventArgs e)
{
const int DX = 25;
const int DY = 25;

Point location = this.Location;
Rectangle rect = Screen.PrimaryScreen.WorkingArea;
if (location.X + this.Width < DX)
{
location.X = DX - this.Width;
}
else if (location.X + DX > rect.Width)
{
location.X = rect.Width - DX;
}
if (location.Y + this.Height < DY)
{
location.Y = DY - this.Height;
}
else if (location.Y + DY > rect.Height)
{
location.Y = rect.Height - DY;
}

if (location != this.Location)
{
this.Location = location;
}

SaveLocation();
}

private const string SAVED_LOCATION_REGSTER_KEY = @"Software\AlarmClient\SavedLocation";

/// <summary>
/// 保存路径
/// </summary>
private Point SavedLocation
{
get
{
int x, y;
try
{
RegistryKey key = Registry.CurrentUser.OpenSubKey(SAVED_LOCATION_REGSTER_KEY);
if (key != null)
{
x = (int)key.GetValue("X", 0);
y = (int)key.GetValue("Y", 0);

return new Point(x, y);
}
}
catch (Exception ex)
{
TestLog.DoLog(ex);
}

Rectangle rect = Screen.PrimaryScreen.WorkingArea;
x = rect.Width - this.Width;
y = rect.Height - this.Height;
return new Point(x, y);
}
set
{
try
{
RegistryKey key = Registry.CurrentUser.CreateSubKey(SAVED_LOCATION_REGSTER_KEY);
key.SetValue("X", value.X);
key.SetValue("Y", value.Y);
}
catch (Exception ex)
{
TestLog.DoLog(ex);
}
}
}

/// <summary>
/// 引发 <see cref="E:System.Windows.Forms.Form.Load"/> 事件。
/// </summary>
/// <param name="e">包含事件数据的 <see cref="T:System.EventArgs"/>。</param>
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
//if (this._activeWindow != IntPtr.Zero)
//{
// WinApi.SetActiveWindow(this._activeWindow);
//}
//this.Controls.EachChildFirst((Control c) =>
//{
// LabelX label = c as LabelX;
// if (label == null) return false;

// label.MouseDown += new MouseEventHandler(label_MouseDown);
// label.MouseMove += new MouseEventHandler(label_MouseMove);

// return true;
//});

// 让窗口上的每一个 LabelX 都把鼠标按下和移动的消息发送给本窗口
MouseEventHandler down = new MouseEventHandler(label_MouseDown);
MouseEventHandler move = new MouseEventHandler(label_MouseMove);

// 遍历窗口中的 LabelX
this.Controls.EachChildFirst((Control c) =>
{
LabelX label = c as LabelX;
if (label == null) return false;

label.MouseDown += down;
label.MouseMove += move;

return true;
});

// 加载初始位置
this.Location = this.SavedLocation;
// 设置窗口为一个圆角的矩形
//this.Region = CreateRegion();
}

/// <summary>
/// 给窗口添加圆角区域
/// </summary>
/// <returns></returns>
private Region CreateRegion()
{
const int RX = 15;
const int RY = 15;

//Region region = this.Region;
System.Drawing.Drawing2D.GraphicsPath path = new System.Drawing.Drawing2D.GraphicsPath();
path.FillMode = System.Drawing.Drawing2D.FillMode.Winding;
path.AddRectangle(new Rectangle(1, RY, this.Width - 2, this.Height - (RY + RY)));
path.AddRectangle(new Rectangle(RX, 1, this.Width - (RX + RX + 2), this.Height - 2));
path.AddEllipse(1, 0, RX + RX, RY + RY);
path.AddEllipse(1, this.Height - (RY + RY + 2), RX + RX, RY + RY);
path.AddEllipse(this.Width - (RX + RX + 2), 0, RX + RX, RY + RY);
path.AddEllipse(this.Width - (RX + RX + 2), this.Height - (RY + RY + 2), RX + RX, RY + RY);

return new Region(path);
}

/// <summary>
/// 鼠标在 LabelX 上移动时,将消息发送给窗口
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void label_MouseMove(object sender, MouseEventArgs e)
{
WinApi.PostMessage(this.Handle, WinApi.WM_MOUSEMOVE, 1, e.X | (e.Y << 16));
}

/// <summary>
/// 鼠标在 LabelX 上按下时,将消息发送给窗口
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void label_MouseDown(object sender, MouseEventArgs e)
{
WinApi.PostMessage(this.Handle, WinApi.WM_LBUTTONDOWN, 1, e.X | (e.Y << 16));
}
#endregion

窗口移动--基类(BaseForm)的更多相关文章

  1. CS中窗体的基类(BaseForm)注意点

    窗体基类最好新建一个窗体(BaseForm) 1.这样能够保证在VS中保证他的派生窗口也能够可视化. 2.如果基类直接是一个cs类文件,对于处理派生窗口就很复杂,比如按钮权限之类的操作; 如果直接继承 ...

  2. QWidget QMainWindow QDialog 三个基类的区别

    Qt类是一个提供所需的像全局变量一样的大量不同的标识符的命名空间.通常情况下,你可以忽略这个类.QObject和一些其它类继承了它,所以在这个Qt命名空间中定义的所有标识符通常情况下都可以无限制的使用 ...

  3. WPF自定义窗口基类

    WPF自定义窗口基类时,窗口基类只定义.cs文件,xaml文件不定义.继承自定义窗口的类xaml文件的根节点就不再是<Window>,而是自定义窗口类名(若自定义窗口与继承者不在同一个命名 ...

  4. WPF自学入门(九)WPF自定义窗口基类

    今天简单记录一个知识点:WPF自定义窗口基类,常用winform的人知道,winform的窗体继承是很好用的,写一个基础窗体,直接在后台代码改写继承窗体名.但如果是WPF要继承窗体,我个人感觉没有理解 ...

  5. WPF 之 创建继承自Window 基类的自定义窗口基类

    开发项目时,按照美工的设计其外边框(包括最大化,最小化,关闭等按钮)自然不同于 Window 自身的,但窗口的外边框及窗口移动.最小化等标题栏操作基本都是一样的.所以通过查看资料,可按如下方法创建继承 ...

  6. wpf之mvvm基类

    当我们用MVVM设计模式的时候要实现INotifyPropertyChanged,每次都要实现这个接口比较麻烦,所以基类的作用就体现出来了.代码如下:   1 2 3 4 5 6 7 8 9 10 1 ...

  7. Thinkphp源码分析系列(七)–控制器基类

    在mvc模式中,c代表的就是控制器,是是应用程序中处理用户交互的部分.通常控制器负责从视图读取数据,控制用户输入,并向模型发送数据.控制器是沟通视图和模型的桥梁,他接受用户请求,并调用模型层去处理用户 ...

  8. WPF开发时光之痕日记本(二)—— MVVM基类

    当我们用MVVM的时候要实现INotifyPropertyChanged,每次都要实现这个接口比较麻烦,所以基类的作用就体现出来了.代码如下: public class ViewModelBase : ...

  9. Duilib学习笔记《06》— 窗体基类WindowImpBase

    在前面的例子中我们发现,窗口都是继承CWindowWnd.INotifyUI,然后重载相关函数去实现.显然,我们发现窗口的创建流程实际上都是差不多的,主要只是在OnCreate加载的配置文件不同等等… ...

随机推荐

  1. PAT乙级 1017. A除以B (20)

    1017. A除以B (20) 时间限制 100 ms 内存限制 65536 kB 代码长度限制 8000 B 判题程序 Standard 作者 CHEN, Yue 本题要求计算A/B,其中A是不超过 ...

  2. ThinkPHP讲解(一)框架基础

    ThinkPHP框架知识点过于杂乱,接下来将以问题的形势讲解tp(ThinkPHP的简写) 1.tp框架是什么,为什么使用是它? 一堆代码的集合,里边有变量.函数.类.常量,里边也有许多设计模式MVC ...

  3. 关于CentOS 7.1后期维护的问题

    1.问题描述:在使用ssh服务远程登录的时候,当显示输入密码,特别特别的慢,刚刚搭建 服务器的时候还很正常,经过一个假期我实在忍不了它了,故决定解决此问题.服务器系统:CentOS 7.1 解决方式: ...

  4. Android SDK Manager更新报错

    错误log: Fetching https://dl-ssl.google.com/android/repository/addons_list-.xml Fetched Add-ons List s ...

  5. Writable、WritableComparable和comparators

    hadoop的序列化格式 hadoop自身的序列化存储格式就是实现了Writable接口的类,他只实现了前面两点,压缩和快速.但是不容易扩展,也不跨语言. 我们先来看下Writable接口,Writa ...

  6. 视频处理控件TVideoGrabber如何重新编码视频

    TVideoGrabber中可以对音频.视频剪辑进行重新编码剪辑,多的朋友知道这个功能更点,但是具体操作上还是不是很熟悉,这里总结一下,主要步骤如下: 1.通过指定开始和停止的时间,可以简单的剪辑视频 ...

  7. Java随学随记

    1.一个Java源文件可包含三个“顶级”要素: (1)一个包(package)声明(可选) (2)任意数量的导入(import)语句 (3)类(class)声明 该三要素必须以上顺序出现.即,任何导入 ...

  8. php用jquery-ajax上传多张图片限制图片大小

    php用jquery-ajax上传多张图片限制图片大小 /** * 上传图片,默认大小限制为3M * @param String $fileInputName * @param number $siz ...

  9. Java中的线程同步机制

    一.首先为什么线程需要同步? 1.多线程安全问题的原因      A:有多线程环境      B:有共享数据      C:有多条语句操作共享数据 2. //未完待续后面会继续更新

  10. 转载:JMS-ActiveMQ浅析

    ActiveMQ 即时通讯服务 浅析 一. 概述与介绍 ActiveMQ 是Apache出品,最流行的.功能强大的即时通讯和集成模式的开源服务器.ActiveMQ 是一个完全支持JMS1.1和J2EE ...