使用.NET事件模型通知文件拷贝进度

使用.NET事件模型的文件拷贝进度通知
本文介绍了一个使用.NET事件模型实现文件拷贝进度通知的应用案例。通过定义CopyReport类及其触发的StartCopy、Report和EndCopy事件,实现了文件拷贝过程中对外部进度指示的解耦。


         很久以前看precyboy Blog上的很长一篇文章,讲.NET事件模型的。文章深入浅出,让我受益匪浅,近日想到自己动手熟练熟练。
         于是准备模仿现有的代码写一个使用.NET事件模型通知文件拷贝进度的程序。
         程序效果截图:
            cx.JPG
 
         定义负责完成文件拷贝并报告进度的类CopyReport,该类的对象在完成文件拷贝任务时会触发三个事件,分别是StartCopy、CopyReport 、EndCopy。
        类视图:
        CopyReport%E7%B1%BB%E8%A7%86%E5%9B%BE.JPG
 
         这里对于初学者来说需要弄懂的“事件”“事件处理程序”的概念。pervyboy的文章解释的很好,这里我就引用他的解释吧:“在面向对象理论中,一个对象(类的实例)可以有属性(property,获取或设置对象的状态)、方法(method,对象可以做的动作)等成员外,还有事件(event)。所谓事件,是对象内部状态发生了某些变化、或者对象做某些动作时(或做之前、做之后),向外界发出的通知。打个比方就是,对象“张三”肚子疼了,然后他站在空地上大叫一声“我肚子疼了!”事件就是这个通知。
         那么,相对于对象内部发出的事件通知,外部环境可能需要应对某些事件的发生,而做出相应的反应。接着上面的比方,张三大叫一声之后,救护车来了把它接到医院(或者疯人院,呵呵,开个玩笑)。外界因应事件发生而做出的反应(具体到程序上,就是针对该事件而写的那些处理代码),称为事件处理程序(event handler)。
         事件处理程序必须和对象的事件挂钩后,才可能会被执行。否则,孤立的事件处理程序不会被执行。另一方面,对象发生事件时,并不一定要有相应的处理程序。就如张三大叫之后,外界环境没有做出任何反应。也就是说,对象的事件和外界对该对象的事件处理之间,并没有必然的联系,需要你去挂接。
         在开始学习之前,我希望大家首先区分“事件”和“事件处理程序”这两个概念。事件是隶属于对象(类)本身的,事件处理程序是外界代码针对对象的事件做出的反应。事件,是对象(类)的设计者、开发者应该完成的;事件处理程序是外界调用方需要完成的。简单的说,事件是“内”;事件处理程序是“外”。”
 
         使用 .NET 事件模型的设计解决了“高耦合”的问题,类CopyReport不会控制Form1的指示进度条,而是通过CopyReport类的事件通知,我们只要挂接我们写好的事件处理程序。这样就实现了进度的指示。

单播和多播
        如果某一事件被挂接多次,则后挂接的事件处理程序,将改写先挂接的事件处理程序。这里就涉及到一个概念,叫“单播事件”。
         所谓单播事件,就是对象(类)发出的事件通知,只能被外界的某一个事件处理程序处理,而不能被多个事件处理程序处理。也就是说,此事件只能被挂接一次,它只能“传播”到一个地方。相对的,就有“多播事件”,对象(类)发出的事件通知,可以同时被外界不同的事件处理程序处理。

CopyReport.cs

None.gifusing System;
None.gif
using System.Threading;
None.gif
using System.Collections;
None.gif
using System.IO;
None.gif
using System.Windows.Forms;
None.gif
None.gif
namespace Jacky.EventDelegateStudy.FileCopyReport
ExpandedBlockStart.gifContractedBlock.gif
dot.gif{
ExpandedSubBlockStart.gifContractedSubBlock.gif    
/**//// <summary>
InBlock.gif    
/// 文件拷贝进度报告
ExpandedSubBlockEnd.gif    
/// </summary>

InBlock.gif    public class CopyReport
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
ContractedSubBlock.gifExpandedSubBlockStart.gif        
"事件参数类"#region "事件参数类"
InBlock.gif        
public class StartCopyEventArgs:EventArgs
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
private DateTime startTime;
InBlock.gif            
public DateTime StartTime
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
ExpandedSubBlockStart.gifContractedSubBlock.gif                
getdot.gif{return startTime;}
ExpandedSubBlockEnd.gif            }

