动态加载的控件添加自定义事件的再次疑问,内详,在线等。

时间:2023-01-01 18:37:25
山次提问的帖子在这里
http://community.csdn.net/Expert/topic/5413/5413571.xml?temp=.5897638
现在的情况如下:
一个Assembly是动态添加到主窗体的。假设为名为assembly1,里面有一个form1。form1里面用如下代码添加了一个自定义事件:
        public delegate void del1(string[] files);
        public event del1 del1Event;
在主窗体上通过类似以下方法加载form1
Assembly ass = Assembly.LoadFrom(AppDomain.CurrentDomain.BaseDirectory + path + ".Dll");
UserControl obj = (UserControl)ass.CreateInstance(className);
obj.Name = "filmmanage1";
splitContainer2.Panel2.Controls.Add(obj);



现在的问题是。我如何添加del1Event这个事件。主要目的是传递files[]这个参数到主窗体。
尝试上个帖子的用
EventHandler del = new EventHandler(_filesEvent);
obj.GetType().GetEvent("del1Event").AddEventHandler(obj, del);
但是这方法似乎只能添加标准的事件格式。_filesEvent的参数只能是固定的,不能用files[]。请问如何解决?
谢谢。

14 个解决方案

#1


public class DeleteFilesEventArgs : EventArgs
{
    protected string[] delFiles;   
    public DeleteFilesEventArgs(string[] files){ this.delFiles = files;}

    public string[] Files{get{return delFiles}}

}

.....
public delegate void DeleteFilesHandler(object e,DeleteFilesEventArgs e)
public event del1 DeleteFilesHandler;

DeleteFilesHandlerdel = new DeleteFilesHandler(this,_filesEvent);
obj.GetType().GetEvent("del1Event").AddEventHandler(obj, del);

....

手写的,可能有错误.

#2


谢谢楼上的。
正在吸收。
有几点不明白。
DeleteFilesEventArgs 这个派生类要放在那里?是dll的项目中还是主项目中?还是都要引用这个类?
public event del1 DeleteFilesHandler;
这个事件声明什么意思?

#3


经过一番折腾。编译通过了。但是运行的时候提示:
Object of type xxx.NewMain+DeleteFilesHandler' cannot be converted to type xxx.PageP_01.FileManage+DelFiles'.

#4


我的操作步骤如下:
首先在主项目上添加一个派生类
DeleteFilesEventArgs 
在Main.cs中添加一个代理
public delegate void DeleteFilesHandler(string[] files);
然后整个加载dll的过程如下:
Assembly ass = Assembly.LoadFrom(AppDomain.CurrentDomain.BaseDirectory + path + ".Dll");
DeleteFilesHandler del = new DeleteFilesHandler( DelFileEvent);
UserControl obj = (UserControl)ass.CreateInstance(className);
obj.GetType().GetEvent("DelFileEvent").AddEventHandler(obj, del);

处理事件的方法如下:
void DelFileEvent(string[] _files)
{ }

#5


你这样的事件并不规范,最好遵循VS的事件规范.

public delegate void DeleteFilesHandler(object e,DeleteFilesEventArgs e)
public event DeleteFilesHandler del1;
....

Assembly ass = Assembly.LoadFrom(AppDomain.CurrentDomain.BaseDirectory + path + ".Dll");

DeleteFilesEventArgs eventArgs = new DeleteFilesEventArgs(DelFileEvent);//DelFileEvent 是要删除文件的数组吗?
UserControl obj = (UserControl)ass.CreateInstance(className);
if (obj != null) obj.GetType().GetEvent("Files_Deleting").AddEventHandler(obj,eventArgs);

处理事件的方法如下:
//void DelFileEvent(string[] _files)
private void Files_Deleting(object sender,DeleteFilesEventArgs e)

  string file = "";
  foreach(string file in e.Files)
  {
    MessageBox.Show(file);
  }
}

#6


发现有错误,更改:
public delegate void DeleteFilesHandler(object sender,DeleteFilesEventArgs e)
public event DeleteFilesHandler del1;
....

Assembly ass = Assembly.LoadFrom(AppDomain.CurrentDomain.BaseDirectory + path + ".Dll");
UserControl obj = (UserControl)ass.CreateInstance(className);

if (obj != null)

  DeleteFilesHandler deleteEvent = new DeleteFilesHandler(obj,new DeleteFilesHandler(...));//...为你要删除的文件数组(传入参数,如:new string[]{@"c:\test.txt",@"d:\bin\app.exe"})
  obj.GetType().GetEvent("Files_Deleting").AddEventHandler(obj,deleteEvent);

}
处理事件的方法如下(初始化时挂钩事件委托):
//void DelFileEvent(string[] _files)
private void Files_Deleting(object sender,DeleteFilesEventArgs e)

  string file = "";
  foreach(string file in e.Files)
  {
    MessageBox.Show(file);
  }
}

