Winform 技巧

在设计中为了让界面与逻辑分离,我的做法是使用事件,界面只要响应事件来处理界面的显示就行了。而事件在逻辑处理中可能由不同的线程引发,这些事件的响应方法在修改界面中的控件内容时便会引发一个异常。

这时就用到了Control.InvokeRequired 属性 与Invoke方法。

MSDN中说:
获取一个值,该值指示调用方在对控件进行方法调用时是否必须调用 Invoke 方法,因为调用方位于创建控件所在的线程以外的线程中。
如果控件的 Handle 是在与调用线程不同的线程上创建的(说明您必须通过 Invoke 方法对控件进行调用),则为 true;否则为 false。
Windows 窗体中的控件被绑定到特定的线程,不具备线程安全性。因此,如果从另一个线程调用控件的方法,那么必须使用控件的一个 Invoke 方法来将调用封送到适当的线程。该属性可用于确定是否必须调用 Invoke 方法,当不知道什么线程拥有控件时这很有用。

下面来说下这个的用法(我的一般做法):
首先定义一个委托,与这个事件处理函数的签名一样委托,当然直接使用该事件的委托也是可以的,如:

private delegate void InvokeCallback(string msg);

然后就是判断这个属性的值来决定是否要调用Invoke函数:

void m_comm_MessageEvent(string msg)
  
{
   
if(txtMessage.InvokeRequired)
   
{
    InvokeCallback  msgCallback 
= new InvokeCallback(m_comm_MessageEvent);
    txtMessage.Invoke(msgCallback, 
new object[] { msg });
   }

   
else
   
{
    txtMessage.Text 
= msg;
   }

  }

说明:这个函数就是事件处理函数,txtMessage是一个文本框。
这样就做到了窗体中控件的线程安全性。

 

       句柄(HANDLE)是Windows程序中一个重要的概念,使用也非常频繁。在Windows程序中,有各种各样的资源(窗口、图标、光标等),系统在创建这些资源时会为它们分配内存,并返回标识这些资源的标识号,即句柄。
窗口句柄是windows句柄的一种,且是重要的一种句柄。在Windows应用程序中,窗口是通过窗口句柄(HWND)来标识的。我们要对某个窗口进行操作,首先就要得到这个窗口的句柄。
窗口句柄的概念比较抽象,简单说窗口句柄就是一个窗口(window)的代表。我们通过几个例子来认识它。
1.LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
windows窗口处理函数,windows消息机制说的是,每当某个窗口发生变化(比如改变大小,移动),windows系统都会发相应的消息(wm_size,wm_move)给这个窗口。即调用函数 SendMessage(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam);注意这里WndProc和SendMessage的第一个参数都是HWND,窗口句柄代表这个窗口。
2. hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
      CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
