#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. paper 2:图像处理常用的Matlab函数汇总

    一 图像的读写 1 imread imread函数用于读入各种图像文件,如:a=imread('e:\w01.tif') 注:计算机E盘上要有w01相应的.tif文件. 2 imwrite imwri ...

  2. Microsoft.Jet.OLEDB.4.0和Microsoft.ACE.OLEDB.12.0的区别

    Microsoft.Jet.OLEDB.4.0和Microsoft.ACE.OLEDB.12.0的区别 时间 2012-12-19 20:30:12  CSDN博客原文  http://blog.cs ...

  3. 夺命雷公狗---Thinkphp----14之前台的首页完善

    我们先来完成我们的首页部分,我们首页要先来完成到焊条部分和右侧的导航部分: 我们先来写控制器: 然后在右侧遍历头部遍历出我们所需要的数据: 因为我们的右侧是引入进来的,所以我们需要到右侧视图下进行遍历 ...

  4. 鸟哥的linux私房菜学习记录之开机流程、模块管理与Loader

  5. python any()和all()用法

    #any(x)判断x对象是否为空对象,如果都为空.0.false,则返回false,如果不都为空.0.false,则返回true #all(x)如果all(x)参数x对象的所有元素不为0.''.Fal ...

  6. 161109、windows下查看端口占用情况

    1.开始---->运行---->cmd,或者是window+R组合键,调出命令窗口 2.输入命令:netstat -ano,列出所有端口的情况.在列表中我们观察被占用的端口,比如是4915 ...

  7. 一道面试题比较synchronized和读写锁

    一.科普定义 这篇博文的两个主角“synchronized”和“读写锁” 1)synchronized 这个同步关键字相信大家都用得比较多,在上一篇“多个线程之间共享数据的方式”中也详细列举他的应用, ...

  8. GCD 多线程 初探

    GCD编程的核心就是dispatch队列,dispatch block的执行最终都会放进某个队列中去进行,它类似NSOperationQueue但更复杂也更强大,并且可以嵌套使用.所以说,结合bloc ...

  9. 加载 pcntl 多进程

    加载 pcntl 有两种方式 一种重新编译安装,在编译时加 --enable-pcntl ./configure --prefix=/usr/local/php --with-mysql=/usr/l ...

  10. sql截断日志

    --收缩数据库 DBCC SHRINKDATABASE(fas) --截断事务日志: BACKUP LOG fas WITH NO_LOG 1.清空日志 DUMP TRANSACTION 库名 WIT ...