InBlock.gif            
public StartCopyEventArgs(DateTime time)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gif                
this.startTime = time;
ExpandedSubBlockEnd.gif            }

ExpandedSubBlockEnd.gif        }

InBlock.gif        
public class ReportEventArgs:EventArgs
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
private int rate;
InBlock.gif            
public int CopyRate
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
ExpandedSubBlockStart.gifContractedSubBlock.gif                
getdot.gifreturn rate;}
ExpandedSubBlockEnd.gif            }

InBlock.gif            
public ReportEventArgs(int r)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gif                
this.rate = r;
ExpandedSubBlockEnd.gif            }

ExpandedSubBlockEnd.gif        }

InBlock.gif        
public class EndCopyEventArgs:EventArgs
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
ExpandedSubBlockStart.gifContractedSubBlock.gif            
public EndCopyEventArgs()dot.gif{}
ExpandedSubBlockEnd.gif        }

ExpandedSubBlockEnd.gif        
#endregion

InBlock.gif
InBlock.gif        
//声明委托delegate
InBlock.gif
        public delegate void StartCopyEventHandler(object sender,StartCopyEventArgs e);
InBlock.gif        
public delegate void ReportEventHandler(object sender,ReportEventArgs e);
InBlock.gif        
public delegate void EndEventHandler(object sender,EndCopyEventArgs e);
InBlock.gif
InBlock.gif        
// 为每种事件生成一个唯一的键
InBlock.gif
        static readonly object StartCopyEventKey = new object();
InBlock.gif        
static readonly object ReportEventKey = new object();
InBlock.gif        
static readonly object EndEventKey = new object();
InBlock.gif
InBlock.gif        
// 为外部挂接的每一个事件处理程序,生成一个唯一的键
InBlock.gif
        private object EventHandlerKey
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
ExpandedSubBlockStart.gifContractedSubBlock.gif            
get dot.gifreturn new object(); }
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
// 为了支持“多播”,这里使用两个 Hashtable:
InBlock.gif        
// 一个记录 handlers,
InBlock.gif        
// 另一个记录这些 handler 分别对应的 event 类型
InBlock.gif        
//(event 的类型用各自不同的 eventKey 来表示)。
InBlock.gif        
// 两个 Hashtable 都使用 handlerKey 作为键。
InBlock.gif

ContractedSubBlock.gifExpandedSubBlockStart.gif        
"Hashtable存储事件类型和事件处理程序的操作"#region "Hashtable存储事件类型和事件处理程序的操作"
InBlock.gif        
// 使用 Hashtable 存储事件处理程序
InBlock.gif
        private Hashtable handlers = new Hashtable();
InBlock.gif        
// 另一个 Hashtable 存储这些 handler 对应的事件类型
InBlock.gif
        private Hashtable events = new Hashtable();
InBlock.gif        
protected void AddEventHandler(object eventKey, Delegate handler)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
// 注意添加时,首先取了一个 object 作为 handler 的 key,
InBlock.gif            
// 并分别作为两个 Hashtable 的键。
InBlock.gif
            lock(this)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gif                
object handlerKey = EventHandlerKey;
InBlock.gif                handlers.Add( handlerKey, handler );
InBlock.gif                events.Add( handlerKey, eventKey);
ExpandedSubBlockEnd.gif            }

ExpandedSubBlockEnd.gif        }

InBlock.gif        
protected void RemoveEventHandler(object eventKey, Delegate handler)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
// 移除时,遍历 events,对每一个符合 eventKey 的项,
InBlock.gif            
// 分别检查其在 handlers 中的对应项,
InBlock.gif            
// 如果两者都吻合,同时移除 events 和 handlers 中的对应项。
InBlock.gif
            lock(this)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gif                
foreach ( object handlerKey in events.Keys)
ExpandedSubBlockStart.gifContractedSubBlock.gif                
dot.gif{
InBlock.gif                    
if (events[ handlerKey ] == eventKey)
ExpandedSubBlockStart.gifContractedSubBlock.gif                    
dot.gif{
InBlock.gif                        
if ( (Delegate)handlers[ handlerKey ] == handler )
ExpandedSubBlockStart.gifContractedSubBlock.gif                        
dot.gif{
InBlock.gif                            handlers.Remove( handlers[ handlerKey ] );
InBlock.gif                            events.Remove( events[ handlerKey ] );
InBlock.gif                            
break;
ExpandedSubBlockEnd.gif                        }

ExpandedSubBlockEnd.gif                    }

ExpandedSubBlockEnd.gif                }

