关键字:WinForm Designer DesignTime Attribute 组件 控件 开发 设计时

在设计时,
看看TextBox控件,Multiline属性设置为false时只能左右方向改变大小,这是怎么实现的呢?
我自定义了一个控件,想要一些属性不显示在属性对话框里,该怎么办呢?
在DataGrid控件的右键菜单里会比其它控件多一项“自动套用格式(A)”,我可以做到类似的功能吗?

使用.net提供的Designer特性,您可以为组件指定设计器,通过自定义的设计器,我们可以很方便的改变组件设计时的行为。在.net中,所有设计器都要实现IDesigner接口。要实现自己的设计器,您可以实现IDesigner接口或直接从已有的设计器类继承如ComponentDesigner类。

接下来我们用一个实际的例子来说明如何创建自己的设计器并实现上述功能,在本文的例子里我选择由ControlDesigner类继承来实现自己的设计器,它是继承自ComponentDesigner类的。查看它的成员列表可以发现,ControlDesigner定义了一个SelectionRules只读属性,该属性可以实现控制控件在某个方向上改变大小的功能。

下面我们就来实现一个自定义的设计器:
public class LabelLineDesigner : System.Windows.Forms.Design.ControlDesigner
{
    
public LabelLineDesigner():base()
    
{}

    
/// <summary>
    
/// 重载SelectionRules属性自定义选择规则
    
/// </summary>

    public override SelectionRules SelectionRules
    
{
        
get
        
{
            SelectionRules selectionRules 
= SelectionRules.Moveable | SelectionRules.Visible | SelectionRules.LeftSizeable | SelectionRules.RightSizeable;
            
            
return selectionRules;
        }

    }

}

OK,我们已经实现了一个简单的设计器,那么如何把它应用到控件上呢?请继续往下看,假设我们自定义了一个名为LabelLine的控件,要应用LabelLineDesigner设计器使用下面方法:
[Designer(typeof(LabelLineDesigner))]//为控件指定设计器
public class LabelLine : System.Windows.Forms.Control
{
    ……
}

此时,如果你在窗体上放置一个LabelLine控件话,你可以看到现在它只能从左右方向上改变控件的大小了。改变LabelLineDesigner类SelectionRules属性值的组合,你可以实现一些有趣的功能,比如控件在设计时不能被选择,如果你想要做一个可视化的报表设计器,这个功能可能会很有用。

现在,这个控件已经不能用鼠标在上下方向改变大小了,但通过属性窗口,我们修改控件的Size属性可以随意改变它的大小,这可不是我希望的。怎么办呢?对,把这个属性藏起来,不让它出现在属性窗口上。

不让一个控件属性显示在属性窗口中,一种方法可以通过IDesignerFilter接口实现,另一种方法可以使用Browable特性。我们一个一个来试。

查了一下SDK文档,ComponentDesigner提供了IDesignerFilter接口的空实现。我们可以重写该实现的方法,从而在设计时调整关联组件的特性、属性和事件。
/// <summary>
/// 重载PostFilterProperties方法隐藏属性
/// </summary>

protected override void PostFilterProperties(IDictionary properties)
{
    
foreach(string prop in unbrowsableProperties)
    
{
        
        properties.Remove(prop);
    }

    
base.PostFilterProperties (properties);
}

//想到去掉的属性
private static readonly string[] unbrowsableProperties = {  "Dock","Size"};

将上面代码添加到LabelLineDesigner类中,编译一下,在属性窗口查看该控件的属性,Size和Dock属性真的不见了。再用鼠标改变一下控件的大小,你会发现怎么没有反应了。怎么会这样?

先不管它,再来试Browable特性,在LableLine类中添加下面代码:
[Browsable(false)]
public new System.Drawing.Size Size
{
    
get
    
{
        
return base.Size;
    }

    
set
    
{
        
base.Size = value;
    }

}

编译一下,再到属性窗口查看,Size属性不见了,用鼠标改变控件大小,也没有问题了。看来这个方法可行。

这两种方法有什么区别呢?原来第一种隐藏属性的方法是将属性从控件属性列表中删除,而调整控件大小时需要同时改变Size属性的值,此时再访问控件的Size属性时已经不存在,所以控件的大小就不能改变了。而应用Browable特性只是让该属性不显示在属性窗口里,并不删除该属性。即第一种方法是删除属性而不是隐藏属性。

接下来,我想在自定义控件的右键菜单里添加一项显示“关于”对话框的功能,也可以通过LabelLineDesigner来实现,在LabelLineDesigner类中添加如下代码:
private System.ComponentModel.Design.DesignerVerb verb = null;
        
private System.ComponentModel.Design.DesignerVerbCollection _Verbs = null;

public override System.ComponentModel.Design.DesignerVerbCollection Verbs
{
    
get
    
{
        
if (_Verbs == null)
        
{
            _Verbs 
= new System.ComponentModel.Design.DesignerVerbCollection();
            _Verbs.Add(verb);
        }


        
return _Verbs;
                
    }

}



private void OnAbout(object sender, EventArgs args) 
{
    System.Windows.Forms.MessageBox.Show(
"显示你的信息");
}


微软把Verbs译成“设计时谓词”,初次看到这个词,我实在无法理解它究竟是做什么的,后来才发现原来在设计时环境中显示控件右键菜单时,会将Verbs属性的内容关联到右键菜单中,单击该菜单项时会调用适当的方法,从而在设计时实现一些特殊的功能。另外利用该方法添加到右键菜单项目也会同时出现在属性窗口中。

到此为止,我们前面提到的三个问题都解决了。其实这些内容在SDK文档中都有介绍,最好的学习资料就在我们手边,而我们却经常忽略了它。

下面是我写的演示程序贴图 
 
 

 

演示程序在Win2003、.NET Framework 1.1环境下调试通过。演示程序下载