当前位置: 移动技术网 > IT编程>开发语言>c# > .Net WInform开发笔记(三)谈谈自制控件(自定义控件)

.Net WInform开发笔记(三)谈谈自制控件(自定义控件)

2019年07月18日  | 移动技术网IT编程  | 我要评论
末日这天写篇博客吧,既然没来,那就纪念一下。 这次谈谈自制控件,也就是自定义控件,先上图,再说 1.扩展openfiledialog,在openfiledialog中添

末日这天写篇博客吧,既然没来,那就纪念一下。

这次谈谈自制控件,也就是自定义控件,先上图,再说

1.扩展openfiledialog,在openfiledialog中添加各种文件(.txt,.jpg,.excel等等)的预览功能

2.重写listbox,增加折叠、鼠标背影、分类等功能

-----------------------------分割线--------------------------------------------------------------
一、扩展openfiledialog

许多软件的打开对话框都有预览功能,最常见的就是图片预览,用鼠标选择一个图片文件后,右侧或者下侧就会有该图片的缩略图(photoshop中属于后者)。在winform编程中,有专门的打开文件对话框的类openfiledialog,但是他不提供文件预览功能,封装得实在太好。看看它公开那些接口

提到扩展,很多人可能想到继承它就可以扩展它,可惜openfiledialog声明为sealed,不允许从他继承。稍微底层一点的,想到可以通过win32 api来修改它的显示方式,只可惜,如你所见,它根本没提供handle属性,更别说handlecreated、handledestroyed等事件了。那么怎么样子搞呢?其实答案还是通过win32 api,只是我们取得它的句柄的方式要复杂一点而且调用api的时机隐晦了一点。

提示:

1.win32 api操作窗体需要知道窗体的句柄;

2.不熟悉win32编程的同学可以先上网查查资料,特别是不知道setparent、setwindowpos等api是干嘛的,我觉得以下的看不懂。

为什么说取得它的句柄复杂了一点?难道不是用“findwindow”、“findwindowex”、“ enumchildwindows”等获取openfiledialog的句柄,再用“setparent”、“setwindowpos”等api将.net控件(本例中是datagridview控件,当然可以使其他任何一种)添加到openfiledialog中去?没错,以上列举出来的api都是基本要用到的,“只是用在什么地方、什么时候用”是个比较麻烦的问题,原因如下:

1)我们知道openfiledialog显示的是模式对话框,也就是说,一旦它showdialog(),它以下的代码是不会再执行的,具体原因是什么(我以后的博客会专门讲为什么),你现在可以理解为openfiledialog()方法会阻塞调用线程,既然阻塞了调用线程,那么我们再无法控制程序了(直到它返回),根本谈不上再调用api获取openfiledialog的句柄然后去操作它。如果有人会说,“我可以另开辟线程去取openfiledialog得句柄再操作它”,恩,我不否定这个方法,只是我想说,如果你真的按照这个方法去试,那么肯定会陷入泥潭。因为你不仅要取它的句柄,你还要监视openfiledialog的一举一动,移动、缩放、用户鼠标点击选择文件、更改目录等,然后再操作.net控件(本例中是datagridview控件,下同),让.net控件去适应openfiledialog的大小等等,你会发现你忙死了,甚至有的你根本监视不了,比如用户点击选择文件、更改目录。

2)就算我们能够在openfiledialog显示之后,取得它的句柄,那么什么时候再调用其他api呢?比如什么时候调用setwindowpos,让.net控件适应openfiledialog的大小变化?什么时候知道用户选择文件发生了变化?

所以,api方法什么时候用?用在什么地方?就是接下来要讨论的东西。

我不知道各位在使用各种框架的时候,对“框架”的理解到什么程度,我觉得可以总结成一句话“跟个2b似地注册一些事件,然后苦逼地去写好每一个回调方法,我们却不知道为啥要这样写”,不是么?既然这样,那么我们的api方法只要写在了正确的回调方法中,我们就能到达想要的目的了。考虑几个问题:

1)openfiledialog显示,我们向其中添加.net控件。我们什么时候知道它显示?

2)openfiledialog大小发生变化时,我们要更新.net控件以适应新的大小。我们什么时候知道openfiledialog的大小发生了变化?

3)openfiledialog中用户选择的文件发生了变化,我们需要知道新选择的文件路径,用来显示在.net控件中。我们怎么知道选择了什么文件?(这里选择文件指用户用鼠标在openfiledialog中单击选取,不是点击“确定”后。)

以上所有的问题,其实在一个地方都可以知道,那就是监听openfiledialog窗体的windows消息,因为一个窗体的任何一个动作都伴随着一系列的windows消息(这个可以用spy++查看)。既然这样,那么我们可以在窗体处理windows消息的回调方法中调用api方法了,也就是窗体的control.wndproc方法中。之前已经说过了,openfiledialog声明为sealed,提供的接口少之又少,我们几乎根本不可能接触到openfiledialog的wndproc,更谈不上监听windows消息,然后调用api去操作它。这时候,nativewindow该出场了,先来引用一下msdn上对nativewindow的解释:

“提供窗口句柄和窗口过程的低级封装。”

说了像没说一样,其实就是说,将一个窗口句柄与nativewindow对象绑定后,该nativewindow对象就能接收到这个窗体的所有消息。说到windows消息,我想说一下windows桌面应用程序的运行流程,其实如果看了我前一篇博客的同学应该有些了解,中基本提到了一些。为了配合本次讲解,我再次画了一张图