ExpandedSubBlockEnd.gif            }

ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
protected ArrayList GetEventHandlers(object eventKey)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            ArrayList t 
= new ArrayList();
InBlock.gif
InBlock.gif            
lock(this)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gif                
foreach ( object handlerKey in events.Keys )
ExpandedSubBlockStart.gifContractedSubBlock.gif                
dot.gif{
InBlock.gif                    
if ( events[ handlerKey ] == eventKey)
ExpandedSubBlockStart.gifContractedSubBlock.gif                    
dot.gif{
InBlock.gif                        t.Add( handlers[ handlerKey ] );
ExpandedSubBlockEnd.gif                    }

ExpandedSubBlockEnd.gif                }

ExpandedSubBlockEnd.gif            }

InBlock.gif
InBlock.gif            
return t;
ExpandedSubBlockEnd.gif        }

InBlock.gif
ExpandedSubBlockEnd.gif        
#endregion

InBlock.gif
InBlock.gif
ContractedSubBlock.gifExpandedSubBlockStart.gif        
"使用了 add 和 remove 访问器的事件声明"#region "使用了 add 和 remove 访问器的事件声明"
InBlock.gif        
public event StartCopyEventHandler StartCopy
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
ExpandedSubBlockStart.gifContractedSubBlock.gif            add
dot.gif{ AddEventHandler(StartCopyEventKey,value); }
ExpandedSubBlockStart.gifContractedSubBlock.gif            remove
dot.gif{ RemoveEventHandler(StartCopyEventKey,value); }
ExpandedSubBlockEnd.gif        }

InBlock.gif        
public event EventHandler EndCopy
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
ExpandedSubBlockStart.gifContractedSubBlock.gif            add
dot.gif{ AddEventHandler(EndEventKey,value); }
ExpandedSubBlockStart.gifContractedSubBlock.gif            remove
dot.gif{ RemoveEventHandler(EndEventKey,value); }
ExpandedSubBlockEnd.gif        }

InBlock.gif        
public event ReportEventHandler Report
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
ExpandedSubBlockStart.gifContractedSubBlock.gif            add
dot.gif{ AddEventHandler(ReportEventKey,value); }
ExpandedSubBlockStart.gifContractedSubBlock.gif            remove
dot.gif{ RemoveEventHandler(ReportEventKey,value); }
ExpandedSubBlockEnd.gif        }

ExpandedSubBlockEnd.gif        
#endregion

InBlock.gif
InBlock.gif
ContractedSubBlock.gifExpandedSubBlockStart.gif        
声明事件调用(虚)函数#region 声明事件调用(虚)函数
InBlock.gif        
protected virtual void OnStartCopy(StartCopyEventArgs e)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            ArrayList handlers 
= GetEventHandlers(StartCopyEventKey);
InBlock.gif            
foreach(StartCopyEventHandler sthandler in handlers)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gif                sthandler(
this,e);
ExpandedSubBlockEnd.gif            }
                
ExpandedSubBlockEnd.gif        }

InBlock.gif        
protected virtual void OnEndCopy(EndCopyEventArgs e)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            ArrayList handlers 
= GetEventHandlers(EndEventKey);
InBlock.gif            
foreach(EndEventHandler endhandler in handlers)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gif                endhandler(
this,e);
ExpandedSubBlockEnd.gif            }

ExpandedSubBlockEnd.gif        }

InBlock.gif        
protected virtual void OnReportCopy(ReportEventArgs e)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            ArrayList handlers 
= GetEventHandlers(ReportEventKey);
InBlock.gif            
foreach(ReportEventHandler rthandler in handlers)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gif                rthandler(
this,e);
ExpandedSubBlockEnd.gif            }

InBlock.gif
ExpandedSubBlockEnd.gif        }

ExpandedSubBlockEnd.gif        
#endregion

InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif        
public CopyReport()dot.gif{    }
InBlock.gif
InBlock.gif    
ExpandedSubBlockStart.gifContractedSubBlock.gif        
/**//// <summary>
InBlock.gif        
///  拷贝文件任务
InBlock.gif        
/// </summary>
InBlock.gif        
/// <param name="source">原文件路径字符串</param>
ExpandedSubBlockEnd.gif        
/// <param name="target">目标文件路径字符串</param>

