日期:2014-05-17  浏览次数:20745 次

C#中事件问题
自己定义了一个用户界面叫做UserControl1
UserControl1里面有一个button 叫做btn1
如果在一个别的地方引用UserControl1那么默认情况下btn1对他来说是私有的,也就是无法操作btn1的属性。
我想在不改变btn1为共有的情况下,怎样才可以为btn1的click事件赋值呢?
也就是说我在做UserControl1的时候还不知道btn的Click事件是什么。
当另一个Frame里面使用了UserControl1,可以根据具体的情况确定Click事件该是什么,这个时候怎么给btn1的Click事件赋值呢?
说的有点混乱,希望各位能听懂,不管方法简单复杂,能实现就好,前提是不将btn1改成public
C# 事件 公有私有 button

------解决方案--------------------
UserControl中:
public delegate void ButtonClickEventHandler(object sender, EventArgs e);
private static readonly object button_Click = new object();
public event ButtonClickEventHandler ButtonClick 
{
add
{
 Events.AddHandler(button_Click, value);
}
remove
{
 Events.RemoveHandler(button_Click, value);
}
}

外面调用:
userControl1.ButtonClick += new ButtonClickEventHandler(userControl_ButtonClick);
void userControl_ButtonClick(object sender, EventArgs e)
{
...
}

------解决方案--------------------
你封装的控件,它的这个业务行为不能去纠结于“永远使用btn1”。假如将来重构为使用TreeView的叶子结点点击事件呢?假如将来重构为鼠标滑动或者触摸屏手势呢?将来仅仅是一个通过互联网而调用远程功能呢(例如你的程序通过调用远程摄像头来判断某个事件需要通知)?将来可能有无穷无尽的重构可能。

关键地是设计的“层次”的问题。你封装控件的目的是对外暴露一个业务功能,而隐藏内部实现。如果你让外部的代码纠结于封装组件内部,那么就失去了封装的意义。这种低级的做法泛滥了,那么你就是为了时髦而封装,而不是为了真正去分层而封装了。

理解了基本的原则,技术上的实现就非常简单只是一些一次性的“见识”了。例如你的则个UserControl是一个“红黄绿灯”,它模拟交通的信号灯,而界面上用户可能按下三个按钮分别点亮三个灯(自然就同时关闭其它的的灯)。那么封装这个UsrControl,你不需要纠结于内部有几个btn或者Image,只要设计一个业务接口调用
public enum LightEnum
{
   红, 黄, 绿
}

public class LitEventArguments: EvetnArgs
{
    public LightEnum Light;
}

public event EventHandler<LitEventArguments> Lit;


然后这个UserControl要抛出“点亮红灯”事件那么只要写
Lit(this, new LitEventArguments{ Light= 红});


而从外部代码看来,根本不需要纠结于红灯是怎样实现的。实际上一个控件之所以好用,90%是靠不断重构的,甚至推到了重新设计内部实现。但是这个事件接口是不变的,因为它是业务逻辑接口,根本不是用来暴露什么btn1之类那种低级的东西用的。