上图中,虚线框可以看做是一个.net中的control类对象(或者其派生类,下同,控件即窗体、窗体即控件),正常情况下,winform程序会按照1->2->3的步骤运行,当我们将control类对象的handle(就是我们常说的窗口句柄,做了一下封装)与一个nativewindow对象绑定后,程序不再按照1->2->3这样的顺序运行了,他会按照1->2-1->2-2->3这样运行,也就是说,nativewindow对象可以拦截control类对象的windows消息,我们完全可以在nativewindow中重写他的wndproc方法,像处理自己的windows消息一样去处理control类对象的消息。所以,我们就可以在nativewindow对象的wndproc中调用我们的api方法。

接下来,上代码(代码只提供大概思路)

1.扩展对话框

复制代码 代码如下:

public class multiopenfiledialog
{
#region fields
private const setwindowposflags uflagshide =
setwindowposflags.swp_noactivate |
setwindowposflags.swp_noownerzorder |
setwindowposflags.swp_nomove |
setwindowposflags.swp_nosize |
setwindowposflags.swp_hidewindow;
#endregion
public string filename;
#region public methods
public dialogresult showdialog()
{
return showdialog(null);
}
public dialogresult showdialog(iwin32window owner)
{
using (openfiledialog open = new openfiledialog())
{
medianform median = new medianform(open);
median.show(owner);
win32.setwindowpos(median.handle, intptr.zero, 0, 0, 0, 0, uflagshide); //隐藏中间窗体
dialogresult dialogresult = open.showdialog(median); //将median作为openfiledialog的owner
median.close();
if (dialogresult == dialogresult.ok)
{
filename = open.filename;
}
return dialogresult;
}
}
#endregion
}

2.监听dialog的nativewindow

复制代码 代码如下:

view code
class dialognativewindow : nativewindow,idisposable
{
intptr handle; //待扩展openfiledialog的句柄
openfiledialog openfiledialog; //待扩展openfiledialog
datagridview addcontrol; //向窗体中添加新的控件
childcontrolnativewindow childnative;
bool init = false;

public dialognativewindow(intptr handle, openfiledialog openfiledialog)
{
this.handle = handle;
this.openfiledialog = openfiledialog;
assignhandle(handle);

//设置控件信息
addcontrol = new datagridview();
addcontrol.width = 600;
addcontrol.height = 200;
addcontrol.datasource = null;
}

#region override methods
protected override void wndproc(ref message m)
{
switch (m.msg)
{
case (int)msg.wm_showwindow: //窗体显示
{
nativechild();
addcontrol();
break;
}
case (int)msg.wm_sizing: //窗体大小改变
{
updatesize();
break;
}
case (int)msg.wm_windowposchanging: //窗体位置变化
{
updatelocation(m);
break;
}
}
base.wndproc(ref m);
}
#endregion

#region event handlers
void childnative_selectpathchanged(stringbuilder path)
{
//处理选择目录变化事件
//...
}

void childnative_selectfilechanged(stringbuilder file)
{
//处理选择文件变化事件
//如果是xls文件,将其显示在datagridview控件中
string str = file.tostring();
if (str.tolower().endswith(".xls"))
{
oledbmanager manager = new oledbmanager();
if (manager.connect("provider=microsoft.jet.oledb.4.0; data source=\'" + str + "\'; extended properties='excel 8.0;'"))
{
datatable tb = manager.searchtable();
if (tb != null)
{
addcontrol.rows.clear();
addcontrol.columns.clear();
foreach (datacolumn col in tb.columns)
{
addcontrol.columns.add(col.columnname, col.caption);
}
foreach (datarow row in tb.rows)
{
object[] objs = new object[tb.columns.count];
for (int i = 0; i < tb.columns.count; ++i)
{
objs[i] = row[i];
}
addcontrol.rows.add(objs);
}
}
}
}
else
{
addcontrol.rows.clear();
addcontrol.columns.clear();
}
}
#endregion

#region private methods
private void nativechild()
{
//查找openfiledialog中的子控件
win32.enumchildwindows(handle, new win32.enumwindowscallback(windowcallback), 0);
}
private void addcontrol()
{
//添加控件到openfiledialog界面
win32.setparent(addcontrol.handle, handle);
rect currentsize = new rect();
win32.getclientrect(handle, ref currentsize);
addcontrol.height = (int)currentsize.height;
addcontrol.location = new point((int)(currentsize.width - addcontrol.width), 0);

init = true;
}
private void updatelocation(message m)
{
if (!init) //只初始化openfiledialog的大小一次
{
windowpos pos = (windowpos)marshal.ptrtostructure(m.lparam, typeof(windowpos));
if (pos.flags != 0 && ((pos.flags & (int)swp_flags.swp_nosize) != (int)swp_flags.swp_nosize))
{
pos.cx += addcontrol.width; //修改openfiledialog的宽度
marshal.structuretoptr(pos, m.lparam, true);

rect currentsize = new rect();
win32.getclientrect(handle, ref currentsize);
addcontrol.height = (int)currentsize.height;
}
}
}
private void updatesize()
{
rect currentsize = new rect();
win32.getclientrect(handle, ref currentsize);
win32.setwindowpos(addcontrol.handle, (intptr)zorderpos.hwnd_bottom, 0, 0, (int)addcontrol.width, (int)currentsize.height, uflagssizeex); //新添加的控件与openfiledialog大小一致
}
private bool windowcallback(intptr handle, int lparam)
{
stringbuilder wndclass = new stringbuilder(256);
win32.getclassname(handle, wndclass, wndclass.capacity);//获取控件类名

if (wndclass.tostring().startswith("#32770")) //找到目标控件
{
childnative = new childcontrolnativewindow(handle);
childnative.selectfilechanged += new childcontrolnativewindow.selectfilechangedeventhandler(childnative_selectfilechanged);
childnative.selectpathchanged += new childcontrolnativewindow.selectpathchangedeventhandler(childnative_selectpathchanged);
return true;
}
return true;
}
#endregion

#region enums
private const setwindowposflags uflagssizeex =
setwindowposflags.swp_noactivate |
setwindowposflags.swp_noownerzorder |
setwindowposflags.swp_nomove |
setwindowposflags.swp_asyncwindowpos |
setwindowposflags.swp_defererase;
private const setwindowposflags uflagssize =
setwindowposflags.swp_noactivate |
setwindowposflags.swp_noownerzorder |
setwindowposflags.swp_nomove;
private const setwindowposflags uflagshide =
setwindowposflags.swp_noactivate |
setwindowposflags.swp_noownerzorder |
setwindowposflags.swp_nomove |
setwindowposflags.swp_nosize |
setwindowposflags.swp_hidewindow;
#endregion

#region idisposable 成员

public void dispose()
{
releasehandle(); //释放与openfiledialog的句柄关联
if (childnative != null)
{
childnative.selectfilechanged -= new childcontrolnativewindow.selectfilechangedeventhandler(childnative_selectfilechanged);
childnative.selectpathchanged -= new childcontrolnativewindow.selectpathchangedeventhandler(childnative_selectpathchanged);
childnative.dispose();
}

}

#endregion
}