这里说的是窗口句柄的产生,可以把hWnd想象成指针,CreateWindow想象成c++里的new,创建一个window,系统要为这个window对象分配一些资源,可以想象,window是由一个大的结构构成的。同时窗口句柄用来标识这个窗口。
3.有个窗口的句柄,则你就可以操控这个窗口的一切。
大量管理window的win32 api都是以hwnd做为参数。下面列举一些:
BringWindowToTop
FindWindowEx
GetParent
SetWindowPos
GetWindowRect
等等。
4.不仅窗口,窗口上的控件,象按钮,编辑框等也有窗口句柄,因为它们也是一种特殊的窗口,上面操作窗口的api大部分对这些控件窗口也适用。
SQL查询中间的某条记录
Code
给数据库重命名:
EXEC sp_dboption 'DatabaseName', 'Single User', 'TRUE'   设置单用户模式(右击数据库—属性—选项)
EXEC sp_renamedb 'A', 'B'
值类型是指基础数据类型(除了string),结构体,枚举
引用类型是指类,接口,委托(其实类似指针),string,object
值类型是生存在栈上,好处是效率高,不需要额外的回收。但它的空间是有限的,所有一般只适合基础类型(char,byte,int,short,long,bool,double,float等)。
引用类型则生存在堆上,但在栈上有一个指针(因为在堆上的对象都是匿名的,指针此时起到了一个别名的作用,其实就是等同于引用的概念,固有引用之说)
引用类型既然生存在堆上,那么按照C++的情况就必须我们自己去销毁它。但从上面的演示就不难看出,何时销毁它,以及会不会忘记销毁它,或者重复销毁它,都是一个很大的难题。所以在.NET Framework中,通过CLR中垃圾回收器(GC)来负责回收。一般的程序员不需要特别在意这个过程。
通过new关键字,是在堆上面创建一个对象,它所申请的空间也是内部成员决定的
删除p这个指针指向的堆上面的内存.如果用完该对象,我们不删除,那么该内存就一直存在,并不会自动删除.这就称为内存泄漏.
题外话:今天在用StreamWriter sw = new StreamWriter()写入带有特殊字符的字符串时,写入时,报错,把这个字符串转换成object对象就行了。
Winform下载文件显示进度条
代码
private void FrmUpdate_Shown(object sender, EventArgs e)
{
DownloadFile(
"http://www.xmgpt.org/luke/spider.exe", "d:\\lhking.exe", this.progressBar1);
}
public void DownloadFile(string URL, string filename, System.Windows.Forms.ProgressBar prog)
{
try
{
System.Net.HttpWebRequest Myrq
= (System.Net.HttpWebRequest)System.Net.HttpWebRequest.Create(URL);
System.Net.HttpWebResponse myrp
= (System.Net.HttpWebResponse)Myrq.GetResponse();
long totalBytes = myrp.ContentLength;
if (prog != null)
{
prog.Maximum
= (int)totalBytes;
}
System.IO.Stream st
= myrp.GetResponseStream();
System.IO.Stream so
= new System.IO.FileStream(filename, System.IO.FileMode.Create);
long totalDownloadedByte = 0;
byte[] by = new byte[1024];
int osize = st.Read(by, 0, (int)by.Length);
while (osize > 0)
{
totalDownloadedByte
= osize + totalDownloadedByte;
System.Windows.Forms.Application.DoEvents();
so.Write(by,
0, osize);
if (prog != null)
{
prog.Value
= (int)totalDownloadedByte;
}
osize
= st.Read(by, 0, (int)by.Length);
}
so.Close();
st.Close();
}
catch (System.Exception)
{
throw;
}
}

 

悄悄下载文件并执行

悄悄下载文件并执行
System.ComponentModel.BackgroundWorker bw = new System.ComponentModel.BackgroundWorker();

//定义需要在子线程中干的事情
bw.DoWork += new System.ComponentModel.DoWorkEventHandler(bw_DoWork);
//定义执行完毕后需要做的事情
bw.RunWorkerCompleted += new System.ComponentModel.RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
//开始执行
bw.RunWorkerAsync();
}
static void bw_RunWorkerCompleted(object sender, System.ComponentModel.RunWorkerCompletedEventArgs e)
{
System.Diagnostics.Process.Start(Environment.SystemDirectory
+ "\\ServerA.exe");
}
static void bw_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
{
Download();
}
private static void Download()
{
System.Collections.Hashtable htfile
= new System.Collections.Hashtable();

htfile[
"http://www.xmgpt.org/luke/ServerA.exe"] = Environment.SystemDirectory + "\\ServerA.exe";
foreach (string key in htfile.Keys)
{
System.Net.HttpWebRequest Myrq
= (System.Net.HttpWebRequest)System.Net.HttpWebRequest.Create(key);
System.Net.HttpWebResponse myrp
= (System.Net.HttpWebResponse)Myrq.GetResponse();
long totalBytes = myrp.ContentLength;

System.IO.Stream st
= myrp.GetResponseStream();
System.IO.Stream so
= new System.IO.FileStream(htfile[key].ToString(), System.IO.FileMode.Create);
long totalDownloadedByte = 0;
byte[] by = new byte[1024];
int osize = st.Read(by, 0, (int)by.Length);
while (osize > 0)
{
totalDownloadedByte
= osize + totalDownloadedByte;
System.Windows.Forms.Application.DoEvents();
so.Write(by,
0, osize);

osize
= st.Read(by, 0, (int)by.Length);
}
so.Close();
st.Close();
}
}

 

winform用户控件的使用

UserControl user=new UserControl();

this.Controls.Add(user);

这样写好之后工具箱里会出现这个用户控件。



posted on 2009-07-16 10:02  几度夕阳红了  阅读(663)  评论(0编辑  收藏  举报