末日这天写篇博客吧,既然没来,那就纪念一下。
这次谈谈自制控件,也就是自定义控件,先上图,再说
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 Winform开发笔记(二)中基本提到了一些。为了配合本次讲解,我再次画了一张图
上图中,虚线框可以看做是一个.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,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,(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,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,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",int msg,int wParam,int lParam);
[Dllimport("user32.dll",CharSet = CharSet.auto)]
public static extern int SendMessage(IntPtr hWnd,StringBuilder param);
[Dllimport("user32.dll",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,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_norEDRAW = 0x0008,
SWP_SHOWWINDOW = 0x0040,
SWP_NOcopYBITS = 0x0100,
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++工具。
完了,剩下那个下次再写了,太多了。希望有帮助~
总结以上是内存溢出为你收集整理的.Net WInform开发笔记(三)谈谈自制控件(自定义控件)全部内容,希望文章能够帮你解决.Net WInform开发笔记(三)谈谈自制控件(自定义控件)所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)