#7


3tzjq(永不言弃) ,非常感谢你的耐心回复。但是还是有如下问题不明白。希望能再次得到你的帮助。
public event DeleteFilesHandler del1; 整个代码中似乎没有用到这个声明的事件啊。


DeleteFilesHandler deleteEvent = new DeleteFilesHandler(obj,new DeleteFilesHandler(...));//...为你要删除的文件数组(传入参数,如:new string[]{@"c:\test.txt",@"d:\bin\app.exe"})

我主要的目的是让DLL通过事件来传递一个要删除的文件列表过来。这个时候我还不知道要删除什么。怎么传递new string[]{@"c:\test.txt",@"d:\bin\app.exe"})?


Files_Deleting 事件执行方法似乎没有看见那里调用了啊。迷惑中。

#8


我也迷惑中...
都没搞懂它们的关系了,你把DLL的代码发到我短消息,我再看看该怎么改.

#9


回复的确实有耐心,我要向你们学习

#10


3tzjq(永不言弃) 的确是好人。我整理一下发给你。稍等。难得会对一个问题一直关注。非常感谢。

#11


短信不能发太长。我就发在这里把。谢谢了。
项目1(dll项目)其中的一个cs文件。是一个usercontrol
public partial class FilmManage : UserControl
{
        public delegate void DelFilms(string[] files);
        public event DelFilms DelFilmEvent;

        //这里是某个按钮的处理函数
        private void toolStripButton6_Click(object sender, EventArgs e)
        {
            string[] files = new string{.....};//这个files是一个方法返回的,这里为了简化就直接new了
            DelFilmEvent(files);//这里是事件源(触发事件)
        }
}
以上项目单独编译出来一个dll.可以看作是一个插件。在主程序中是用反射加载的。没有直接用using 引用过来。

项目2(主项目)
更具您先前提供的信息目前的状态如下:
首先有一个类如下:
    public class DeleteFilesEventArgs : EventArgs
    {
        protected string[] delFiles;
        public string[] Files
        {
            get
            {
                return delFiles;
            }
        }
        
        public DeleteFilesEventArgs(string[] files)
        {
            this.delFiles = files;
        }

    }


然后在主窗体上

 public partial class NewMain : Form
{
public delegate void DeleteFilesHandler(object sender, DeleteFilesEventArgs e);

private void butten_Click(object sender, EventArgs e)
{
string path = Properties.Settings.Default.AddDAL;
string className = path + ".FilmManage";
Assembly ass = Assembly.LoadFrom(AppDomain.CurrentDomain.BaseDirectory + path + ".Dll");
UserControl obj = (UserControl)ass.CreateInstance(className);
//以上是动态加载这个dll中的FilmManage用户控件。
DeleteFilesHandler del = new DeleteFilesHandler( filmmanage1_DelFilmEvent);
obj.GetType().GetEvent("DelFilmEvent").AddEventHandler(obj, del);
//以上就是想要完成的,现在需要解决的问题。把FilmManage中的DelFilmEvent事件注册上。并且把Files传递过来。
splitContainer2.Panel2.Controls.Add(obj);
}

//事件处理函数就是要在这个函数里面处理filmmanage传递过来的参数
void filmmanage1_DelFilmEvent(object sender, DeleteFilesEventArgs e)
{
foreach (string str in e.Files)
{Debug.WriteLine(str);}
}


}


#12


那么这些代码:DeleteFilesEventArgs 类和
public delegate void DeleteFilesHandler(object sender,DeleteFilesEventArgs e)
public event DeleteFilesHandler del1;
应该放在DLL项目中.但它们是独立的,也就是说主项目也需要引用DeleteFilesEventArgs 类,所以,利用一个变通方法(事件参数object sender 传出文件数组):
DLL项目中:
public event EventHandler DelFilmEvent;//标准事件委托

private void toolStripButton6_Click(object sender, EventArgs e)
{
   //改用ArrayList
   //string[] files = new string{.....};//这个files是一个方法返回的,这里为了简化就直接new了
   ArrayList files = this.GetFiles();//GetFiles 为你的一个函数,需要更改返回类型为ArrayList

   if (DelFilmEvent != null) DelFilmEvent(files,EventArgs.Empty);//更用sender传数组
}

