最近在想C#中的控件是如何绘制上去的,当然我想问的就是绘制是在什么时候触发的?网上找了找,似乎也有人在讨论,众说纷纭。于是将C#那个Forms结尾的dll给反编译了,似乎看出些猫腻,里面有几个和绘制相关的方法,OnPaint和OnItemdraw,如下图:

这是我们直接从源码中看到的,也就是说在这两个方法中又是通过事件去处理的。

Windows是基于消息的,所谓消息,就是指Windows发出的一个通知,告诉应用程序某个事情发生了某种变化,例如,单击鼠标、改变窗口尺寸、按下键盘上的一个键都会使Windows发送一个消。

在MFC中我们会看到WM_PAINT 这个消息,而这个消息对应的操作函数就是OnPaint,了解MFC中视图的话,就应该知道我们经常在Ondraw 方法中进行绘制,其实这个OnDraw方法是在OnPaint中调用的。而在C#中OnPaint会引发Paint,如果我们要对一些进行操作,重新Paint就行了。

在C#中是通过消息触发-然后调用OnPaint,OnDrawItem方法,然后调用一个派发事件的调用,对于事件C#开发人员应该不会陌生,什么单击,双击等。

事件我在合理简单的称之为一个委托的特殊变量,看来在C#中存在大量的委托或者大量的事件,今天就静下心来想了想,既然治理派发事件的其实是一个虚函数,虚函数是子类可以重写的,并且可以在运行时识别的,那为什么不在子类中直接重写虚函数,而还要派发事件呢?这里我通过两种方式都实现了我要的结果(ListBox隔行换色):

 

 重写事件


this.DrawItem += new DrawItemEventHandler(ListBoxEx_DrawItem); void ListBoxEx_DrawItem(object sender, DrawItemEventArgs e) { OnDrawItem1(e); } protected void OnDrawItem1(DrawItemEventArgs e) { if (e.Index != -1) { if ((e.State & DrawItemState.Selected) == DrawItemState.Selected) { RenderHelper.RenderBackgroundInternal(e.Graphics, e.Bounds, Color.FromArgb(255, 255, 255), Color.FromArgb(0, 0, 0), Color.Purple, RoundStyle.Left, true , true, LinearGradientMode.Vertical); } else { Color backColor; if (e.Index % 2 == 0) { backColor = Color.FromArgb(255, 255, 255); } else { backColor = Color.FromArgb(0, 255, 255); } using (SolidBrush brush = new SolidBrush(backColor)) { e.Graphics.FillRectangle(brush, e.Bounds); } } string text = Items[e.Index].ToString(); TextFormatFlags formatFlags = TextFormatFlags.VerticalCenter; if (RightToLeft == RightToLeft.Yes) { formatFlags |= TextFormatFlags.RightToLeft; } else { formatFlags |= TextFormatFlags.Left; } TextRenderer.DrawText( e.Graphics, text, Font, e.Bounds, ForeColor, formatFlags); if ((e.State & DrawItemState.Focus) == DrawItemState.Focus) { e.DrawFocusRectangle(); } } }
重写虚函数



protected void OnDrawItem(DrawItemEventArgs e) { base.OnDrawItem(e); if (e.Index != -1) { if ((e.State & DrawItemState.Selected) == DrawItemState.Selected) { RenderHelper.RenderBackgroundInternal(e.Graphics, e.Bounds, Color.FromArgb(255, 255, 255), Color.FromArgb(0, 0, 0), Color.Purple, RoundStyle.Left, true , true, LinearGradientMode.Vertical); } else { Color backColor; if (e.Index % 2 == 0) { backColor = Color.FromArgb(255, 255, 255); } else { backColor = Color.FromArgb(0, 255, 255); } using (SolidBrush brush = new SolidBrush(backColor)) { e.Graphics.FillRectangle(brush, e.Bounds); } } string text = Items[e.Index].ToString(); TextFormatFlags formatFlags = TextFormatFlags.VerticalCenter; if (RightToLeft == RightToLeft.Yes) { formatFlags |= TextFormatFlags.RightToLeft; } else { formatFlags |= TextFormatFlags.Left; } TextRenderer.DrawText( e.Graphics, text, Font, e.Bounds, ForeColor, formatFlags); if ((e.State & DrawItemState.Focus) == DrawItemState.Focus) { e.DrawFocusRectangle(); } } }

 

 

肯定是一样的,刚才已经说的很清楚了OnDrawItem中调用了DrawItem,这个只是顺序的不同而已,这种带来的好处,我个人认为,这里将主动权交给了我们,通过委托可以实现迟后的绑定,将要执行的操作暴露给了客户端。DrawItem是事件,是微软定义好的,那么事件的处理函数,将由我们实现。通过和MFC的对比,看来这两者在事件处理上本质上还是一样的,可谓换汤不换药。

委托到底有什么好处呢?这个问题我还没说吧。但是我不想说了,因为从上面可以看出就是委托才将消息跟我们的事件对应起来,这是上面的例子直接可以看出的,起到桥梁作用,起到了延后调用的作用,还有处理逻辑分离(MVC中就是在视图中定义事件或者委托变量,然后在Controller中绑定的)。此外,在给委托变量赋值的时候可以用“=”,也可以用“+=”,前者是赋值,而后者是相当于追加或者绑定,(如果是事件的话,直接用+=),但是在追加(绑定)之前先赋值,否则会直接报错,大家也可以在去尝试。

 

 

        int Pow2(int x)
        {
             return (int)Math.Pow(x, 2);
        }
    
                
            Pow PowTest2 = new Pow(this.Pow2);
           //使用+=之前先用等号赋值,不然出错       
              PowTest2 +=new Pow(this.Pow2);
             PowTest2.Invoke(4);
  
委托变量和在C++或者C语言中学的函数指针类似,因为在这两个语言中,函数名代表了函数所在位置的指针,所以可以定义一个有相同参数的变量,C#中的委托变量跟这个如出一辙:

  protected int add(int a, int b)
        {

            return a + b;
        }

        protected int sub(int a, int b)
        {

            return a - b;
        }

 

 

 

 public delegate int Calculate(int a, int b);
        Calculate pCal;
        public Form1()
        {
            
                    pCal = add;
        }

 

        private void Form1_Load(object sender, EventArgs e)
        {
        

 

            if (pCal != null)
            {
                int c=pCal(5, 3);

 

 

                pCal = sub;

 

                c = pCal(5, 3);

 

            }
        }

 

今天的这些就是自己的饿突发奇想,冥冥之中,希望自己有所长进,有所收获,也希望自己能将这种剖根问底的想法坚持到底!

推荐博文:http://www.cnblogs.com/BLoodMaster/archive/2010/07/06/1771926.html

posted on 2013-06-07 17:46  醉意人间  阅读(269)  评论(0编辑  收藏  举报