3.监听子控件的nativewindow
复制代码 代码如下:

class childcontrolnativewindow : nativewindow,idisposable
{
intptr handle; //需要被监听消息的子控件句柄
public childcontrolnativewindow(intptr handle)
{
this.handle = handle;
assignhandle(handle);
}

#region override methods
protected override void wndproc(ref message m)
{
switch (m.msg)
{
case (int)msg.wm_notify:
ofnotify ofnotify = (ofnotify)marshal.ptrtostructure(m.lparam, typeof(ofnotify));
if (ofnotify.hdr.code == (uint)dialogchangestatus.cdn_selchange) //openfiledialog选择文件发生变化
{
stringbuilder file = new stringbuilder(256);
win32.sendmessage(win32.getparent(handle), (int)dialogchangeproperties.cdm_getfilepath, (int)256, file);
if (selectfilechanged != null)
selectfilechanged(file); //通知注册者
}
else if (ofnotify.hdr.code == (uint)dialogchangestatus.cdn_folderchange) //openfiledialog选择目录发生变化
{
stringbuilder path = new stringbuilder(256);
win32.sendmessage(win32.getparent(handle), (int)dialogchangeproperties.cdm_getfolderpath, (int)256, path);
if (selectpathchanged != null)
selectpathchanged(path); //通知注册者
}
break;
}
base.wndproc(ref m);
}
#endregion

#region delegate
public delegate void selectfilechangedeventhandler(stringbuilder file);
public delegate void selectpathchangedeventhandler(stringbuilder path);
#endregion

#region events
public event selectfilechangedeventhandler selectfilechanged; //当openfiledialog的选择文件发生变化时发生
public event selectpathchangedeventhandler selectpathchanged; //当openfiledialog的选择目录发生变化时发生
#endregion

#region idisposable 成员

public void dispose()
{
releasehandle(); //终止与子控件句柄的关联
}

#endregion
}

4.中间过渡窗体,用来获取openfiledialog的句柄
复制代码 代码如下:
 
class medianform : form
{
openfiledialog open = null;
dialognativewindow dialognative;

public medianform(openfiledialog open)
{
this.open = open;
startposition = formstartposition.manual;
location = new system.drawing.point(-1000, -1000); //避免界面闪烁
}
protected override void onclosing(system.componentmodel.canceleventargs e)
{
if (dialognative != null)
{
dialognative.dispose(); //释放资源
}
base.onclosing(e);
}
protected override void wndproc(ref message m)
{
if (m.msg == (int) msg.wm_activate)
{
dialognative = new dialognativewindow(m.lparam, open); //m.lparam为要打开的窗口句柄,开始监听openfiledialog的windows消息
}
base.wndproc(ref m);
}
}

5.访问excel文件的类
复制代码 代码如下:

class oledbmanager
{
oledbconnection conn;
/// <summary>
/// 连接excel文件
/// </summary>
/// <param name="connstr"></param>
/// <returns></returns>
public bool connect(string connstr)
{
try
{
conn = new oledbconnection(connstr);
conn.open();
return true;
}
catch
{
return false;
}
}
/// <summary>
/// 查找第一张表中的数据
/// </summary>
/// <returns></returns>
public datatable searchtable()
{
try
{
datatable tb = new datatable();
string sql = "select * from [sheet1$]";
oledbcommand com = new oledbcommand(sql, conn);
oledbdataadapter adp = new oledbdataadapter(com);
adp.fill(tb);
return tb;
}
catch
{
return null;
}
}
}

6.几个win32结构体、枚举类型以及api声明(本代码参考codeproject上的一篇文章)
复制代码 代码如下:

public static class win32
{
#region delegates
public delegate bool enumwindowscallback(intptr hwnd, int lparam);
#endregion

#region user32
[dllimport("user32.dll", charset = charset.auto)]
public static extern intptr getparent(intptr hwnd);
[dllimport("user32.dll")]
public static extern int getdlgctrlid(intptr hwndctl);
[dllimport("user32.dll", charset = charset.auto, exactspelling = true)]
public static extern int mapwindowpoints(intptr hwnd, intptr hwndto, ref point pt, int cpoints);
[dllimport("user32.dll", setlasterror = true)]
public static extern bool getwindowinfo(intptr hwnd, out windowinfo pwi);
[dllimport("user32.dll")]
public static extern void getwindowtext(intptr hwnd, stringbuilder param, int length);
[dllimport("user32.dll")]
public static extern void getclassname(intptr hwnd, stringbuilder param, int length);
[dllimport("user32.dll")]
public static extern bool enumchildwindows(intptr hwndparent, enumwindowscallback lpenumfunc, int lparam);
[dllimport("user32.dll")]
public static extern bool enumwindows(enumwindowscallback lpenumfunc, int lparam);
[dllimport("user32.dll", charset = charset.auto)]
public static extern bool releasecapture();
[dllimport("user32.dll", charset = charset.auto)]
public static extern intptr setcapture(intptr hwnd);
[dllimport("user32.dll", charset = charset.auto)]
public static extern intptr childwindowfrompointex(intptr hparent, point pt, childfrompointflags flags);
[dllimport("user32.dll", entrypoint = "findwindowexa", callingconvention = callingconvention.stdcall, charset = charset.ansi)]
public static extern intptr findwindowex(intptr hwndparent, intptr hwndchildafter, string lpszclass, string lpszwindow);
[dllimport("user32.dll")]
public static extern intptr setparent(intptr hwndchild, intptr hwndnewparent);
[dllimport("user32.dll", charset = charset.auto)]
public static extern int postmessage(intptr hwnd, uint msg, intptr wparam, intptr lparam);
[dllimport("user32.dll", charset = charset.auto)]
public static extern int postmessage(intptr hwnd, int msg, int wparam, int lparam);
[dllimport("user32.dll", charset = charset.auto)]
public static extern int sendmessage(intptr hwnd, uint msg, intptr wparam, intptr lparam);
[dllimport("user32.dll", charset = charset.auto)]
public static extern int sendmessage(intptr hwnd, int msg, int wparam, int lparam);
[dllimport("user32.dll", charset = charset.auto)]
public static extern int sendmessage(intptr hwnd, int msg, int wparam, stringbuilder param);
[dllimport("user32.dll", charset = charset.auto)]
public static extern int sendmessage(intptr hwnd, int msg, int wparam, char[] chars);
[dllimport("user32.dll", charset = charset.auto)]
public static extern intptr begindeferwindowpos(int nnumwindows);
[dllimport("user32.dll", charset = charset.auto)]
public static extern intptr deferwindowpos(intptr hwinposinfo, intptr hwnd, intptr hwndinsertafter, int x, int y, int width, int height, setwindowposflags flags);
[dllimport("user32.dll", charset = charset.auto)]
public static extern bool enddeferwindowpos(intptr hwinposinfo);
[dllimport("user32.dll", charset = charset.auto)]
public static extern bool setwindowpos(intptr hwnd, intptr hwndinsertafter, int x, int y, int width, int height, setwindowposflags flags);
[dllimport("user32.dll")]
public static extern bool getwindowrect(intptr hwnd, ref rect rect);
[dllimport("user32.dll")]
public static extern bool getclientrect(intptr hwnd, ref rect rect);
#endregion
}
#region swp_flags
[flags]
public enum swp_flags
{
swp_nosize = 0x0001,
swp_nomove = 0x0002,
swp_nozorder = 0x0004,
swp_noactivate = 0x0010,
swp_framechanged = 0x0020, /* the frame changed: send wm_nccalcsize */
swp_showwindow = 0x0040,
swp_hidewindow = 0x0080,
swp_noownerzorder = 0x0200, /* don't do owner z ordering */

swp_drawframe = swp_framechanged,
swp_noreposition = swp_noownerzorder
}
#endregion

#region dialogchangestatus
public enum dialogchangestatus : long
{
cdn_first = 0xfffffda7,
cdn_initdone = (cdn_first - 0x0000),
cdn_selchange = (cdn_first - 0x0001),
cdn_folderchange = (cdn_first - 0x0002),
cdn_shareviolation = (cdn_first - 0x0003),
cdn_help = (cdn_first - 0x0004),
cdn_fileok = (cdn_first - 0x0005),
cdn_typechange = (cdn_first - 0x0006),
}
#endregion

#region dialogchangeproperties
public enum dialogchangeproperties
{
cdm_first = (0x400 + 100),
cdm_getspec = (cdm_first + 0x0000),
cdm_getfilepath = (cdm_first + 0x0001),
cdm_getfolderpath = (cdm_first + 0x0002),
cdm_getfolderidlist = (cdm_first + 0x0003),
cdm_setcontroltext = (cdm_first + 0x0004),
cdm_hidecontrol = (cdm_first + 0x0005),
cdm_setdefext = (cdm_first + 0x0006)
}
#endregion

