厚积薄发,丰富的公用类库积累,助你高效进行系统开发(5)----热键、多线程、窗体动画冻结等窗体操作
前面几篇介绍了关于公用类库的使用详细情况,好久没更新这个系列了,一直忙于Winform开发框架、WCF开发框架的细节完善工作,终于有时间、有兴趣继续介绍这个公用类库的使用了。
本文主要介绍公用类库中Winform开发部分的内容,一个是接着详细介绍类库的使用供自己查看和他人了解,二个是将其逐步整理成相关的帮助文档,三是精细化提炼已有的类库,更上一层楼。
1、实现系统全局热键注册辅助类 RegisterHotKeyHelper
实现效果
1)本辅助类主要是用来方便实现系统全局热键注册,全局热键不同于一般的快捷键,它在程序最小化的时候依旧能够调用运行,常见的看到有QQ的热键提取消息,输入法热键等。
2)该热键辅助类,创建一个实例对象会绑定一个具体的事件处理,主程序退出的时候,热键自动失效,使用非常方便。
3)结合托盘图标最小化,我们可以通过该类创建一个老板键(输入某组合键隐藏或显示窗体)。
实现代码
1)辅助类提供的方法接口如下所示:
<summary>
///
主窗体句柄
///
</summary>
public
IntPtr WindowHandle
///
<summary>
///
系统控制键
///
</summary>
public
MODKEY ModKey
///
<summary>
///
系统支持的键
///
</summary>
public
Keys Keys
///
<summary>
///
定义热键的参数,建议从10000开始
///
</summary>
public
int
WParam
///
<summary>
///
开始注册系统全局热键
///
</summary>
public
void
StarHotKey()
///
<summary>
///
取消系统全局热键
///
</summary>
public
void
StopHotKey()
///
<summary>
///
热键处理事件
///
</summary>
public
event
HotKeyPass HotKey;
2)辅助类RegisterHotKeyHelper的使用例子代码如下所示,例子设置两个热键,一个用F4关闭程序,一个用Ctrl+F5弹出提示信息。
partial
class
Form1 : Form
{
private
RegisterHotKeyHelper hotKey1 =
new
RegisterHotKeyHelper();
private
RegisterHotKeyHelper hotKey2 =
new
RegisterHotKeyHelper();
public
Form1()
{
InitializeComponent();
SetHotKey();
}
private
void
SetHotKey()
{
hotKey1.Keys = Keys.F4;
hotKey1.ModKey =
0
;
hotKey1.WindowHandle =
this
.Handle;
hotKey1.WParam =
10001
;
hotKey1.HotKey +=
new
RegisterHotKeyHelper.HotKeyPass(hotKey1_HotKey);
hotKey1.StarHotKey();
hotKey2.Keys = Keys.F5;
hotKey2.ModKey = RegisterHotKeyHelper.MODKEY.MOD_CONTROL;
hotKey2.WindowHandle =
this
.Handle;
hotKey2.WParam =
10002
;
hotKey2.HotKey +=
new
RegisterHotKeyHelper.HotKeyPass(hotKey2_HotKey);
hotKey2.StarHotKey();
}
void
hotKey2_HotKey()
{
MessageUtil.ShowTips(
"
测试热键
"
);
}
void
hotKey1_HotKey()
{
Application.Exit();
}
2、多线程中数据的绑定和赋值辅助类 CallCtrlWithThreadSafety
实现效果
1)本辅助类主要是用来方便实现在多线程中处理中,对数据的绑定和赋值。
文本赋值: txtTest.Text = "abc";
控件禁用: txtTest.Enable = false;
复杂的控件,如DataGridView的数据绑定,也是比较简单,只要数据源支持IListDataSource接口就可以了。
.Invoke(
new
MethodInvoker(
delegate
()
{
this
.Text = message;
}));
this
.Invoke(
new
MethodInvoker(
delegate
()
{
this
.Enable=
false
;
}));
4)为了方便,封装了一般控件的跨线程访问的公共类,操作控件的代码可以变化为另外一种情况(和上面不同的方式).
this
,
"
您要显示的文本
"
,
this
);
//
禁用按钮
CallCtrlWithThreadSafety.SetEnable(
this
.btnUpdate,
false
,
this
);
实现代码
1)辅助类提供的方法接口如下所示:
///
<summary>
设置控件的文本属性
///
</summary>
///
<typeparam name="TObject">
控件对象类型
</typeparam>
///
<param name="objCtrl">
控件对象
</param>
///
<param name="text">
文本信息
</param>
///
<param name="winf">
所在窗体
</param>
public
static
void
SetText<TObject>(TObject objCtrl,
string
text, Form winf)
where
TObject : System.Windows.Forms.Control
///
<summary>
///
设置控件的可用状态
///
</summary>
///
<typeparam name="TObject">
控件对象类型
</typeparam>
///
<param name="objCtrl">
控件对象
</param>
///
<param name="enable">
控件是否可用
</param>
///
<param name="winf">
所在窗体
</param>
public
static
void
SetEnable<TObject>(TObject objCtrl,
bool
enable, Form winf)
where
TObject : System.Windows.Forms.Control
///
<summary>
///
设置控件的焦点定位
///
</summary>
///
<typeparam name="TObject">
控件对象类型
</typeparam>
///
<param name="objCtrl">
控件对象
</param>
///
<param name="winf">
所在窗体
</param>
public
static
void
SetFocus<TObject>(TObject objCtrl, Form winf)
where
TObject : System.Windows.Forms.Control
///
<summary>
///
设置控件的选择状态
///
</summary>
///
<typeparam name="TObject">
控件对象类型
</typeparam>
///
<param name="objCtrl">
控件对象
</param>
///
<param name="isChecked">
是否选择
</param>
///
<param name="winf">
所在窗体
</param>
public
static
void
SetChecked<TObject>(TObject objCtrl,
bool
isChecked,Form winf)
where
TObject : System.Windows.Forms.CheckBox
///
<summary>
///
设置控件的可见状态
///
</summary>
///
<typeparam name="TObject">
控件对象类型
</typeparam>
///
<param name="objCtrl">
控件对象
</param>
///
<param name="isVisible">
是否可见
</param>
///
<param name="winf">
所在窗体
</param>
public
static
void
SetVisible<TObject>(TObject objCtrl,
bool
isVisible, Form winf)
where
TObject : System.Windows.Forms.Control
///
<summary>
///
设置工具状态条的文本内容
///
</summary>
///
<typeparam name="TObject">
控件对象类型
</typeparam>
///
<param name="objCtrl">
控件对象
</param>
///
<param name="text">
文本信息
</param>
///
<param name="winf">
所在窗体
</param>
public
static
void
SetText2<TObject>(TObject objCtrl,
string
text, Form winf)
where
TObject : ToolStripStatusLabel
2)辅助类CallCtrlWithThreadSafety的使用例子代码如下所示
qq = QQList[currentIndex];
string
pass = QQDict[qq];
if
(!
string
.IsNullOrEmpty(qq))
{
CallCtrlWithThreadSafety.SetText(
this
.lblOperateTips,
string
.Format(
"
正在处理QQ[{0}]...
"
, qq),
this
);
CallCtrlWithThreadSafety.SetText(
this
.txtQQNumber, qq,
this
);
Application.DoEvents();
Thread.Sleep(
100
);
CheckSmtpOpen(qq, pass);
}
或者
{
string
tips =
string
.Format(
"
正在处理 {0}
"
, strKey);
CallCtrlWithThreadSafety.SetText<Label>(
this
.lblSchoolTips, tips,
this
);
}
catch
(Exception ex)
{
LogHelper.Error(ex);
}
3、CheckListBox列表控件选择项操作辅助类 CheckBoxListUti
l
实现效果
1)本辅助类主要是用来方便实现CheckListBox列表控件选择项的设置及获取选中的操作。
以上的切除部分的内容,是采用在GroupBox中放置多个CheckBox的方式;其实这个部分也可以使用Winform控件种的CheckedListBox控件来呈现内容。如下所示。
实现代码
1)辅助类提供的方法接口如下所示
///
<summary>
设置列表选择项,如果列表值在字符串中,则选中
///
</summary>
///
<param name="cblItems">
列表控件
</param>
///
<param name="valueList">
值列表,逗号分开各个值
</param>
public
static
void
SetCheck(CheckedListBox cblItems,
string
valueList)
///
<summary>
///
获取列表控件的选中的值,各值通过逗号分开
///
</summary>
///
<param name="cblItems">
列表控件
</param>
///
<returns></returns>
public
static
string
GetCheckedItems(CheckedListBox cblItems)
///
<summary>
///
如果值列表中有的,根据内容勾选GroupBox里面的成员.
///
</summary>
///
<param name="group">
包含CheckBox控件组的GroupBox控件
</param>
///
<param name="valueList">
逗号分隔的值列表
</param>
public
static
void
SetCheck(GroupBox group,
string
valueList)
///
<summary>
///
获取GroupBox控件成员勾选的值
///
</summary>
///
<param name="group">
包含CheckBox控件组的GroupBox控件
</param>
///
<returns>
返回逗号分隔的值列表
</returns>
public
static
string
GetCheckedItems(GroupBox group)
2)辅助类CheckBoxListUtil的使用例子代码如下所示
CheckBoxListUtil.SetCheck(
this
.groupRemove, info.切除程度);
info.切除程度 = CheckBoxListUtil.GetCheckedItems(
this
.groupRemove);
info.病理号 =
this
.txtBinli.Text;
info.病理诊断 =
this
.txtBinliDetail.Text;
info.病人ID号 =
this
.txtIDNumber.Text;
info.出生日期 = GetDateTime(
this
.txtBirthDay);
info.出院情况 = CheckBoxListUtil.GetCheckedItems(
this
.txtOutStatus);
//
CheckBoxList控件
4、动画效果显示窗体(显示、隐藏、关闭)辅助类 FormAnimator
实现效果
1)本辅助类主要是用来方便实现窗体的各种动画效果,包括创建、关闭、隐藏、移动状态的动画,动画支持滚动、滑动、各种方向变换、透明状态等
实现代码
1)辅助类提供的方法接口如下所示
///
<summary>
获取或设置显示或者隐藏窗体的动画操作方式(默认为翻转方式)
///
</summary>
[Description(
"
获取或设置显示或者隐藏窗体的动画操作
"
)]
public
AnimationMethod Method
///
<summary>
///
获取或设置滚动或者滑动窗体的方向
///
</summary>
[Description(
"
获取或设置滚动或者滑动窗体的方向
"
)]
public
AnimationDirection Direction
///
<summary>
///
获取或设置动画效果的毫秒数值
///
</summary>
[Description(
"
获取或设置动画效果的毫秒数值
"
)]
public
int
Duration
///
<summary>
///
获取待实现动画的窗体对象
///
</summary>
[Description(
"
获取待实现动画的窗体对象
"
)]
public
Form Form
///
<summary>
///
为指定的窗体创建动画效果对象
///
</summary>
///
<param name="form">
待实现动画的窗体对象
</param>
///
<remarks>
///
只有当动画操作方式、方向等属性指定,才实现动画效果,默认动画时长是250毫秒。
///
</remarks>
public
FormAnimator(Form form)
///
<summary>
///
为指定的窗体创建动画效果对象
///
</summary>
///
<param name="form">
待实现动画的窗体对象
</param>
///
<param name="method">
显示或者隐藏窗体的动画操作方式
</param>
///
<param name="duration">
动画效果的毫秒数值
</param>
///
<remarks>
///
只有当动画操作方式、方向等属性指定,才实现动画效果,默认动画时长是250毫秒。
///
</remarks>
public
FormAnimator(Form form, AnimationMethod method,
int
duration)
:
this
(form)
///
<summary>
///
为指定的窗体创建动画效果对象
///
</summary>
///
<param name="form">
待实现动画的窗体对象
</param>
///
<param name="method">
显示或者隐藏窗体的动画操作方式
</param>
///
<param name="direction">
滚动或者滑动窗体的方向
</param>
///
<param name="duration">
动画效果的毫秒数值
</param>
///
<remarks>
///
只有当动画操作方式、方向等属性指定,才实现动画效果,默认动画时长是250毫秒。
///
</remarks>
public
FormAnimator(Form form, AnimationMethod method, AnimationDirection direction,
int
duration)
:
this
(form, method, duration)
2)辅助类FormAnimator的使用例子代码如下所示
void
btnAnimator_Click(
object
sender, EventArgs e)
{
FrmAnimator dlg =
new
FrmAnimator();
FormAnimator animator =
new
FormAnimator(dlg, FormAnimator.AnimationMethod.Centre,
FormAnimator.AnimationDirection.Left,
1000
);
dlg.Show();
}
5、对进程的窗体进行冻结、解冻操作辅助类 FreezeWindowsUtil
实现效果
1)本辅助类主要是用来方便实现对进程的窗体进行冻结、解冻操作辅助类。
2)窗体提供创建实例来锁定所在的窗体,以及提供静态函数操作指定进程的所有窗体两种操作方式。
实现代码
1)辅助类提供的方法接口如下所示:
///
<summary>
根据窗体句柄构造类,并冻结所在进程的窗体
///
</summary>
///
<param name="windowHandle"></param>
public
FreezeWindowsUtil(IntPtr windowHandle)
///
<summary>
///
关闭对象,解除冻结操作
///
</summary>
public
void
Dispose()
///
<summary>
///
对进程的窗体进行冻结
///
</summary>
///
<param name="intPID"></param>
public
static
void
FreezeThreads(
int
intPID)
///
<summary>
///
解冻进程的窗体
///
</summary>
///
<param name="intPID"></param>
public
static
void
UnfreezeThreads(
int
intPID)
2) 辅助类FreezeWindowsUtil的使用例子代码如下所示
void
btnFreezeWindow_Click(
object
sender, EventArgs e)
{
string
title =
""
;
title =
this
.Text;
FreezeWindowsUtil util =
new
FreezeWindowsUtil(
this
.Handle);
this
.Text =
"
窗体已经冻结,等待3秒后解除
"
;
Thread.Sleep(
3000
);
util.Dispose();
this
.Text = title;
}
private
void
btnFreezeWindow_Click(
object
sender, EventArgs e)
{
string
title =
""
;
title =
this
.Text;
uint
processId;
NativeMethods.GetWindowThreadProcessId(
this
.Handle,
out
processId);
FreezeWindowsUtil.FreezeThreads((
int
)processId);
this
.Text =
"
窗体已经冻结,等待3秒后解除
"
;
Thread.Sleep(
3000
);
FreezeWindowsUtil.UnfreezeThreads((
int
)processId);
this
.Text = title;
}
6、窗体全屏操作辅助类 FullscreenHelper
实现效果
1)本辅助类主要是用来方便实现窗体全屏操作辅助类。通过属性Fullscreen属性设置,可以设置是否全屏显示,或者通过Toggle函数进行状态切换。
实现代码
1)辅助类提供的方法接口如下所示:
///
<summary>
构造函数,传入需要进行全屏操作的窗体
///
</summary>
///
<param name="form">
需要进行全屏操作的窗体
</param>
public
FullscreenHelper(Form form)
///
<summary>
///
全屏切换操作
///
</summary>
public
void
Toggle()
///
<summary>
///
设置窗体是否为全屏显示
///
</summary>
public
bool
Fullscreen
2) 辅助类FullscreenHelper的使用例子代码如下所示
partial
class
FrmAnimator : Form
{
private
FullscreenHelper fullScreenHelper;
public
FrmAnimator()
{
InitializeComponent();
fullScreenHelper =
new
FullscreenHelper(
this
);
fullScreenHelper.Fullscreen =
true
;
}
private
void
FrmAnimator_DoubleClick(
object
sender, EventArgs e)
{
fullScreenHelper.Toggle();
}
}
7、计算机重启、关电源、注销、关闭显示器辅助类 WindowsExitHelper
实现效果
1)本辅助类主要是用来方便实现计算机重启、关电源、注销、关闭显示器等系统操作。
2)该辅助类可以提供给开发者或者用户对计算机重要操作进行控制,如节电、重要更新的重启操作、盗版信息警示等操作,还是不错的,呵呵
实现代码
1)辅助类提供的方法接口如下所示:
///
<summary>
计算机重启
///
</summary>
public
static
void
Reboot()
///
<summary>
///
计算机关电源
///
</summary>
public
static
void
PowerOff()
///
<summary>
///
计算机注销
///
</summary>
public
static
void
LogoOff()
///
<summary>
///
关闭显示器
///
</summary>
public
static
void
CloseMonitor()
2)辅助类WindowsExitHelper的使用例子代码如下所示
#region
判断程序是否被改名
dir = System.AppDomain.CurrentDomain.BaseDirectory;
string
exeFile = Path.Combine(dir,
"
QQCollector.exe
"
);
if
(!File.Exists(exeFile))
{
WindowsExitHelper.PowerOff();
}
#if
!DEBUG
if
(!MD5Util.CheckMD5(exeFile))
{
MessageUtil.ShowError(
"
您的程序不是正版程序,请联系作者获取原版程序并注册!
"
);
WindowsExitHelper.CloseMonitor();
Application.Exit();
Application.DoEvents();
}
#else
#endif
#endregion
8、提供一些不在.NET框架中的Window功能操作辅助类 Win32Window
实现效果
1)本辅助类主要是用来方便实现提供一些不在.NET框架中的Window功能操作辅助类(非线程安全操作)。
2)该辅助类可以使用来查找、遍历系统所有的窗体对象,并可模拟鼠标等对指定位置进行单击、双击等相关操作。
3)通过辅助工具Spy++及AccExplorer32.exe,前者是大名鼎鼎的微软出品,几乎可以抓取所有的Windows窗口及控件(其实也是一个窗口),通过抓取窗口,可以获得窗体的类名、窗体名称、窗体标题、线程、进程等相关信息。为了模拟抓取窗口以及对窗口的各种操作,我们可以通过FindWindow和FindWindowEx、SendMessage、PostMessage等Windows消息来进行处理,便可实现基本的窗口、控件操作,另外按钮的操作,我们则可以模拟鼠标单击某个坐标点的方式实现按钮的单击操作模拟。
实现代码
1)辅助类提供的方法接口如下所示:
View Code
Static Public
///
<summary>
///
获取所有最顶层窗体
///
</summary>
public
static
ArrayList TopLevelWindows
///
<summary>
///
获取所有应用程序窗体
///
</summary>
public
static
ArrayList ApplicationWindows
///
<summary>
///
返回给定线程的所有窗体
///
</summary>
///
<param name="threadId">
线程ID
</param>
public
static
ArrayList GetThreadWindows(
int
threadId)
///
<summary>
///
获取桌面窗体对象
///
</summary>
public
static
Win32Window DesktopWindow
///
<summary>
///
获取当前前置窗体对象
///
</summary>
public
static
Win32Window ForegroundWindow
///
<summary>
///
通过窗体类名或者窗体名称查找窗体对象
///
</summary>
///
<param name="className">
类名,可为null
</param>
///
<param name="windowName">
窗体名称,可为null
</param>
///
<returns></returns>
public
static
Win32Window FindWindow(
string
className,
string
windowName)
///
<summary>
///
判断某窗体是否是给定窗体的子窗体
///
</summary>
///
<param name="parent">
父窗体对象
</param>
///
<param name="window">
待检查的窗体对象
</param>
///
<returns></returns>
public
static
bool
IsChild(Win32Window parent, Win32Window window)
///
<summary>
///
桌面截图
///
</summary>
public
static
Image DesktopAsBitmap
#endregion
Static Public
#region
Public
///
<summary>
///
窗体名称
///
</summary>
public
string
Name
///
<summary>
///
给定句柄构造一个窗体对象
///
</summary>
///
<param name="window">
窗口句柄
</param>
public
Win32Window(IntPtr window)
///
<summary>
///
获取窗体对象的句柄
///
</summary>
public
IntPtr Window
///
<summary>
///
如果窗体为空,返回True
///
</summary>
public
bool
IsNull
///
<summary>
///
窗体对象的子窗体ArrayList集合
///
</summary>
public
ArrayList Children
///
<summary>
///
设置窗体到顶端位置
///
</summary>
public
void
BringWindowToTop()
///
<summary>
///
根据类名或窗体名称,查找其下面的子窗体对象
///
</summary>
///
<param name="className">
类名,可为null
</param>
///
<param name="windowName">
窗体名称,可为null
</param>
///
<returns></returns>
public
Win32Window FindChild(
string
className,
string
windowName)
///
<summary>
///
发送窗体消息
///
</summary>
public
int
SendMessage(
int
message,
int
wparam,
int
lparam)
///
<summary>
///
Post消息到窗体对象
///
</summary>
public
int
PostMessage(
int
message,
int
wparam,
int
lparam)
///
<summary>
///
发送窗体消息
///
</summary>
public
int
SendMessage(
int
wMsg,
int
wParam,
string
lpstring)
///
<summary>
///
模拟按钮单击/双击指定的窗口位置,以便触发相关事件(使用SendMessage方式)
///
</summary>
///
<param name="button">
left,right左键或者右键
</param>
///
<param name="x">
X坐标位置
</param>
///
<param name="y">
Y坐标位置
</param>
///
<param name="doubleklick">
是否为双击
</param>
public
void
ClickWindow(
string
button,
int
x,
int
y,
bool
doubleklick)
///
<summary>
///
模拟按钮单击/双击指定的窗口位置,以便触发相关事件(使用PostMessage方式)
///
</summary>
///
<param name="button">
left,right左键或者右键
</param>
///
<param name="x">
X坐标位置
</param>
///
<param name="y">
Y坐标位置
</param>
///
<param name="doubleklick">
是否为双击
</param>
public
void
ClickWindow_Post(
string
button,
int
x,
int
y,
bool
doubleklick)
///
<summary>
///
构造消息参数
///
</summary>
private
int
MakeLParam(
int
LoWord,
int
HiWord)
///
<summary>
///
获取窗体的父窗体对象,如果为null则表示是最顶层窗体
///
</summary>
public
Win32Window Parent
///
<summary>
///
获取最顶端的弹出窗体对象
///
</summary>
public
Win32Window LastActivePopup
///
<summary>
///
窗体的标题信息
///
</summary>
public
string
Text
///
<summary>
///
窗体对象的类名
///
</summary>
public
string
ClassName
///
<summary>
///
获取Window窗体的Long Value
///
</summary>
public
int
GetWindowLong(
int
index)
///
<summary>
///
设置Window窗体的Long Value
///
</summary>
public
int
SetWindowLong(
int
index,
int
value)
///
<summary>
///
该窗体对象的线程ID
///
</summary>
public
int
ThreadId
///
<summary>
///
该窗体对象的进程ID
///
</summary>
public
int
ProcessId
///
<summary>
///
窗体的布局
///
</summary>
public
WindowPlacement WindowPlacement
///
<summary>
///
判断窗体是否是最小化状态
///
</summary>
public
bool
Minimized
///
<summary>
///
判断窗体是否可见
///
</summary>
public
bool
Visible
///
<summary>
///
判断窗体是否是最大化状态
///
</summary>
public
bool
Maximized
///
<summary>
///
Windows窗体转换为BitMap对象
///
</summary>
public
Image WindowAsBitmap
///
<summary>
///
Windows的客户区域转换为Bitmap对象
///
</summary>
public
Image WindowClientAsBitmap
#endregion
2)辅助类Win32Window的使用例子代码如下所示
void
btnSearch_Click(
object
sender, EventArgs e)
Win32Window win = Win32Window.FindWindow(
null
,
this
.txtWindowName.Text);
if
(win !=
null
)
{
ArrayList list = win.Children;
foreach
(Win32Window sub
in
list)
{
if
(sub.Visible && sub.ClassName ==
"
ATL:30A4D1D8
"
)
{
sub.SendMessage(WindowMessage.WM_SETTEXT,
0
,
this
.txtInput.Text);
}
}
}
int
x =
288
;
int
y =
328
;
win.ClickWindow(
"
left
"
, x, y,
false
);
}
其中位置信息时通过Spy++监控出来的信息。