TextCtrl.xaml
<Grid>
<StackPanel Orientation="Horizontal" VerticalAlignment="Center" HorizontalAlignment="Center" Height="68">
<Button Width="100" Margin="10" Content="清除" x:Name="btnClear"/>
<Button Width="100" Margin="10" Content="恢复" x:Name="btnRecall"/>
</StackPanel>
</Grid>
TextCtrl.xaml.cs
public partial class TextCtrl : UserControl
{
public TextCtrl()
{
InitializeComponent();
this.btnClear.Click +=this.clearClick;
this.btnRecall.Click += this.recalClick;
}
public event Action<string,string> clearEvent;
public event Action<string,string> recallEvent;
public Action clear_delegate;
public Action recall_delegate;
private void clearClick(object sender, RoutedEventArgs e)
{
if (clearEvent != null) { clearEvent("clear", "event"); }//没有Invoke()方法
if (clear_delegate != null) { clear_delegate.Invoke(); }//有Invoke()方法
}
private void recalClick(object sender, RoutedEventArgs e)
{
if (recallEvent != null) { recallEvent("recall","event"); }//没有Invoke()方法
if (recall_delegate != null) { recall_delegate.Invoke(); }//有Invoke()方法
}
}
MainWindow.xaml
<Grid>
<StackPanel Orientation="Vertical" >
<TextBox Width="200" Height="45" HorizontalAlignment="left" Margin="10" x:Name="txtBox" />
<local:TextCtrl HorizontalAlignment="Left" Margin="10 0 10 0" x:Name="textCtrl"/>
<TextBlock x:Name="txtBlock" Height="Auto" Width="Auto" Foreground="Red" FontSize="14"/>
</StackPanel>
</Grid>
MainWindwo.xaml.cs
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.textCtrl.clearEvent += TextCtrl_clearEvent;
this.textCtrl.recallEvent += TextCtrl_recallEvent;
// this.textCtrl.clearEvent += new Action<string,string> (TextCtrl_clearEvent);//也可以这么写
// this.textCtrl.recallEvent +=new Action<string,string>( TextCtrl_recallEvent);//也可以这么写
// this.textCtrl.clearEvent = TextCtrl_clearEvent; //报错
// this.textCtrl.recallEvent = TextCtrl_recallEvent; //报错
this.textCtrl.clear_delegate += textBlockClear;
this.textCtrl.recall_delegate += textBlockRecall;
// this.textCtrl.clear_delegate += new Action(textBlockClear);//也可以这么写
//this.textCtrl.recall_delegate += new Action(textBlockRecall);//也可以这么写
// this.textCtrl.clear_delegate = textBlockClear;//不报错
// this.textCtrl.recall_delegate = textBlockRecall;//不报错
}
private string text;
public string Text
{ get
{
return text;
}
set{
text = value;
}
}
private void TextCtrl_recallEvent(string arg1, string arg2)
{
txtBox.Text = Text;
}
private void TextCtrl_clearEvent(string arg1, string arg2)
{
Text = txtBox.Text;
txtBox.Clear();
}
private void textBlockClear()
{
txtBlock.Text = "Clear";
}
private void textBlockRecall()
{
txtBlock.Text = "Recall";
}
}
被event修饰后,可以在xaml上写这个自定义事件
<local:TextCtrl HorizontalAlignment="Left" Margin="10 0 10 0" x:Name="textCtrl" clearEvent="TextCtrl_clearEvent" recallEvent="TextCtrl_recallEvent"/>
运行效果:
讲解部分:
一、委托概念
1、概念:Delegate(委托、代理...):委托其实一种程序特性,它特的特点就在于,委托是用来表示方法的。换句话说委托是方法的代表、方法的指针。
int age=10;age其实就是10的代表。
Course myCourse = new Course(); myCourse是一个特定对象的代表。
委托类型 委托变量=具体方法(可以是1个,也可以是多个)。委托就方法的变量。
2、为什么要使用委托?
生活中想象一下,比如我们做一件事情,但是我们自己无法直接去完成。但是我们通过别人可以帮我们完成。
我--->其他人(委托)--->做事情
通过刚才的比较,我们发现,前面age、myCourse等代表的都是某种“静态数据”。
委托代表的是“行为”,就是方法。
软件开发中,我们也会遇到类似情况,那就是我们本身想调用一个行为(方法)但是这个方法因为再不同的对象中,
我们可能直接调用不了,这时候就可以使用委托。
正常情况下:A对象中,创建了B对象,这时候,如果B对象中有一个公共行为C,那么我们在A中是能调用的。
class A
{
B b=new B();
void MyMethod()
{
b.C();
}
void NewMethod(){}
}
问题:如果B想调用A中的行为NewMethod是否可以?当然不行!但是通过委托是可以的。
二、委托的基本使用
1. 声明委托(定义方法的原型:方法的返回值类型、方法的参数类型和个数)
2.根据委托编写具体方法
3. 创建委托变量(委托是引用类型)
4. 将委托变量和一个或多个符合委托定义的具体的方法关联。
5. 通过委托变量使用具体的方法(不是直接使用方法)
结论:通过委托变量,可以轻松的调用它所关联的具体方法。
扩展:如果我们给委托变量,同时关联了多个方法,当我们使用委托变量的时候,方法会按照你关联的顺序依次调用。
以上就是我们常说的“多路委托或叫做多播委托”。
好处:我们不仅能动态的增加委托对方法的关联,还可以动态的移除方法的关联。
三、委托的实战应用(一):在多窗体通信中的使用
1、在主窗体A中,创建了若干子窗体B的对象。
现在B窗体需要调用A中的一个方法。正常情况是不行的。但是可以通过委托实现。
2、提示:我们使用委托完成任务的时候,委托变量在哪里定义的技巧是:在哪里使用,就在哪里定义!(谁使用谁创建)
委托变量和具体方法的关联,通常是分开的。一般就是在具体方法定义的地方,进行关联。
总结: B1->A B2->A B3->A
扩展:通过委托如何实现消息的广播?
在哪里接收消息,就把接收消息的方法写到哪里!这里是B窗体。
四、委托的实战应用(二):解决在容器嵌入窗体时的切换问题
五、事件Event(和委托比较)
随便找一个: this.btnCreateChildForm.Click += new System.EventHandler(this.btnCreateChildForm_Click);
public event EventHandler Click
public delegate void EventHandler(object sender, EventArgs e);
通过观察按钮的事件,发现了事件其实是委托的进一步包装。
定义事件:(直接看代码)案例中,我们实现和前面一样的功能,但是这次通过事件来实现。
事件概念:事件其实是对象对外界信息的刺激,产生的一种消息响应机制。
本质:事件其实是委托的进一步包装。
事件的参与者:
【1】发送者(sender):就是对象本身,当时本身信息状态变化的时候,触发一个事件,并通知所有的接受者接收。
passMsgEvent(this.txtSendMsg.Text, this.Text);
【2】接受者(Receiver):就是事件的处理者,在事件发送者触发后,会自动执行的这段代码。
private void ReceiveMsg(string msg, string childName)
{
this.txtContent.Text += $"来自:{childName} 的消息:{msg}\r\n";
}
事件和委托对比不同点:
第一、事件无法直接赋值,比如事件=null;会出现编译错误,而委托可以。
好处:避免用户对事件直接操作,比如Click事件,如果允许Click=null,会把底层代码清除!可以起到保护。
委托相对太“开放”。
第二、event对象没有invoke()方法,只能通过使用括号的方式来运行。
委托和事件的选择:
第一、正常解决问题,你使用委托和事件没有什么本质区别。所以,我们建议是使用委托。
第二、如果我们做控件二次开发,扩展控件的事件的时候,那必须用事件。