I have written a plugin system that uses an interface and for any plugins that meet this contract are loaded at runtime into the main system.
The plugin effectively returns a TabPage that is slotted into the main app, and is controlled fromwithin the plugin dll.
If an error occurs within the plugin, the standard Windows error message shows. What I want to do it create an event that returns the error message so I can display it in the area I have reserved for text.
Do I need to keep a track of all attached plugin/interface instances to be able to set up an event to monitor each one?
At present, my system loops through the dll's within the app folder and those that meet the interface contract are loaded up, the actual instance of the interface is discarded each time as control is then handed over to the dll via button events that are loaded with the TabPage and handled within the plugin.
I hope this all makes sense.
You don't need to keep a reference to the plugin class, just add a delegate to the event when you start it up, after that you don't need the reference anymore.
You could add an event to your plugin contract:
public interface IPlugin
{
event EventHandler<ErrorEventArgs> Error;
void Initialise();
}
That way, any host can subscribe to that event when errors occur within the plugin:
public class MyPlugin : IPlugin
{
public event EventHandler<ErrorEventArgs> Error;
public void Initialise()
{
try
{
}
catch (Exception e)
{
OnError(new ErrorEventArgs(e));
}
}
protected void OnError(ErrorEventArgs e)
{
var ev = Error;
if (ev != null)
ev(this, e);
}
}
If I have followed you post correctly, this is how I would go about doing it.
In the plugin interface (Lets say IPlugin) you will need to declare an event.
public delegate void ShowErrorEventHandler(string errorMessage);
public interface IPlugin
{
event ShowErrorEventHandler ShowError;
}
Then when you load your plugins, for each one just subscribe to it's ShowError event, for example:
...
foreach(var plugin in plugins)
{
plugin.ShowError += MainForm_ShowError;
}
...
private void MainForm_ShowError(string errorMessage)
{
// Do something with the error... stick it in your reserved area
txtReservedArea.Text = errorMessage;
}
Hope this helps
Related
Is it at all possible to generate handlers for ALL events object has to offer in a similar way you can do it for a single event simply by pressing tab tab after += ?
if not Visual Studio, any other IDE that can do that ?
I have one way for you. Obviously, this solution will not meet your needs i 100%, but you can try it.
You can create an interface with all methods from a known object and inherit it. Now you can implement this interface. Unfortunately, you need to add an event handler to the constructor.
class myObject:IMyObject {
Public myObject() //this you have to add
{
this.my_Event += onMy_EventHandled();
this.my_Event1 += onMy_EventHandled1();
}
//this section will be create automatically
void onMy_EventHandled()
{
}
void onMy_EventHandled2()
{
}
}
e.g. interface
interface IMyObject {
void onMy_EventHandled();
void onMy_EventHandled();
}
My team is developing a Plugin project, in which Host application coordinates Plugins work (each Plugin has a specific function and will be executed on a seperate Thread). I'm writing Host application and define IPlugin interface; other people will develop Plugins.
The problem is: how to know when plugin completed or thrown exception. I have a solution is using event and delegate to let Plugins callback Host application, but I think this approach is not really good. Because if develop Plugin person implemented my IPlugin interface but forget writing raising event code.
In this case, the Plugin can be plug in my host application but my host application can not know when this Plugin completed or thrown exception or other communication, that's very bad.
My code likes this:
IPlugin.cs:
public delegate void OnFinishDelegate(IPlugin p, AMessageEventArgs e);
public delegate void OnExceptionDelegate(IPlugin p, AMessageEventArgs e);
public interface IPlugin
{
event OnFinishDelegate OnFinish;
event OnExceptionDelegate OnException;
void DoWork();
}
EventArgs:
public class AMessageEventArgs:EventArgs
{
private string message;
public string Message
{
get { return message; }
set { message = value; }
}
}
Host Application:
static void Main(string[] args)
{
// ...ignore load plugin code
//
IPlugin p = new Plugin();
// register event with IPlugin
p.OnFinish += new OnFinishDelegate(OnFinishHandler);
p.OnException += new OnExceptionDelegate(OnExceptionHandler);
// let plugin do its work on a subthread
Thread t = new Thread(p.DoWork);
t.Start();
// and then main continue do other work...
}
// if plugin throw exception, in the host application will
// handle this exception...
private static void OnExceptionHandler(IPlugin p, AMessageEventArgs e)
{
// in here will process exception of plugin...
}
// if plugin completed its work, it will use OnFinish event to
// notify to host application
private static void OnFinishHandler(IPlugin p,AMessageEventArgs e)
{
// in here will process completed work event
}
And I expect Plugin code will like below:
public class Plugin:IPlugin
{
// use event to callback host application
public event OnFinishDelegate OnFinish;
public event OnExceptionDelegate OnException;
// Create an EventArgs
AMessageEventArgs e = new AMessageEventArgs();
public void DoWork()
{
try
{
// execute update data
UpdateData();
}
catch (Exception ex)
{
e.Message = ex.Message;
// if have any exception, Plugin will raise an event in host application
// but if developer forget write below three lines of code, my host application will
// out of control.
if (OnException!=null)
{
OnException(this,e);
}
}
// if have no exception, Plugin will use OnFinish event to talk to host application
// to know that this plugin completed its work
// but if developer forget write below three lines of code, my host application will
// out of control.
if (OnFinish!=null)
{
OnFinish(this,e);
}
}
How to resolve this problem?
Additional problem: Did my IPlugin interface define well? if not well, can you advise me to improve this interface.
Thanks you!
I don't think the plugins need to know they're running in separate threads. I'd just have:
interface IPlugin {
void DoWork();
}
And then the host program would deal with catching exceptions and all the threading, something like:
Thread t = new Thread(() => {
try {
plugin.DoWork();
}
catch (Exception ex) {
// handle exception or save it to handle in the main thread
}
});
t.Start();
You've correctly identified the problem with the event model in the interface - when a plugin implements the IPlugin interface, they have to define the OnException event, but there is nothing requiring them to use it.
Define your IPlugin interface with a single DoWork method, and allow the standard exception pattern to report successful completion or an error status. If the DoWork method returns normally, the plugin is finished (no need for an OnFinish event). If DoWork throws an exception, your main application can catch the exception and deal with it (no need for an OnException event).
I would recommend looking into the Task Parallel Library for executing the plugins. It provides more control than using threads directly, including exception handling.
I've just read HeadFist Design pattern and discovered a solution: Factory Method.
In my case, I should use abstract class instead interface (IPlugin). In this abstract class, I define a Operate() method that will report result(completed result or exception result) to my host application. The second method is DoWork() method that the third party programmer can writing his function and don't care about OnComplete or OnException event.
My code like below:
Abstract class:
public delegate void OnFinishDelegate(APlugin p, AMessageEventArgs e);
public delegate void OnExceptionDelegate(APlugin p, AMessageEventArgs e);
public abstract class APlugin
{
public event OnFinishDelegate OnFinish;
public event OnExceptionDelegate OnException;
AMessageEventArgs e = new AMessageEventArgs();
public void Operate()
{
try
{
// implement plugin work
// we don't care how does the third party programmer write his Plugin program
DoWork();
// if DoWork() completed , it will raise an OnFinish event
// in my host application
e.Message = "Completed";
if (OnFinish != null)
{
OnFinish(this, e);
}
}
catch(Exception ex)
{
// if DoWork() throw exception, it will raise an OnException event
// in my host application
e.Message = ex.Message;
if (OnException!=null)
{
OnException(this,e);
}
}
}
// In here, the third party programmer will override this DoWork() method
private abstract void DoWork();
}
Host applicaton code:
static void Main(string[] args)
{
// ...ignore load plugin code
//
APlugin p = new Plugin();
// register event with IPlugin
p.OnFinish += new OnFinishDelegate(OnFinishHandler);
p.OnException += new OnExceptionDelegate(OnExceptionHandler);
// let plugin do its work on a subthread
Thread t = new Thread(p.Operate);
t.Start();
// and then main continue do other work...
}
// if plugin throw exception, in the host application will
// handle this exception...
private static void OnExceptionHandler(APlugin p, AMessageEventArgs e)
{
// in here will process exception of plugin...
}
// if plugin completed its work, it will use OnFinish event to
// notify to host application
private static void OnFinishHandler(APlugin p, AMessageEventArgs e)
{
// in here will process completed work event
}
>
And Plugin code (must like below):
class Plugin:APlugin
{
public override void DoWork()
{
// in here, the third party programmer can write anything
// for example: update data in database
UpdateData();
}
private void UpdateData()
{
// do update data
}
}
I'm writing a program that logs user idle time, however when I attempt to run the program it throws a Stack Overflow Exception.
These are my custom events
public void OnInactive(EventArgs e)
{
this.OnInactive(new EventArgs());
do
{
var idle2 = GetIdleTime();
GetIdleTime();
System.Diagnostics.Debug.WriteLine(idle2);
}
while (timer.Interval > 5000);
}
public void OnActive(EventArgs e)
{
this.OnActive(new EventArgs());
if (timer.Interval < 5000)
{
var idle3 = GetIdleTime();
System.Diagnostics.Debug.WriteLine(idle3);
}
}
I've breakpointed the code to try and locate the source of the issue, which appears to lie within this.OnInactive(new EventArgs());, However I'm pretty stumped on how to resolve this issue as I'm a beginner to Custom Events and haven't been coding in C# for long.
Any and all help with this issue would be greatly appreciated!
Thanks in Advance =]
Your handler method is calling itself immediately on entry:
this.OnInactive(new EventArgs());
this leads to a sequence of calls:
OnInactive -> OnInactive -> OnInactive -> ... ->
which will continue until you run out of stack space and the StackOverflowException is thrown by the runtime.
It's not clear what you're trying to achieve with the recursive call, but you should be able to just remove it.
You have the same issue in your OnActive handler.
EDIT: In response to the comments, it seems you're trying to raise the event itself at the beginning of your method. Assuming your event declaration looks like:
public event EventHandler InActive;
then you can raise it with:
EventHandler inactiveEvent = this.InActive;
if(inactiveEvent != null)
{
inactiveEvent(this, e);
}
and similarly for your Active event.
I gues you are trying to call the base method, but in fact you are now calling OnInactive when hitting OnInactive. This behaviour is recursive and will finaly stop due StackOverflow exception.
You can call the base function with base.<function name>.
For example:
class SpecialDerived : Base
{
public override void Say()
{
Console.WriteLine("Called from Special Derived.");
base.Say();
}
}
More info: http://msdn.microsoft.com/en-us/library/hfw7t1ce(v=vs.71).aspx
I think what you need is a bit more understanding about events. Let me explain the same through a sample code.
Class A{
public event OnInactive;
public event OnActive;
}
when any changes occur in classA you want to update things in ClassB. So you will implement events of class A in ClassB.
this link will describe you the same in detail.
My understanding says that there is no use of events when you are triggering it from the same class and listening in the same class.
these aren't event handlers, these are the methods that are going to
be called in order to raise the active and inactive events – Reece
Cottam
You need to actually call the event.
public class ReecesWatcher
{
public event EventHandler ActiveEvent;
public event EventHandler InactiveEvent;
protected virtual void OnInactive(EventArgs e)
{
// Fire the event using the () syntax. Fire it through
// a test variable so that we can reliabilty test for null,
// if there are no subscribers.
EventHandler inactiveEventTest = InactiveEvent;
if (inactiveEventTest != null)
{
inactiveEventTest(this, new EventArgs());
}
do
{
var idle2 = GetIdleTime();
GetIdleTime();
System.Diagnostics.Debug.WriteLine(idle2);
}
while (timer.Interval > 5000);
}
protected virtual void OnActive(EventArgs e)
{
// Fire the event using the () syntax. Fire it through
// a test variable so that we can reliabilty test for null,
// if there are no subscribers.
EventHandler activeEventTest = ActiveEvent;
if (activeEventTest != null)
{
activeEventTest(this, new EventArgs());
}
if (timer.Interval < 5000)
{
var idle3 = GetIdleTime();
System.Diagnostics.Debug.WriteLine(idle3);
}
}
// ... the rest of your class, where you call OnActive and OnInactive to
// cause the events to be fired.
}
I recommend not making your OnActive and OnInactive methods public, otherwise you're exposing too much of the implementation to the rest of your program. If you expect the class to be inherited from, then make them protected, otherwise I usually make them entirely private, since they're basically wrapper functions called by the rest of the class.
I have a UserControl on a Form,
when I MouseMove on that UserControl I want to do something in the Form.
How can I make the Form 'listen' for this event?
I am using Visual C#, .Net framework 3.5, winforms
I suppose you're referring to a use control or something like that.
You can add a public event, and trigger it inside your class when detecting the inner class event.
Then you have to subscribe to the published event in the second class.
This is a sample so that you see the sintax:
public class WithEvent
{
// this is the new published event
public EventHandler<EventArgs> NewMouseEvent;
// This handles the original mouse event of the inner class
public void OriginalEventhandler(object sender, EventArgs e)
{
// this raises the published event (if susbcribedby any handler)
if (NewMouseEvent != null)
{
NewMouseEvent(this, e);
}
}
}
public class Subscriber
{
public void Handler(object sender, EventArgs e)
{
// this is the second class handler
}
public void Subscribe()
{
WithEvent we = new WithEvent();
// This is how you subscribe the handler of the second class
we.NewMouseEvent += Handler;
}
}
If you are talking about Windows Forms (it's not clear from the question) you need to define
a new event in the class who recieves the mouse-event. After reciving it raises a new custom-event. Another class is subcribed to that (custom-event) a recieves notification.
For moe information (it's not something that can be presenteed in a couple of lines)
can have alook here:
How to propagate an Event up to the MainForm?
If you are talking about WPF, there are different concept of events: event routing. If your class is UI element present in UI tree of the component that recieves actually mouse-event, it will be propagated to your class too. So no need of more coding.
To expand a little on the answer from JotaBe, there are two scenarios that I could see you having:
a) class A calls a method in class B, and an exception happens. In this case, you don't need to do anything: exception will walk the stack, until it finds a catch statement. So, really, all you need to do is NOT catch an exception, or if you do need to catch it (for logging purposes and such), then rethrow it.
b) if you need to have a code triggered in some unrelated class, as a result of exception, then the best way is to use events. In your class declare:
public class ClassA
{
public static event EventHandler<Exception> OnException;
public void Notify(Exception ex)
{
if (OnException != null)
{
OnException(this, ex);
}
}
}
and then, in order to be notified, all you need is to
ClassA.OnException += (sender, exeption) =>
{
... some GetHashCode ..
};
... I guess JotaBe already added all necessary example code as I was typing
I have a question about events interception with c# and Postsharp.
I would like to cancel the execution of events like BeforeDropDown, RowSelected MouseClick with EventInterceptionAspect in postsharp.
But i can not find a proper place where i can write the code.
example:
i tried something like this:
[Serializable]
class EventInter : EventInterceptionAspect
{
public override bool CompileTimeValidate(System.Reflection.EventInfo targetEvent)
{
return "FormClosed".Equals(targetEvent.Name);
}
public override void OnInvokeHandler(EventInterceptionArgs args)
{
if condition executes method otherwise no
}
}
in the form:
[EventInter]
public partial class Frm_RomperMesa : KryptonForm
But it didn´t work. So i want to know if it is possible to achieve what i want.
Thanks in advace. I hope be clear.
yes, it is possible. The problem is, you're trying to apply an event interception aspect to an event defined in another assembly which you can't do within your code. You can't even override the event because it's setup to be handled using the base Form type in the designer code behind
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.Form1_FormClosing);
you will have to modify the assembly to do this. Use the following aspect and the links to modify your
public class EventAspectProvider : TypeLevelAspect , IAspectProvider
{
public IEnumerable<AspectInstance> ProvideAspects(object targetElement)
{
Type t = (Type)targetElement;
EventInfo e = t.GetEvents().First(c => c.Name.Equals("FormClosing"));
return new List<AspectInstance>() { new AspectInstance(e, new EventInter()) };
}
}
[Serializable]
public class EventInter : EventInterceptionAspect
{
public override void OnInvokeHandler(EventInterceptionArgs args)
{
int x = 0;
if (x > 0) //Do you logic here
{
args.ProceedInvokeHandler();
}
}
}
http://programmersunlimited.wordpress.com/2011/07/27/applying-aspects-to-3rd-party-assemblies-using-postsharp/
http://programmersunlimited.wordpress.com/2011/08/16/exposing-internal-methods-in-3rd-party-assemblies-for-external-use/
Basically it boils down to modifying the System.Windows.Forms.dll which I don't recommend. But if it's some other 3rd party vendor library, then go for it.
A workaround is to do it the other way around: Use an aspect on the method that is hooked to the event and cancel the normal execution of the method if the condition is met. This does not prevent the event form being raised but it prevents your event handling code from being executed.
[EventInter]
private void someForm_FormClosed(object sender, EventArg arg) {}
We use this approach a lot in our project. We have several aspects that apply to event handling methods (exception handling, cursors handling, etc...).
We go a little further, we apply the aspects at the assembly level and we use CompileTimeValide to recognize the signature of an event handling method. In theory, it's not 100% reliable, but we have not found any problems with this approach so far.