#region imenotify
public enum imenotify
{
imn_closestatuswindow = 0x0001,
imn_openstatuswindow = 0x0002,
imn_changecandidate = 0x0003,
imn_closecandidate = 0x0004,
imn_opencandidate = 0x0005,
imn_setconversionmode = 0x0006,
imn_setsentencemode = 0x0007,
imn_setopenstatus = 0x0008,
imn_setcandidatepos = 0x0009,
imn_setcompositionfont = 0x000a,
imn_setcompositionwindow = 0x000b,
imn_setstatuswindowpos = 0x000c,
imn_guideline = 0x000d,
imn_private = 0x000e
}
#endregion

#region folderviewmode
public enum folderviewmode
{
default = 0x7028,
icon = default + 1,
smallicon = default + 2,
list = default + 3,
details = default + 4,
thumbnails = default + 5,
title = default + 6,
thumbstrip = default + 7,
}
#endregion

#region enum dialogviewproperty
public enum defaultviewtype
{
icons = 0x7029,
list = 0x702b,
details = 0x702c,
thumbnails = 0x702d,
tiles = 0x702e,
}
#endregion

#region buttonstyle
public enum buttonstyle : long
{
bs_pushbutton = 0x00000000,
bs_defpushbutton = 0x00000001,
bs_checkbox = 0x00000002,
bs_autocheckbox = 0x00000003,
bs_radiobutton = 0x00000004,
bs_3state = 0x00000005,
bs_auto3state = 0x00000006,
bs_groupbox = 0x00000007,
bs_userbutton = 0x00000008,
bs_autoradiobutton = 0x00000009,
bs_pushbox = 0x0000000a,
bs_ownerdraw = 0x0000000b,
bs_typemask = 0x0000000f,
bs_lefttext = 0x00000020,
bs_text = 0x00000000,
bs_icon = 0x00000040,
bs_bitmap = 0x00000080,
bs_left = 0x00000100,
bs_right = 0x00000200,
bs_center = 0x00000300,
bs_top = 0x00000400,
bs_bottom = 0x00000800,
bs_vcenter = 0x00000c00,
bs_pushlike = 0x00001000,
bs_multiline = 0x00002000,
bs_notify = 0x00004000,
bs_flat = 0x00008000,
bs_rightbutton = bs_lefttext
}
#endregion

#region zorderpos
public enum zorderpos
{
hwnd_top = 0,
hwnd_bottom = 1,
hwnd_topmost = -1,
hwnd_notopmost = -2
}
#endregion

#region static control styles
public enum staticcontrolstyles : long
{
ss_left = 0x00000000,
ss_center = 0x00000001,
ss_right = 0x00000002,
ss_icon = 0x00000003,
ss_blackrect = 0x00000004,
ss_grayrect = 0x00000005,
ss_whiterect = 0x00000006,
ss_blackframe = 0x00000007,
ss_grayframe = 0x00000008,
ss_whiteframe = 0x00000009,
ss_useritem = 0x0000000a,
ss_simple = 0x0000000b,
ss_leftnowordwrap = 0x0000000c,
ss_ownerdraw = 0x0000000d,
ss_bitmap = 0x0000000e,
ss_enhmetafile = 0x0000000f,
ss_etchedhorz = 0x00000010,
ss_etchedvert = 0x00000011,
ss_etchedframe = 0x00000012,
ss_typemask = 0x0000001f,
ss_realsizecontrol = 0x00000040,
ss_noprefix = 0x00000080, /* don't do "&" character translation */
ss_notify = 0x00000100,
ss_centerimage = 0x00000200,
ss_rightjust = 0x00000400,
ss_realsizeimage = 0x00000800,
ss_sunken = 0x00001000,
ss_editcontrol = 0x00002000,
ss_endellipsis = 0x00004000,
ss_pathellipsis = 0x00008000,
ss_wordellipsis = 0x0000c000,
ss_ellipsismask = 0x0000c000
}
#endregion

#region combo box styles
public enum comboboxstyles : long
{
cbs_simple = 0x0001,
cbs_dropdown = 0x0002,
cbs_dropdownlist = 0x0003,
cbs_ownerdrawfixed = 0x0010,
cbs_ownerdrawvariable = 0x0020,
cbs_autohscroll = 0x0040,
cbs_oemconvert = 0x0080,
cbs_sort = 0x0100,
cbs_hasstrings = 0x0200,
cbs_nointegralheight = 0x0400,
cbs_disablenoscroll = 0x0800,
cbs_uppercase = 0x2000,
cbs_lowercase = 0x4000
}
#endregion

#region window styles
public enum windowstyles : long
{
ws_overlapped = 0x00000000,
ws_popup = 0x80000000,
ws_child = 0x40000000,
ws_minimize = 0x20000000,
ws_visible = 0x10000000,
ws_disabled = 0x08000000,
ws_clipsiblings = 0x04000000,
ws_clipchildren = 0x02000000,
ws_maximize = 0x01000000,
ws_caption = 0x00c00000,
ws_border = 0x00800000,
ws_dlgframe = 0x00400000,
ws_vscroll = 0x00200000,
ws_hscroll = 0x00100000,
ws_sysmenu = 0x00080000,
ws_thickframe = 0x00040000,
ws_group = 0x00020000,
ws_tabstop = 0x00010000,
ws_minimizebox = 0x00020000,
ws_maximizebox = 0x00010000,
ws_tiled = 0x00000000,
ws_iconic = 0x20000000,
ws_sizebox = 0x00040000,
ws_popupwindow = 0x80880000,
ws_overlappedwindow = 0x00cf0000,
ws_tiledwindow = 0x00cf0000,
ws_childwindow = 0x40000000
}
#endregion

