委托杂谈

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

 

 

 

最近在想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

相关文章
|
27天前
|
Java C++
继承杂谈。
继承杂谈。
17 0
|
4月前
|
存储 C# C++
C#进阶-委托(Delegrate)
类似于 C 或 C++ 中函数的指针,委托是C#的函数指针,是存有对某个方法的引用的一种引用类型变量。引用可在运行时被改变。本篇文章我们将讲解C#里委托的类型及如何使用。委托的语法第一次接触难免感到陌生,最好的学习方式就是在项目中多去使用,相信会有很多感悟。
28 0
C# 委托的实战应用
个人感觉既然是新手接触委托 肯定不喜欢一大串的概念 直接上写法吧 概念问题百度搜一下 大面积雷同随便看 但是写法你们要慎重选择学习
|
监控 C#
艾伟_转载:把委托说透(1):开始委托之旅 委托与接口
委托,本是一个非常基础的.NET概念,但前一阵子在园子里却引起轩然大波。先是Michael Tao的随笔让人们将委托的写法与茴香豆联系到了一起,接着老赵又用一系列文章分析委托写法的演变,并告诫“嘲笑孔乙己的朋友们,你们在一味鄙视“茴”的四种写法的同时,说不定也失去了一个了解中国传统文化的机会呢!”。
980 0