事件
C#事件分为几个步骤:
定义事件
定义处理函数
为事件添加处理函数
激活事件
事件被激活后自动调用处理函数。
public event messagehandleer shenzhijianglin;
public void ooohelp(object sender, EventArgs e)
{
MessageBox.Show("IM be clicked! help!");
}
newf.shenzhijianglin += newf.ooohelp;
shenzhijianglin.Invoke(sender, e);
激活事件可以使用Invoke激活,也可以使用别的方式激活,因为.NET有很多的东西都可以激活自己本身的事件。
而且为事件添加处理函数需要使用+=操作符,这个操作符也太难看了,太丑了。
匿名方法和定义委托类型都需要delegate,也就是说一个关键字其实有两种意思,是有歧义的。
匿名:正常来说,为事件添加处理函数,语法为:
public event MouseEventHandler MouseDown;
MouHook.MouseDown += mh_OnMouEvent;
void mh_OnMouEvent(object sender, MouseEventArgs e)//任何鼠标事件
{}
也就是说先定
义一个事件,然后为这个事件添加处理函数,然后定义一个函数。
但是通过匿名,可以不声明函数,直接将事件处理函数定义出来:
public event messagehandleer shenzhijianglin;
newf.shenzhijianglin += delegate { MessageBox.Show("IM be clicked! help!"); };//匿名 和托管无关
这样方便一点。
委托
C#是没有指针的。
所以说,想要实现函数指针,就需要用到委托。
我的理解是,委托就是一个函数指针。
先声明一个委托类型
protected delegate int HookProc(int nCode, int wParam, IntPtr lParam);
然后声明一个委托类型的 委托变量
protected HookProc _hookCallback;
最后将这个委托变量指向一个函数,注意参数要与委托类型一致
_hookCallback = new HookProc(HookCallbackProcedure);
这样就可以实现动态的改变委托变量指向的函数。
钩子
钩子比较麻烦,怎么说呢,其实看看那代码就行了。总的来说,就是调用WINDOWS自己的库函数,系统会捕获鼠标键盘的动作事件,然后调用这些一个事件处理函数,来处理捕获到的消息。然后再写一个事件在处理捕获之后的详细的处理。
public void Start()
{
if (!_isStarted &&
_hookType != 0)
{
//确保_hookCallback不是一个空的引用
//如果是,GC会随机回收它,并且一个空的引用会爆出异常
_hookCallback = new HookProc(HookCallbackProcedure);
using (Process curPro = Process.GetCurrentProcess())
{
using (ProcessModule curMod = curPro.MainModule)
{
_handleToHook = (int)SetWindowsHookExW(
_hookType,
_hookCallback,
GetModuleHandle(curMod.ModuleName),
0);
}
}
// 钩成功
if (_handleToHook != 0)
{
_isStarted = true;
}
}
}
public void Stop()
{
if (_isStarted)
{
UnhookWindowsHookEx(_handleToHook);
_isStarted = false;
}
}
UDP:
using System.Net.Sockets;
using System.Net;
IPEndPoint localIpep;
private UdpClient udpcRecv;
localIpep = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 8888); // 本机IP,指定的端口号
byte[] bytRecv = udpcRecv.Receive(ref remoteIpep);
udpcRecv.Close();
多线程操纵控件:
经常会遇到跨线程访问的情况,很多人就说要用到委托;比如在辅助线程中要去更新一个UI界面上的label控件,通常会有一个if else判断语句:
if (label1.InvokeRequired)
这句是在判断label1控件是否是调用线程创建的,即判断是否跨线程调用,是则返回true,否则返回false;注意,这里判断的是调用线程是否是创建该控件的线程,因为调用线程是用户自己新建的一个辅助线程,下文中的mythread,而label控件是由主线程创建,因此,if语句的条件成立,执行该语句块的内容。注意该语句块的内容,首先实例化了一个用户自定义的委托,并把threadHandler方法绑定到该实例上,之后调用Invoke方法执行该委托,避免了子线程直接调用主线程的控件。
子线程给编辑框赋值则报错,需要使用此方式来赋值。原理:定义一个委托,指向一个新的SetText,然后触发此事件。
public delegate void SetTextCallback(string text, string text2);
private void SetText(string text, string text2)
{
if (this.textBox1.InvokeRequired)
{
SetTextCallback d = new SetTextCallback(SetText);
this.Invoke(d, new object[] { text, text2 });
}
else
{
//在此设置textBox1的文本
this.textBox1.Text = text;
this.textBox2.Text = text2;
}
}
private void SetText2(string text, string text2)
{
if (this.textBox1.InvokeRequired)
{
SetTextCallback d = new SetTextCallback(SetText);
this.Invoke(d, new object[] { text, text2 });
}
else
{
//在此设置textBox1的文本
this.textBox5.Text = text;
this.textBox7.Text = text2;
}
}
Action 与 Func是.NET类库中增加的内置委托,以便更加简洁方便的使用委托。
最初使用委托时,均需要先定义委托类型,然后定义一个符合委托类型签名的函数,
在调用前,需声明并创建委托对象,将指定函数与委托进行关联。
如例1:
public delegate int Math(int param1,int param2);定义委托类型
Public int Add(int param1,int param2)//定义同签名函数
{
Return param1+param2;
}
Math math;//声明委托
math=new Math(Add);创建委托对象,与指定进行关联
math(3,4);//调用委托函数
例1通过简单改造:
Func<int,int,int> math=Add;//指定委托对象并关联函数
math(3,4);//调用委托函数
Lambda:
Func<int,int,int> math=(param1,param2)=>
{
Return param1+param2;
}
Action的使用如同上面Func的使用一样,只是缺少了返回类型,直接调用委托函数。
if (UnAllocGrid.InvokeRequired)
{
UnAllocGrid.Invoke(new Action(() =>
{
UnAllocGrid.DataSource = DatasourUnAlloc;
UnAllocView.RefreshData();
//UnAllocView.ExpandAllGroups();
this.RightUnAllocCheck.Checked = false;
}));
}
结构体转字节数组:
/// <summary>
/// 发送的时候先要把结构转换成字节数组
/// 将结构转换为字节数组,结构对象字节数组
/// </summary>
public byte[] StructToBytes(object obj)
{
//得到结构体的大小
int size = Marshal.SizeOf(obj);
//创建byte数组
byte[] bytes = new byte[size];
//分配结构体大小的内存空间
IntPtr structPtr = Marshal.AllocHGlobal(size);
//将结构体拷到分配好的内存空间
Marshal.StructureToPtr(obj, structPtr, false);
//从内存空间拷到byte数组
Marshal.Copy(structPtr, bytes, 0, size);
//释放内存空间
Marshal.FreeHGlobal(structPtr);
//返回byte数组
return bytes;
}
/// <summary>
/// byte数组转结构
/// byte数组
/// 结构类型
/// 转换后的结构
/// </summary>
public object BytesToStruct(byte[] bytes, Type type)
{
//得到结构的大小
int size = Marshal.SizeOf(type);
//Log(size.ToString(), 1);
//byte数组长度小于结构的大小
if (size > bytes.Length)
{
//返回空
return null;
}
//分配结构大小的内存空间
IntPtr structPtr = Marshal.AllocHGlobal(size);
//将byte数组拷到分配好的内存空间
Marshal.Copy(bytes, 0, structPtr, size);
//将内存空间转换为目标结构
object obj = Marshal.PtrToStructure(structPtr, type);
//释放内存空间
Marshal.FreeHGlobal(structPtr);
//返回结构
return obj;
}