#region window extended styles
public enum windowexstyles
{
ws_ex_dlgmodalframe = 0x00000001,
ws_ex_noparentnotify = 0x00000004,
ws_ex_topmost = 0x00000008,
ws_ex_acceptfiles = 0x00000010,
ws_ex_transparent = 0x00000020,
ws_ex_mdichild = 0x00000040,
ws_ex_toolwindow = 0x00000080,
ws_ex_windowedge = 0x00000100,
ws_ex_clientedge = 0x00000200,
ws_ex_contexthelp = 0x00000400,
ws_ex_right = 0x00001000,
ws_ex_left = 0x00000000,
ws_ex_rtlreading = 0x00002000,
ws_ex_ltrreading = 0x00000000,
ws_ex_leftscrollbar = 0x00004000,
ws_ex_rightscrollbar = 0x00000000,
ws_ex_controlparent = 0x00010000,
ws_ex_staticedge = 0x00020000,
ws_ex_appwindow = 0x00040000,
ws_ex_overlappedwindow = 0x00000300,
ws_ex_palettewindow = 0x00000188,
ws_ex_layered = 0x00080000
}
#endregion

#region childfrompointflags
public enum childfrompointflags
{
cwp_all = 0x0000,
cwp_skipinvisible = 0x0001,
cwp_skipdisabled = 0x0002,
cwp_skiptransparent = 0x0004
}
#endregion

#region hittest
public enum hittest
{
hterror = (-2),
httransparent = (-1),
htnowhere = 0,
htclient = 1,
htcaption = 2,
htsysmenu = 3,
htgrowbox = 4,
htsize = htgrowbox,
htmenu = 5,
hthscroll = 6,
htvscroll = 7,
htminbutton = 8,
htmaxbutton = 9,
htleft = 10,
htright = 11,
httop = 12,
httopleft = 13,
httopright = 14,
htbottom = 15,
htbottomleft = 16,
htbottomright = 17,
htborder = 18,
htreduce = htminbutton,
htzoom = htmaxbutton,
htsizefirst = htleft,
htsizelast = htbottomright,
htobject = 19,
htclose = 20,
hthelp = 21
}
#endregion

