龙盟编程博客 | 无障碍搜索 | 云盘搜索神器
快速搜索
主页 > web编程 > asp.net编程 >

ASP.NET开发组件之用Label控件模拟网页链接的组件(2)

时间:2009-12-21 11:47来源:未知 作者:admin 点击:
分享到:
本组件是为了让 Label 显示为网页链接的效果,那么首先组件必须知道对哪个 Label 进行操作。那么首先添加一个 Label 类型的属性。篇首提到组件一般是对控

本组件是为了让Label显示为网页链接的效果,那么首先组件必须知道对哪个Label进行操作。那么首先添加一个Label类型的属性。篇首提到组件一般是对控件的事件进行处理,那么就必须用“+=”去绑定控件事件和事件处理方法。在什么时候绑定?下面让我们先了解一下窗体背后的故事。

在“解决方案资源管理器”中随便打开一个窗体的Designer.cs文件,可以看到如下代码段。

设计器代码1

 

分析代码可以看出来,最底部是窗体中控件和组件变量的声明,展开IniitalizeComponent方法,可以看到首先是控件变量的实例化,然后是对各个控件的属性设置。其中包含了对事件处理程序的设置,例如下面对button1Click事件的设置:this.button1.Click += new System.EventHandler(this.button1_Click);

设计器代码2

 

而切换到窗体代码,可以看到如下代码:

窗体代码

 

在窗体类的构造函数中,调用了InitializeComponent方法,这意味着窗体实例化的时候完成了对窗体上所有控件组件以及相关事件处理方法的设置。

了解窗体背后的故事之后,我们就可以在设置组件的属性的时候将目标Label控件的事件绑定到事件处理方法,这样就可以保证窗体实例化的时候将事件绑定到对应的处理方法上。当然还有其他方法,比如采用ISupportInitialize接口,在以后的文章中会介绍。声明的属性如下: 

Code
        private Label m_TargetLabel;
        
/// <summary>
        
/// 目标 Label 控件
        
/// </summary>
        [Category(c_ControlCategory), Description("目标 Label 控件。")]
        
public Label TargetLabel
        {
            
get { return m_TargetLabel; }
            
set 
            {
                
if (m_TargetLabel != value)
                {
                    
this.HandleLabelMouseEvent(m_TargetLabel, false);//取消绑定之前控件的事件
                    m_TargetLabel = value;
                    
this.HandleLabelMouseEvent(m_TargetLabel, true);//绑定当前控件的事件
                }
            }
        }

        
/// <summary>
        
/// 绑定Label的鼠标事件
        
/// </summary>
        
/// <param name="TargetLabel">目标Label控件</param>
        
/// <param name="HandleFlag">绑定标志位,true为绑定,false为取消绑定</param>
        private void HandleLabelMouseEvent(Label TargetLabel, bool HandleFlag)
        {
            
if (TargetLabel != null && !this.DesignMode)
            {
                
if (HandleFlag)
                {
                    TargetLabel.MouseEnter 
+= new EventHandler(Label_MouseEnter);
                    TargetLabel.MouseLeave 
+= new EventHandler(Label_MouseLeave);
                    TargetLabel.MouseDown 
+= new MouseEventHandler(Label_MouseDown);
                    TargetLabel.MouseUp 
+= new MouseEventHandler(Label_MouseUp);
                }
                
else
                {
                    TargetLabel.MouseEnter 
-= new EventHandler(Label_MouseEnter);
                    TargetLabel.MouseLeave 
-= new EventHandler(Label_MouseLeave);
                    TargetLabel.MouseDown 
-= new MouseEventHandler(Label_MouseDown);
                    TargetLabel.MouseUp 
-= new MouseEventHandler(Label_MouseUp);
                }
            }
        }

 

 

 

分析这段代码,首先在属性上方有[Category(c_ControlCategory), Description("目标 Label 控件。")]。这叫做Attribute,中文称为特性,以便与Property(属性)区别。关于特性的详细介绍,请参考开篇中给出的相关链接资料。

这里介绍一下涉及到的特性的相关知识。要使用特性,必须添加对System.ComponentModel命名控件的引用,即在代码顶部添加using System.ComponentModel。而特性最直观的应用就是在PropertyGrid中可以看到,如下图。详细的介绍请参考如下链接:

http://www.cnblogs.com/guanjinke/archive/2006/12/06/584714.html

http://www.cnblogs.com/mapserver/articles/344458.html

属性窗口

 

Catagory特性是用来在PropertyGrid控件中进行分类的,通过相同的Category特性标记的属性会被分配到一组中。这里声明了两个私有常量,因为Category特性不接受变量。

Code
        //CategoryAttribute相关常量
        private const string c_ControlCategory = "控制";
        
private const string c_ApparanceCategory = "Appearance";

这里声明了两个用于Category特性的常量,一个是“控制”,一个是“Appearance”,但是在PropertyGrid控件中显示的却都是中文。因为在.NET中已经集成了常用的Category,比如AppearanceBehaviorLayout等,当Category设置为这些值的时候,IDE就会将其显示为IDE的当前语言。

Description特性是用来在PropertyGrid控件中显示属性的描述信息的。当需要对属性进行详细解释的时候,就采用Description特性,方便用户理解。

 

set代码段中首先判断之前的目标Label控件是否与设置的值是否一致,不一致则取消之前的Label控件的事件绑定,然后再绑定新控件。为什么必须先取消呢,因为事件绑定到处理方法上之后会一直有效,如果不取消,就算将其他对象的事件绑定到同一个处理方法上,只要之前的事件发生,还是会调用处理方法。这一点就必须理解委托的概念,因为事件就是通过委托实现的。关于委托,这里不作过多的阐述,不了解的朋友可以查阅相关资料。

这里又提出一个问题:如果窗体上有很多个Label控件都需要实现网页链接的效果,那岂不是需要有很多个SimulateLinkLabel组件与之一一对应?这样做当然可以,但效率有点低了。通过上面介绍的事件绑定机制,可以灵活避免这个问题。因为多个控件的事件可以绑定到同一个方法,那么可以将HandleLabelMouseEvent方法设置为public,通过代码去绑定需要网页链接效果的Label控件,这些Label控件任何一个触发了事件都会去调用对应的事件处理方法。

另外在HandleLabelMouseEvent方法中有一个this.DesignMode,这代表当前状态是否是设计时。有时候需要根据设计时还是运行时做出一些特定的操作。这里表示如果在设计时就不需要绑定控件事件,因为这时候绑定了也没什么效果。但有时候确实需要在设计时执行特定操作,就必须判断这个属性了。至于具体的应用,在以后的文章中遇到了再详细分析。

 

为了模拟网页链接效果,在鼠标相关事件处理方法中需要改变Label控件的外观。而这些外观要做到灵活设置,就必须添加相关的属性。这里添加了部分颜色相关的属性,如果需要,还可以添加其他外观相关的属性,比如图片,边框,不同状态的字体等。

Code
        private Color m_ActiveForeColor = Color.Yellow;
        
/// <summary>
        
/// 活动链接的前景色
        
/// </summary>
        [Category(c_ApparanceCategory), Description("活动链接的前景色。"), DefaultValue(typeof(Color), "Yellow")]
        
public Color ActiveForeColor
        {
            
get { return m_ActiveForeColor; }
            
set { m_ActiveForeColor = value; }
        }

        
private bool m_EnableActiveForeColor = true;
        
/// <summary>
        
/// 指示是否启用活动链接前景色
        
/// </summary>
        [Category(c_ControlCategory), Description("指示是否启用活动链接前景色。"), DefaultValue(true)]
        
public bool EnableActiveForeColor
        {
            
get { return m_EnableActiveForeColor; }
            
set { m_EnableActiveForeColor = value; }
        }

        
private Color m_ActiveBackColor = Color.Blue;
        
/// <summary>
        
/// 活动链接的背景色
        
/// </summary>
        [Category(c_ApparanceCategory), Description("活动链接的背景色。"), DefaultValue(typeof(Color), "Blue")]
        
public Color ActiveBackColor
        {
            
get { return m_ActiveBackColor; }
            
set { m_ActiveBackColor = value; }
        }

        
private bool m_EnableActiveBackColor = false;
        
/// <summary>
        
/// 指示是否启用活动链接背景色
        
/// </summary>
        [Category(c_ControlCategory), Description("指示是否启用活动链接背景色。"), DefaultValue(false)]
        
public bool EnableActiveBackColor
        {
            
get { return m_EnableActiveBackColor; }
            
set { m_EnableActiveBackColor = value; }
        }

        