主项目更改(DeleteFilesEventArgs 类...可删除):
....
obj.GetType().GetEvent("DelFilmEvent").AddEventHandler(obj, new EventHandler(filmmanage1_DelFilmEvent));

void filmmanage1_DelFilmEvent(object arrFiles, EventArgs e)
{
  ArrayList files = (ArrayList)arrFiles;
  foreach (string file in files)
  {
    Console.WriteLine(file); //应该能得到传出的文件名  
  }
}

好好试试,应该可以!
}

#13


3tzjq(永不言弃)  呵呵。偶像。利用事件源来传递参数。真牛。问题解决了。。
艾。看来我要好好补一下事件模型了。谢谢你了。

#14


不用客气!互相学习

#1


public class DeleteFilesEventArgs : EventArgs
{
    protected string[] delFiles;   
    public DeleteFilesEventArgs(string[] files){ this.delFiles = files;}

    public string[] Files{get{return delFiles}}

}

.....
public delegate void DeleteFilesHandler(object e,DeleteFilesEventArgs e)
public event del1 DeleteFilesHandler;

DeleteFilesHandlerdel = new DeleteFilesHandler(this,_filesEvent);
obj.GetType().GetEvent("del1Event").AddEventHandler(obj, del);

....

手写的,可能有错误.

#2


谢谢楼上的。
正在吸收。
有几点不明白。
DeleteFilesEventArgs 这个派生类要放在那里?是dll的项目中还是主项目中?还是都要引用这个类?
public event del1 DeleteFilesHandler;
这个事件声明什么意思?

#3


经过一番折腾。编译通过了。但是运行的时候提示:
Object of type xxx.NewMain+DeleteFilesHandler' cannot be converted to type xxx.PageP_01.FileManage+DelFiles'.

#4


我的操作步骤如下:
首先在主项目上添加一个派生类
DeleteFilesEventArgs 
在Main.cs中添加一个代理
public delegate void DeleteFilesHandler(string[] files);
然后整个加载dll的过程如下:
Assembly ass = Assembly.LoadFrom(AppDomain.CurrentDomain.BaseDirectory + path + ".Dll");
DeleteFilesHandler del = new DeleteFilesHandler( DelFileEvent);
UserControl obj = (UserControl)ass.CreateInstance(className);
obj.GetType().GetEvent("DelFileEvent").AddEventHandler(obj, del);

处理事件的方法如下:
void DelFileEvent(string[] _files)
{ }

#5


你这样的事件并不规范,最好遵循VS的事件规范.

public delegate void DeleteFilesHandler(object e,DeleteFilesEventArgs e)
public event DeleteFilesHandler del1;
....

Assembly ass = Assembly.LoadFrom(AppDomain.CurrentDomain.BaseDirectory + path + ".Dll");

DeleteFilesEventArgs eventArgs = new DeleteFilesEventArgs(DelFileEvent);//DelFileEvent 是要删除文件的数组吗?
UserControl obj = (UserControl)ass.CreateInstance(className);
if (obj != null) obj.GetType().GetEvent("Files_Deleting").AddEventHandler(obj,eventArgs);

处理事件的方法如下:
//void DelFileEvent(string[] _files)
private void Files_Deleting(object sender,DeleteFilesEventArgs e)

  string file = "";
  foreach(string file in e.Files)
  {
    MessageBox.Show(file);
  }
}

#6


发现有错误,更改:
public delegate void DeleteFilesHandler(object sender,DeleteFilesEventArgs e)
public event DeleteFilesHandler del1;
....

Assembly ass = Assembly.LoadFrom(AppDomain.CurrentDomain.BaseDirectory + path + ".Dll");
UserControl obj = (UserControl)ass.CreateInstance(className);

if (obj != null)

  DeleteFilesHandler deleteEvent = new DeleteFilesHandler(obj,new DeleteFilesHandler(...));//...为你要删除的文件数组(传入参数,如:new string[]{@"c:\test.txt",@"d:\bin\app.exe"})
  obj.GetType().GetEvent("Files_Deleting").AddEventHandler(obj,deleteEvent);

}
处理事件的方法如下(初始化时挂钩事件委托):
//void DelFileEvent(string[] _files)
private void Files_Deleting(object sender,DeleteFilesEventArgs e)

  string file = "";
  foreach(string file in e.Files)
  {
    MessageBox.Show(file);
  }
}

#7


3tzjq(永不言弃) ,非常感谢你的耐心回复。但是还是有如下问题不明白。希望能再次得到你的帮助。
public event DeleteFilesHandler del1; 整个代码中似乎没有用到这个声明的事件啊。