#region windows messages
public enum msg
{
wm_null = 0x0000,
wm_create = 0x0001,
wm_destroy = 0x0002,
wm_move = 0x0003,
wm_size = 0x0005,
wm_activate = 0x0006,
wm_setfocus = 0x0007,
wm_killfocus = 0x0008,
wm_enable = 0x000a,
wm_setredraw = 0x000b,
wm_settext = 0x000c,
wm_gettext = 0x000d,
wm_gettextlength = 0x000e,
wm_paint = 0x000f,
wm_close = 0x0010,
wm_queryendsession = 0x0011,
wm_quit = 0x0012,
wm_queryopen = 0x0013,
wm_erasebkgnd = 0x0014,
wm_syscolorchange = 0x0015,
wm_endsession = 0x0016,
wm_showwindow = 0x0018,
wm_ctlcolor = 0x0019,
wm_wininichange = 0x001a,
wm_settingchange = 0x001a,
wm_devmodechange = 0x001b,
wm_activateapp = 0x001c,
wm_fontchange = 0x001d,
wm_timechange = 0x001e,
wm_cancelmode = 0x001f,
wm_setcursor = 0x0020,
wm_mouseactivate = 0x0021,
wm_childactivate = 0x0022,
wm_queuesync = 0x0023,
wm_getminmaxinfo = 0x0024,
wm_painticon = 0x0026,
wm_iconerasebkgnd = 0x0027,
wm_nextdlgctl = 0x0028,
wm_spoolerstatus = 0x002a,
wm_drawitem = 0x002b,
wm_measureitem = 0x002c,
wm_deleteitem = 0x002d,
wm_vkeytoitem = 0x002e,
wm_chartoitem = 0x002f,
wm_setfont = 0x0030,
wm_getfont = 0x0031,
wm_sethotkey = 0x0032,
wm_gethotkey = 0x0033,
wm_querydragicon = 0x0037,
wm_compareitem = 0x0039,
wm_getobject = 0x003d,
wm_compacting = 0x0041,
wm_commnotify = 0x0044,
wm_windowposchanging = 0x0046,
wm_windowposchanged = 0x0047,
wm_power = 0x0048,
wm_copydata = 0x004a,
wm_canceljournal = 0x004b,
wm_notify = 0x004e,
wm_inputlangchangerequest = 0x0050,
wm_inputlangchange = 0x0051,
wm_tcard = 0x0052,
wm_help = 0x0053,
wm_userchanged = 0x0054,
wm_notifyformat = 0x0055,
wm_contextmenu = 0x007b,
wm_stylechanging = 0x007c,
wm_stylechanged = 0x007d,
wm_displaychange = 0x007e,
wm_geticon = 0x007f,
wm_seticon = 0x0080,
wm_nccreate = 0x0081,
wm_ncdestroy = 0x0082,
wm_nccalcsize = 0x0083,
wm_nchittest = 0x0084,
wm_ncpaint = 0x0085,
wm_ncactivate = 0x0086,
wm_getdlgcode = 0x0087,
wm_syncpaint = 0x0088,
wm_ncmousemove = 0x00a0,
wm_nclbuttondown = 0x00a1,
wm_nclbuttonup = 0x00a2,
wm_nclbuttondblclk = 0x00a3,
wm_ncrbuttondown = 0x00a4,
wm_ncrbuttonup = 0x00a5,
wm_ncrbuttondblclk = 0x00a6,
wm_ncmbuttondown = 0x00a7,
wm_ncmbuttonup = 0x00a8,
wm_ncmbuttondblclk = 0x00a9,
wm_ncxbuttondown = 0x00ab,
wm_ncxbuttonup = 0x00ac,
wm_ncxbuttondblclk = 0x00ad,
wm_keydown = 0x0100,
wm_keyup = 0x0101,
wm_char = 0x0102,
wm_deadchar = 0x0103,
wm_syskeydown = 0x0104,
wm_syskeyup = 0x0105,
wm_syschar = 0x0106,
wm_sysdeadchar = 0x0107,
wm_keylast = 0x0108,
wm_ime_startcomposition = 0x010d,
wm_ime_endcomposition = 0x010e,
wm_ime_composition = 0x010f,
wm_ime_keylast = 0x010f,
wm_initdialog = 0x0110,
wm_command = 0x0111,
wm_syscommand = 0x0112,
wm_timer = 0x0113,
wm_hscroll = 0x0114,
wm_vscroll = 0x0115,
wm_initmenu = 0x0116,
wm_initmenupopup = 0x0117,
wm_menuselect = 0x011f,
wm_menuchar = 0x0120,
wm_enteridle = 0x0121,
wm_menurbuttonup = 0x0122,
wm_menudrag = 0x0123,
wm_menugetobject = 0x0124,
wm_uninitmenupopup = 0x0125,
wm_menucommand = 0x0126,
wm_ctlcolormsgbox = 0x0132,
wm_ctlcoloredit = 0x0133,
wm_ctlcolorlistbox = 0x0134,
wm_ctlcolorbtn = 0x0135,
wm_ctlcolordlg = 0x0136,
wm_ctlcolorscrollbar = 0x0137,
wm_ctlcolorstatic = 0x0138,
wm_mousemove = 0x0200,
wm_lbuttondown = 0x0201,
wm_lbuttonup = 0x0202,
wm_lbuttondblclk = 0x0203,
wm_rbuttondown = 0x0204,
wm_rbuttonup = 0x0205,
wm_rbuttondblclk = 0x0206,
wm_mbuttondown = 0x0207,
wm_mbuttonup = 0x0208,
wm_mbuttondblclk = 0x0209,
wm_mousewheel = 0x020a,
wm_xbuttondown = 0x020b,
wm_xbuttonup = 0x020c,
wm_xbuttondblclk = 0x020d,
wm_parentnotify = 0x0210,
wm_entermenuloop = 0x0211,
wm_exitmenuloop = 0x0212,
wm_nextmenu = 0x0213,
wm_sizing = 0x0214,
wm_capturechanged = 0x0215,
wm_moving = 0x0216,
wm_devicechange = 0x0219,
wm_mdicreate = 0x0220,
wm_mdidestroy = 0x0221,
wm_mdiactivate = 0x0222,
wm_mdirestore = 0x0223,
wm_mdinext = 0x0224,
wm_mdimaximize = 0x0225,
wm_mditile = 0x0226,
wm_mdicascade = 0x0227,
wm_mdiiconarrange = 0x0228,
wm_mdigetactive = 0x0229,
wm_mdisetmenu = 0x0230,
wm_entersizemove = 0x0231,
wm_exitsizemove = 0x0232,
wm_dropfiles = 0x0233,
wm_mdirefreshmenu = 0x0234,
wm_ime_setcontext = 0x0281,
wm_ime_notify = 0x0282,
wm_ime_control = 0x0283,
wm_ime_compositionfull = 0x0284,
wm_ime_select = 0x0285,
wm_ime_char = 0x0286,
wm_ime_request = 0x0288,
wm_ime_keydown = 0x0290,
wm_ime_keyup = 0x0291,
wm_mousehover = 0x02a1,
wm_mouseleave = 0x02a3,
wm_cut = 0x0300,
wm_copy = 0x0301,
wm_paste = 0x0302,
wm_clear = 0x0303,
wm_undo = 0x0304,
wm_renderformat = 0x0305,
wm_renderallformats = 0x0306,
wm_destroyclipboard = 0x0307,
wm_drawclipboard = 0x0308,
wm_paintclipboard = 0x0309,
wm_vscrollclipboard = 0x030a,
wm_sizeclipboard = 0x030b,
wm_askcbformatname = 0x030c,
wm_changecbchain = 0x030d,
wm_hscrollclipboard = 0x030e,
wm_querynewpalette = 0x030f,
wm_paletteischanging = 0x0310,
wm_palettechanged = 0x0311,
wm_hotkey = 0x0312,
wm_print = 0x0317,
wm_printclient = 0x0318,
wm_theme_changed = 0x031a,
wm_handheldfirst = 0x0358,
wm_handheldlast = 0x035f,
wm_afxfirst = 0x0360,
wm_afxlast = 0x037f,
wm_penwinfirst = 0x0380,
wm_penwinlast = 0x038f,
wm_app = 0x8000,
wm_user = 0x0400,
wm_reflect = wm_user + 0x1c00
}
#endregion