private Color m_HoverForeColor = Color.Red;
        
/// <summary>
        
/// 悬浮状态前景色
        
/// </summary>
        [Category(c_ApparanceCategory), Description("悬浮状态前景色。"), DefaultValue(typeof(Color), "Red")]
        
public Color HoverForeColor
        {
            
get { return m_HoverForeColor; }
            
set { m_HoverForeColor = value; }
        }

        
private bool m_EnableHoverForeColor = true;
        
/// <summary>
        
/// 指示是否启用悬浮状态前景色
        
/// </summary>
        [Category(c_ControlCategory), Description("指示是否启用悬浮状态前景色。"), DefaultValue(true)]
        
public bool EnableHoverForeColor
        {
            
get { return m_EnableHoverForeColor; }
            
set { m_EnableHoverForeColor = value; }
        }

        
private Color m_HoverBackColor = Color.Blue;
        
/// <summary>
        
/// 悬浮状态背景色
        
/// </summary>
        [Category(c_ApparanceCategory), Description("悬浮状态背景色。"), DefaultValue(typeof(Color), "Blue")]
        
public Color HoverBackColor
        {
            
get { return m_HoverBackColor; }
            
set { m_HoverBackColor = value; }
        }

        
private bool m_EnableHoverBackColor = false;
        
/// <summary>
        
/// 指示是否启用悬浮状态背景色
        
/// </summary>
        [Category(c_ControlCategory), Description("指示是否启用悬浮状态背景色。"), DefaultValue(false)]
        
public bool EnableHoverBackColor
        {
            
get { return m_EnableHoverBackColor; }
            
set { m_EnableHoverBackColor = value; }
        }

这里为每一个颜色属性提供了一个对应的标志位属性,指示是否启用对应颜色属性。这些属性上方除了CategoryDescription特性外,还多了一个DefaultValue特性。DefaultValue特性是用来指示属性的默认值的,详细资料可以参考http://www.cnblogs.com/guanjinke/archive/2006/12/24/602451.html

DefaultValue特性最直观的理解就是:在PropertyGrid中如果是默认值,则显示为普通字体,如果被修改了,则显示为粗体。在Designer.cs代码中如果是默认值,则不会生成设置该属性的代码。

一般情况下DefaultValue特性只接受简单类型的值,比如数值、逻辑值、字符串。对颜色的设置则需要特殊处理,因为Color不是简单类型。从代码中可以看到颜色属性上方的DefaultValue特性格式为DefaultValue(typeof(Color), "ColorName")MSDN中的解释是:

DefaultValueAttribute(Type, String) :初始化 DefaultValueAttribute 类的新实例,将指定的值转换为指定的类型,并将固定区域性作为翻译上下文。

参数

type

类型:System.Type

表示要将值转换为的类型的 Type。

value

类型:System.String

可以通过该类型的 TypeConverter 和美国英语转换为该类型的 String。

这里又出现了新的概念,TypeConverter,详细介绍可以参考

http://www.cnblogs.com/guanjinke/archive/2006/12/11/588609.html

http://www.cnblogs.com/guanjinke/archive/2006/12/11/589372.html

http://www.cnblogs.com/guanjinke/archive/2006/12/14/592605.html

http://www.cnblogs.com/mapserver/articles/353722.html

当然并不是所有类型的属性都可以通过这种方法设置默认值的,这种属性的类型必须有一个对应的TypeConverter,其中的CanConvertFrom方法必须能接受字符串才行。通过Reflector查看Color的代码,可以看到Color类有一个对应的TypeConvert特性,其中的类型是ColorConverter

反编译Color

 ColorConverter继承了TypeConverter,其中的CanConvertFrom方法如下,说明可以从字符串转换成Color。当然,真正从字符串转换为Color的代码必须在ConvertFrom中实现。

反编译ColorConverter

 

以上介绍完属性,就该介绍方法了。绑定事件的方法HandleLabelMouseEvent已经在上面给出了,剩下就是鼠标事件的处理方法。

Code
收藏文章
表情删除后不可恢复,是否删除
取消
确定
图片正在上传,请稍后...
评论内容为空!
还没有评论,快来抢沙发吧!

热评话题

按钮 内容不能为空!
立刻说两句吧! 查看0条评论
精彩图集

赞助商链接