{
protected override void WndProc(ref Message m)
{
Console.WriteLine(m.ToString());
base.WndProc(ref m);
}
}
MyRichTextBox rtb = new MyRichTextBox();
private void frmMain_Load(object sender, EventArgs e)
{
this.Controls.Add(rtb);
}
private void button1_Click(object sender, EventArgs e)
{
this.rtb.Text = this.textBox1.Text;
}
测试后的打印的内容:
msg=0x115 (WM_VSCROLL) hwnd=0x10b34 wparam=0x1 lparam=0x0 result=0x0
msg=0x204e (WM_REFLECT + WM_NOTIFY) hwnd=0x10b34 wparam=0x10b34 lparam=0x517bf48 result=0x0
msg=0x2111 (WM_REFLECT + WM_COMMAND) hwnd=0x10b34 wparam=0x6020b34 lparam=0x10b34 result=0x0
msg=0xf (WM_PAINT) hwnd=0x10b34 wparam=0x0 lparam=0x0 result=0x0
msg=0x2111 (WM_REFLECT + WM_COMMAND) hwnd=0x10b34 wparam=0x4000b34 lparam=0x10b34 result=0x0
msg=0xb8 hwnd=0x10b34 wparam=0x0 lparam=0x0 result=0x0
msg=0x215 (WM_CAPTURECHANGED) hwnd=0x10b34 wparam=0x0 lparam=0x0 result=0x0
msg=0x115 (WM_VSCROLL) hwnd=0x10b34 wparam=0x8 lparam=0x0 result=0x0
msg=0x204e (WM_REFLECT + WM_NOTIFY) hwnd=0x10b34 wparam=0x10b34 lparam=0x517bf48 result=0x0
msg=0x84 (WM_NCHITTEST) hwnd=0x10b34 wparam=0x0 lparam=0xc600b7 result=0x0
msg=0x84 (WM_NCHITTEST) hwnd=0x10b34 wparam=0x0 lparam=0xc600b7 result=0x0
msg=0x20 (WM_SETCURSOR) hwnd=0x10b34 wparam=0x10b34 lparam=0x2000007 result=0x0
msg=0xa0 (WM_NCMOUSEMOVE) hwnd=0x10b34 wparam=0x7 lparam=0xc600b7 result=0x0
msg=0x84 (WM_NCHITTEST) hwnd=0x10b34 wparam=0x0 lparam=0xc600b8 result=0x0
msg=0x84 (WM_NCHITTEST) hwnd=0x10b34 wparam=0x0 lparam=0xc600b8 result=0x0
从一大堆结果中找自己感兴趣的,啊哈,有了,
msg=0x115 (WM_VSCROLL) hwnd=0x10b34 wparam=0x8 lparam=0x0 result=0x0
这就是我想要的内容,大力水手与你猜猜猜开始了,
什么是msg=0x115,每行的msg都不一样,当然了windows消息不一样,那么msg就不一样。
那么hwnd是什么?windows程序接触多了,是个傻子也知道这是句柄,也可以认为是指针,谁的指针,当然是你操作的对象的指针,那么是不是用这个家伙就可以代表着那个对象,啊哈,答对了。
wparam呢?lparam呢?不好猜了吧,我也不知道,w和l不知道并不意味这咱们啥都不知道,param这知道,参数嘛。
下面我们来解决这个问题:
从面向对象的角度上看,如果我们将对象的地址或指针换了,那么他所操作的应该是其他的对象。
着手的地方应该是WndProc方法,这个方法有一个强制引用参数Message,既然是强制引用,那么这小子很有可能是个值类型的玩意,但对我们没什么影响。我们的目标是RichText1滚到哪里,RichTextBox2也滚到哪里,这样,我们就只换我们操作的对象就可以了。
现在要考虑的是将Message怎么传递给另外的RichTextBox,并且能够实现功能。在windows体系本身来说用的就是事件消息机制,那我们为什么不能再画一个瓢呢?啊哈,.Net本身就有一个委托机制。
先做一个委托吧。
public delegate void SendMessage(Message msg);
下来在MyRichTextBox中做一个事件SendMessageEvent。
public event SendMessage SendMessageEvent;
当WndProc执行的时候激发这个事件。
public event SendMessage SendMessageEvent;
protected override void WndProc(ref Message m)
{
SendMessageEvent(m);
base.WndProc(ref m);
}
但是这个消息要能让另一个RichTextBox滚动也需要执行WndProc,但是WndProc为受保护方法,没法子,只好做了一个公开的方法,
public void Scroll(Message m)
{
m.HWnd = this.Handle;
WndProc(ref m);
}
在使用的时候,用以下方式:
MyRichTextBox c1 = new MyRichTextBox();
MyRichTextBox c2 = new MyRichTextBox();
private void Form1_Load(object sender, EventArgs e)
{
c1.SendMessageEvent += new SendMessage(c1_SendMessageEvent);
this.Controls.Add(c1);
this.Controls.Add(c2);
}
void c1_SendMessageEvent(Message msg)
{
c2.Scroll(msg);
}
c1为源RichTextBox,c2为被动RichTextBox,c1滚动,c2也跟着滚动。
其实大家看到这儿,怎么回事,c2的滚动还是要调用c2的Scroll方法,这算那门子事啊,大力水手曰:世道艰难,求人不如求己,但是c2的发财,是由于c1的消息,所以大力水手曰:信息是第一生产力。
是否就此天下太平了?四海欢腾了?九州高歌了?
回顾我们的目标,我们要两个RichTextBox同步滚动,的确实现了,但是如果去掉:c1.SendMessageEvent += new SendMessage(c1_SendMessageEvent);将会引发NullReferenceException?
原因是这个事件没有被一个合适的方法所订阅,你就想调用这个方法,解决之道也简单,加一个简单的判空即可:
if (SendMessageEvent!=null)
{
SendMessageEvent(m);
}
够了吗,够了,天下太平了?四海欢腾了?九州高歌了?
没有,这回是多了,怎么回事?无论在c1上做什么操作,在c2上就有什么结果,我只想要同步滚动而已,太多了,应该只拦截那些滚动的方法。
if (m.Msg==0x115)
{
if (SendMessageEvent!=null)
{
SendMessageEvent(m);
}
}
base.WndProc(ref m);
0x115为滚动,但是...,但是...,嗯,总有点不太对劲的地方,做一下全面测试,啊,找到了,刚才看到Scroll就以为找到了滚动,将谁忽略了?!哪有啊,肯定有!哦,明白了那个字母“V”,我以为那是一个修饰符而已,看来还是很有用处的,什么用处啊?到底是啥啊,你想急死我啊,嘿,还就是,谁让你不好好学习了。那是vertical,垂直啊,我说嘛,加上了这个横向滚动咋就不行了,看来还得再来一个咯,还得把横向滚动的消息放过,那么找吧,又找到了一个HScroll就是它了。
再改改if (m.Msg==0x115 || m.Msg==0x114)。
还不太美,毕竟不能太违反八荣八耻:将0x114,0x115改为两个常数。
private const int WM_HSCROLL = 0x0114;
private const int WM_VSCROLL = 0x0115;
天下太平了?四海欢腾了?九州高歌了?
因为这两个常量是同一类型,处于同一个地位,因而,最好将他们做为一个常量组,.Net体系中有常量组吗?有啊,改名了,叫枚举。
public enum WindowsMessage
{
WM_HSCROLL = 0x0114,
WM_VSCROLL = 0x0115
}
因而final version应该是:
public enum WindowsMessage
{
WM_HSCROLL = 0x0114,
WM_VSCROLL = 0x0115
}
public delegate void SendMessage(Message msg);
public class MyRichTextBox:System.Windows.Forms.RichTextBox
{
public event SendMessage SendMessageEvent;
protected override void WndProc(ref Message m)
{
if (m.Msg==WindowsMessage.WM_HSCROLL || m.Msg==WindowsMessage.WM_VSCROLL)
{
if (SendMessageEvent!=null)
{
SendMessageEvent(m);
}
}
base.WndProc(ref m);
}
public void Scroll(Message m)
{
m.HWnd = this.Handle;
WndProc(ref m);
}
}
这样就功德圆满了,收工。
文章来源: http://blog.sina.com.cn/s/blog_49458c2701007woh.html