DeleteFilesHandler deleteEvent = new DeleteFilesHandler(obj,new DeleteFilesHandler(...));//...为你要删除的文件数组(传入参数,如:new string[]{@"c:\test.txt",@"d:\bin\app.exe"})

我主要的目的是让DLL通过事件来传递一个要删除的文件列表过来。这个时候我还不知道要删除什么。怎么传递new string[]{@"c:\test.txt",@"d:\bin\app.exe"})?


Files_Deleting 事件执行方法似乎没有看见那里调用了啊。迷惑中。

#8


我也迷惑中...
都没搞懂它们的关系了,你把DLL的代码发到我短消息,我再看看该怎么改.

#9


回复的确实有耐心,我要向你们学习

#10


3tzjq(永不言弃) 的确是好人。我整理一下发给你。稍等。难得会对一个问题一直关注。非常感谢。

#11


短信不能发太长。我就发在这里把。谢谢了。
项目1(dll项目)其中的一个cs文件。是一个usercontrol
public partial class FilmManage : UserControl
{
        public delegate void DelFilms(string[] files);
        public event DelFilms DelFilmEvent;

        //这里是某个按钮的处理函数
        private void toolStripButton6_Click(object sender, EventArgs e)
        {
            string[] files = new string{.....};//这个files是一个方法返回的,这里为了简化就直接new了
            DelFilmEvent(files);//这里是事件源(触发事件)
        }
}
以上项目单独编译出来一个dll.可以看作是一个插件。在主程序中是用反射加载的。没有直接用using 引用过来。

项目2(主项目)
更具您先前提供的信息目前的状态如下:
首先有一个类如下:
    public class DeleteFilesEventArgs : EventArgs
    {
        protected string[] delFiles;
        public string[] Files
        {
            get
            {
                return delFiles;
            }
        }
        
        public DeleteFilesEventArgs(string[] files)
        {
            this.delFiles = files;
        }

    }


然后在主窗体上

 public partial class NewMain : Form
{
public delegate void DeleteFilesHandler(object sender, DeleteFilesEventArgs e);

private void butten_Click(object sender, EventArgs e)
{
string path = Properties.Settings.Default.AddDAL;
string className = path + ".FilmManage";
Assembly ass = Assembly.LoadFrom(AppDomain.CurrentDomain.BaseDirectory + path + ".Dll");
UserControl obj = (UserControl)ass.CreateInstance(className);
//以上是动态加载这个dll中的FilmManage用户控件。
DeleteFilesHandler del = new DeleteFilesHandler( filmmanage1_DelFilmEvent);
obj.GetType().GetEvent("DelFilmEvent").AddEventHandler(obj, del);
//以上就是想要完成的,现在需要解决的问题。把FilmManage中的DelFilmEvent事件注册上。并且把Files传递过来。
splitContainer2.Panel2.Controls.Add(obj);
}

//事件处理函数就是要在这个函数里面处理filmmanage传递过来的参数
void filmmanage1_DelFilmEvent(object sender, DeleteFilesEventArgs e)
{
foreach (string str in e.Files)
{Debug.WriteLine(str);}
}


}


#12


那么这些代码:DeleteFilesEventArgs 类和
public delegate void DeleteFilesHandler(object sender,DeleteFilesEventArgs e)
public event DeleteFilesHandler del1;
应该放在DLL项目中.但它们是独立的,也就是说主项目也需要引用DeleteFilesEventArgs 类,所以,利用一个变通方法(事件参数object sender 传出文件数组):
DLL项目中:
public event EventHandler DelFilmEvent;//标准事件委托

private void toolStripButton6_Click(object sender, EventArgs e)
{
   //改用ArrayList
   //string[] files = new string{.....};//这个files是一个方法返回的,这里为了简化就直接new了
   ArrayList files = this.GetFiles();//GetFiles 为你的一个函数,需要更改返回类型为ArrayList

   if (DelFilmEvent != null) DelFilmEvent(files,EventArgs.Empty);//更用sender传数组
}

主项目更改(DeleteFilesEventArgs 类...可删除):
....
obj.GetType().GetEvent("DelFilmEvent").AddEventHandler(obj, new EventHandler(filmmanage1_DelFilmEvent));

void filmmanage1_DelFilmEvent(object arrFiles, EventArgs e)
{
  ArrayList files = (ArrayList)arrFiles;
  foreach (string file in files)
  {
    Console.WriteLine(file); //应该能得到传出的文件名  
  }
}

好好试试,应该可以!
}

#13


3tzjq(永不言弃)  呵呵。偶像。利用事件源来传递参数。真牛。问题解决了。。
艾。看来我要好好补一下事件模型了。谢谢你了。

#14


不用客气!互相学习