#region setwindowposflags
public enum setwindowposflags
{
swp_nosize = 0x0001,
swp_nomove = 0x0002,
swp_nozorder = 0x0004,
swp_noredraw = 0x0008,
swp_noactivate = 0x0010,
swp_framechanged = 0x0020,
swp_showwindow = 0x0040,
swp_hidewindow = 0x0080,
swp_nocopybits = 0x0100,
swp_noownerzorder = 0x0200,
swp_nosendchanging = 0x0400,
swp_drawframe = 0x0020,
swp_noreposition = 0x0200,
swp_defererase = 0x2000,
swp_asyncwindowpos = 0x4000
}
#endregion
}

#region windowinfo
[structlayout(layoutkind.sequential)]
public struct windowinfo
{
public uint32 cbsize;
public rect rcwindow;
public rect rcclient;
public uint32 dwstyle;
public uint32 dwexstyle;
public uint32 dwwindowstatus;
public uint32 cxwindowborders;
public uint32 cywindowborders;
public uint16 atomwindowtype;
public uint16 wcreatorversion;
}
#endregion

#region point
[structlayout(layoutkind.sequential)]
public struct point
{
public int x;
public int y;

#region constructors
public point(int x, int y)
{
this.x = x;
this.y = y;
}

public point(point point)
{
x = point.x;
y = point.y;
}
#endregion
}
#endregion

#region rect
[structlayout(layoutkind.sequential)]
public struct rect
{
public uint left;
public uint top;
public uint right;
public uint bottom;

#region properties
public point location
{
get { return new point((int)left, (int)top); }
set
{
right -= (left - (uint)value.x);
bottom -= (bottom - (uint)value.y);
left = (uint)value.x;
top = (uint)value.y;
}
}

public uint width
{
get { return right - left; }
set { right = left + value; }
}

public uint height
{
get { return bottom - top; }
set { bottom = top + value; }
}
#endregion

#region overrides
public override string tostring()
{
return left + ":" + top + ":" + right + ":" + bottom;
}
#endregion
}
#endregion

#region windowpos
[structlayout(layoutkind.sequential)]
public struct windowpos
{
public intptr hwnd;
public intptr hwndafter;
public int x;
public int y;
public int cx;
public int cy;
public uint flags;

#region overrides
public override string tostring()
{
return x + ":" + y + ":" + cx + ":" + cy + ":" + ((swp_flags)flags).tostring();
}
#endregion
}
#endregion

#region nccalcsize_params
[structlayout(layoutkind.sequential)]
public struct nccalcsize_params
{
public rect rgrc1;
public rect rgrc2;
public rect rgrc3;
public intptr lppos;
}
#endregion

#region nmhdr
[structlayout(layoutkind.sequential)]
public struct nmhdr
{
public intptr hwndfrom;
public uint idfrom;
public uint code;
}
#endregion

#region ofnotify
[structlayout(layoutkind.sequential)]
public struct ofnotify
{
public nmhdr hdr;
public intptr openfilename;
public intptr filenameshareviolation;
}
#endregion

补充一下
1.代码只提供思路,不能拿来继承一下,就能实现自己想要的功能。

2.可以自己将代码中dialognativewindow类的addcontrol替换为其他控件,比如picturebox用来预览图片、textbox用来预览txt文件、richtextbox用来预览代码文件等等,还可自由组合。

3.可以自己将代码中dialognativewindow类的两个事件(selectedfilechanged、selectpathchanged)移到multiopenfiledialog中,并使其对外开放,外部程序可以监听该事件。

4.如果想做成通用类,拿过来继承一下就可以实现自己想要的效果,建议使multiopenfiledialog从usercontrol,并将addcontrol设为自己。也就是说将自己添加到openfiledialog中去,multiopenfiledialog的派生类就可以在vs中设计自己想要的效果。

5.一个窗体新建显示时,它的拥有者会接收许多消息,包括wm_activate、wm_idle等等,并且lparam参数为新建窗体的句柄。

复制代码 代码如下:
 
class form1:form
{
private void form1_load(object sender,eventargs e)
{
using(openfiledialog dia = new openfiledialog())
{
dia.showdialog(this);
}
}
protected override void wndproc(ref message m)
{
//当dia显示时,它的拥有者即为this,这里会接受一连串的window消息,并且它的lparam参数为dia的句柄
base.wndproc(ref m);
}
}

6.windows中窗体和所谓的控件(button、textbox)本质上没有区别,任务栏与qq聊天框或者chrome浏览器的地址栏对我们程序员来讲,是同一个东西。

7.与窗体有关的win32 api基本都需要窗体句柄,其实任何一个api几乎都需要知道操作对象的句柄(不一定是窗体)。

8.windows中任何一个窗体(控件)理论上都是平级的,不管是否同一进程,也就是说,我的winform应用程序只要知道了chrome浏览器窗体的句柄,就可以控制chrome浏览器,监听chrome窗体的windows消息(除非chrome程序本身禁止了此操作)。

9.windows桌面应用程序开发中,(部分平台、语言)理解四个东西,即进程、线程 、窗体(已经说了,是广义上的窗体)、消息。

10.查看系统中以上四个东西,可以使用spy++工具。

完了,剩下那个下次再写了,太多了。希望有帮助~

如您对本文有疑问或者有任何想说的,请点击进行留言回复,万千网友为您解惑!

相关文章:

验证码:
移动技术网