InBlock.gif        public void ReportCopyRateTask(string source,string target)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            FileStream sFile 
= new FileStream(source,FileMode.Open,FileAccess.Read);
InBlock.gif            FileStream tFile 
= new FileStream(target,FileMode.OpenOrCreate, FileAccess.Write);
InBlock.gif
InBlock.gif            
int length = 1024;
InBlock.gif            
byte[] buffer = new byte[1025];
InBlock.gif            
int bytesread,totalread = 0;
InBlock.gif            
long filesize = sFile.Length;
InBlock.gif
InBlock.gif            
//触发事件,并传入该事件参数对应的参数对象
InBlock.gif
            OnStartCopy(new StartCopyEventArgs(DateTime.Now));
InBlock.gif
InBlock.gif            
while((bytesread = sFile.Read(buffer,0,length)) > 0)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{    
InBlock.gif                totalread
+=1024;
InBlock.gif                
double dfilesize = Convert.ToDouble(filesize);
InBlock.gif                
double drate = (totalread/dfilesize)*100;
InBlock.gif                
int rate = 0;
InBlock.gif                
if(drate<0)
InBlock.gif                    rate
=0;
InBlock.gif                
else
ExpandedSubBlockStart.gifContractedSubBlock.gif                
dot.gif{
InBlock.gif                    
string srate = drate.ToString();
InBlock.gif                    
string a = srate.Substring(0,srate.IndexOf('.'));
InBlock.gif                    rate 
= Convert.ToInt32(a);
ExpandedSubBlockEnd.gif                }

InBlock.gif
InBlock.gif                OnReportCopy(
new ReportEventArgs(rate));
InBlock.gif                
InBlock.gif                tFile.Write(buffer,
0,bytesread);
InBlock.gif                
InBlock.gif                Thread.Sleep(
1);
ExpandedSubBlockEnd.gif            }

InBlock.gif            
//关闭文件流
InBlock.gif
            sFile.Close();
InBlock.gif            tFile.Close();
InBlock.gif
InBlock.gif            OnEndCopy(
new EndCopyEventArgs());        
ExpandedSubBlockEnd.gif        }

InBlock.gif
ExpandedSubBlockEnd.gif    }

ExpandedBlockEnd.gif}

None.gif
None.gif

Form1的重要代码

None.gif        private void button1_Click(object sender, System.EventArgs e)
ExpandedBlockStart.gifContractedBlock.gif        
dot.gif{
InBlock.gif            
try
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gif                
//创建文件拷贝进度报告的对象
InBlock.gif
                CopyReport cp = new CopyReport();
InBlock.gif
InBlock.gif                
//将对象触发的事件与事件处理程序挂钩
InBlock.gif                
//这里我只挂接了两个Report和EndCopy两个事件
InBlock.gif
                cp.Report+=new Jacky.EventDelegateStudy.FileCopyReport.CopyReport.ReportEventHandler(cp_Report);
InBlock.gif                cp.EndCopy
+=new EventHandler(cp_EndCopy);
InBlock.gif
InBlock.gif                
this.Cursor = Cursors.WaitCursor;
InBlock.gif
InBlock.gif                
//做拷贝文件的任务,内部触发该对象的一些事件
InBlock.gif
                cp.ReportCopyRateTask(textBox1.Text.Trim(),textBox2.Text.Trim());
InBlock.gif                
InBlock.gif                
this.Cursor =Cursors.Default;
ExpandedSubBlockEnd.gif            }

InBlock.gif            
catch(Exception ee)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gif                MessageBox.Show(ee.Message);
ExpandedSubBlockEnd.gif            }

InBlock.gif
ExpandedBlockEnd.gif        }

None.gif
None.gif        
//挂接的事件处理函数
None.gif
        private void cp_Report(object sender, Jacky.EventDelegateStudy.FileCopyReport.CopyReport.ReportEventArgs e)
ExpandedBlockStart.gifContractedBlock.gif        
dot.gif{
InBlock.gif            
//设置进度条进度
InBlock.gif
            progressBar1.Value =e.CopyRate;
ExpandedBlockEnd.gif        }

None.gif
None.gif        
private void cp_EndCopy(object sender, EventArgs e)
ExpandedBlockStart.gifContractedBlock.gif        
dot.gif{
InBlock.gif            MessageBox.Show(
"文件拷贝成功完成!");
ExpandedBlockEnd.gif        }


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值