I have a plugin that creates an object that has an event. Is there a way for a seperate class to monitor this event, even though it does not have control of the object?
For example, I have a plugin that calls an object that uploads some data. When the data is uploaded, the event is triggered to say that this is so. In my client app, I want this to be notified when this event triggers so that it can do something.
The plugin and client will be in C#, and the event class is written in VB.net.
Would it simply be a case of the object notifying the plugin, and in turn, the plugin notifying the client app?
Is this possible?
Thanks.
EDIT (in response to request for code):
The code is fairly simple, it will be a case of in the DLL:
Object O = new Object();
O.CompleteEvent += (BLAH BLAH);
O.Run();
Now when run completes, it will trigger the CompleteEvent.
I want it to be noticed that this event has triggered within a completely different assembly that does not have the O object. The new assembly can monitor the event, however it will be outside the scope of the O object. I hope i'm explaining this okay?
As mentioned earlier, would it simply be a case of the dll then notifying the client assembly that the run is complete?
Events can be static or instance, just like any other class members. And you can subscribe static and instance methods to either type.
Related
I have a Xamarin android application that has a main fragment activity (named Home) which hosts a view pager and then several fragments in the view pager.
The application gets data from a bluetooth device that passes the data via an event handler once I instantiate the class.
BTScanner scanner = new BTScanner();
scanner.onScanData += BTScanner_onScanData;
The issue is, I need this event handler to be active on two of the fragments in my view pager, when that page is active. In other words, I want to receive the scan data if I am on fragment1 or fragment2, However, I can't have it go to both at the same time, there is processing of the data received and the processing is different based on which fragment you are receiving the scan data in.
What I have so far is I created a custom interface on the activity and implemented it in the fragments. It will allow me to call a method on the fragments when the view pager switches pages. Based on these methods, I can de-init the event handler on one page and init it on the other. Here is an example on the fragment activity:
private void ViewPager_PageSelected(object sender, ViewPager.PageSelectedEventArgs e)
{
int position = (int)e.Position;
ICustomFragmentLifecycleForPager fragmentToResume = (ICustomFragmentLifecycleForPager)adapter.InstantiateItem(viewPager, position);
fragmentToResume.onResumePagerFragment(previousActiveFragment);
ICustomFragmentLifecycleForPager fragmentToPause = (ICustomFragmentLifecycleForPager)adapter.InstantiateItem(viewPager, previousActiveFragment);
fragmentToPause.onPausePagerFragment();
previousActiveFragment = position;
}
Therefore, with this, I have it working as needed because when I implement the interface on the fragments, I get onPausePagerFragment called on the fragment I can de-init, and an onResumePagerFragment on the fragment I can init.
All that said, the issue I am having is actually on first startup. On first startup, I am setting the fragment to show first and when I do that, the
ViewPager_PageSelected
is not called initially, thus not calling my custom interface methods to init or de-init the scanner.
One thing I tried already is to put a method call in the onCreate of the activity (also tried it in onStartup and onResume) that would in theory only be called one time when the application starts and would then check which fragment is active at startup and force the interface methods to fire appropriately. However, this feels clunky and is not working properly. In addition to not working properly, I am also getting null exceptions in the fragment, when the interface method does fire because I force it to in onCreate of the activity, the method that is called by the interface on the fragment, onResumePagerFragment, returns a null for the activity here:
var activity = (Home)Activity;
This worked before and continues to work in other places in the code so I suspect that this is happening because the activity has not fully started yet before the interface calls the method on the fragment and it attempts to get a reference to the activity. Again, I tried doing this in onResume and onStart on the activity but I still get a null.
With all that said, what is the best way in general to handle a scenario like mine where I have the main activity which starts but then is nothing more than a fragment/view pager container and I need to have one instance to the event handler active on a fragment at a time? Should I even need to do an interface or rather use a static class? If I use a static class, I know how to get the instance of the class on each but how do you then create the event handler AND make sure to un-register is as well when another fragment grabs the instance?
Thanks!
Mike
I could not show you C# code, but below my answer could give you a hint.
https://stackoverflow.com/a/30554102/361100
Note that Android natively provides EventBus and Xamarin I found is MessageBus component alternatively.
Secondly, you can make Service so that the service is act as a delegator of all data communication whenever events are fired.
In conclusion, we could think Fragment does not gurantee to give same fragment when it restored and especially it is garbage-collected at any time when it's used with ViewPager.
I have this code
List<DaSubscription> lstSubscription=new List<DaSubscription>();
for(int i=0;i<20;i++)//20 is just to simulate the behavior
{
DaSubscription Generic=new DaSubscription();
Generic.DataChanged += new DataChangedEventHandler(Generic_DataChanged);
lstSubscription.add(Generic);
}
//EVENT Handler which is raised from a 3rd party library [COM]
void Generic_DataChanged(DaSubscription aDaSubscription, DaItem[] items, ValueQT[] values, int[] results)
{
UpdateDataChangedDTO(items, values);
}
As the same event handler [m_daSubscription_Generic_DataChanged] is assigned to the multiple instance of same class [m_daSubscription]. Question i have is if at the same time multiple instances invokes this handler how will be handled here. will there will be any instance it shall overwrite the data. or the event handler will be separate for each instance.
The event handlers execute seperately. It sounds like your worried about the parameters being overwritten by another call to the handler. That won't happen (I don't think it is even possible). Since it doesn't look like you are accessing any shared objects in the event handler, you should be perfectly safe.
I have one WinForms control project that produces a dll. There is a second dll project (also winforms control) that uses the first project. There is a third winforms project, this time a form, that uses the second project. So [Third Project] <>------> [Second Project] <>--------> [First Project]
The first project exposes a static event. I'm trying to subscribe to that event from the third project. The event stays as null (not subscriptions) after the += call.
Why is it not subscribing? Is it because the Winforms controls have their own thread? The FirstProject user control is created on the fly at some point in time. But I will expect the static to work correctly, without doing anything else,
Project 1
namespace Something
{
public partial class FirstClass : UserControl
{
...
public delegate void EventHandler();
public static event EventHandler MyEvent;
...
}
}
Project 3
namespace Another
{
public partial class ThirdClass : Form
{
...
public ThirdClass()
{
....
Something.FirstClass.MyEvent += new Something.FirstClass.EventHandler(MyHandler);
}
public void MyHandler()
{
}
...
}
}
EDIT
I have created a small application with the basics to get the three projects and the static event. And it works. Therefore something else is going on.
EDIT 2
The dll that contained the first project, the one with the event, was being loaded twice. I have just added an alias, but didn't help. And still will not explain when just after the += the event is still null.
EDIT 3 I transformed the event so I have the add/remove accessors pair. It does enter into the add. The Handler method gets the value correctly (and therefore no null), but once it goes outside, is null again.
The static event should work just fine. Try to debug your code to make sure the event registration is being called and that the event itself gets fired as expected. The event does not care about threads. It will accept the registration either way. Threading will, however, cause an exception if you try to edit the form on a thread besides the UI thread.
And the reason will be in my EDIT 2. Because is a static event, loading twice the dll (two different paths) was creating two different static events (or two different handlers). My EDIT 3 clearly showed that the event was being subscribed to.
Once I forced the third project (the one subscribing to the static event) to load the dll from the same location as the project creating the event (I didn't wanted to use the GAC), all worked.
I'm trying to work with an old com control (a control array), the following samples: 5435293, 39541, 5497403, 5738092 explain (or at least what I understand) how to handle events of control arrays with .net controls, so they have Sender and EventArgs.
My question will be: How can you handle the events of an old com control array?.
EDIT:
The array will be created dynamically at the start, for example: Q. How many connections do you want? A. 5
example:
the control has this event: control_connected(int status, string description)
I can make some function with the same arguments and asign it to the connected event, but i cant figure out how to do it with a control array.
Ty so much for your help, and sorry about the crappy English... I'm not a navite English speaker
COM events have a different modal, you do not have one handler per event, you have an event sink object that hooks every event the COM server plan to raise. If you just hook the ActiveX events with delegates, event sink RCWs will be created and may cause crashes later, so I assume you are creating your own event sink class.
Since you have your own event sink class, you must follow the event publisher's event signature. The signatures do not have a sender argument, since the COM server assumes you have a reference to the sender, thus there is no need to send it again every time an event is raised.
You can, of cause, cache the server's reference in your event sink object for later use. Your event sink object can declare its own version of managed events with a sender parameter, and pass the cached COM server as the sender argument when it raises events.
Something like
[ComImport]
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
[TypeLibType(TypeLibTypeFlags.FHidden)]
[Guid("eventGuid")]
[CLSCompliant(false)]
public interface IEvent
{
[DispId(123)]
void control_connected(int status, string description);
}
public class EventSink:IEvent
{
object control;
public EventSink (object control)
{
this.control=control;
}
public event EventHandler<ControlConnectedEventArgs> ControlConnected;
void control_connected(int status, string description);
{
EventHandler<ControlConnectedEventArgs> temp=this.ControlConnected;
if(temp!=null)
temp(this.control, new ControlConnectedEventArgs(status,description));
}
}
If you have an array of COM servers, just declare an array of event sinks, attach each sink to each COM server with ConnectionPointCookie, and wire the event handlers from the event sink instead of the COM servers.
My app uses a logging class which is invoked by each module as it is constructed.
The logging class fires an event every time a new entry is added, so that the GUI can be updated.
Is there any way I can listen to events fired during the construction of an instance?
For instance, I currently have this in my calling class:
input = new Inputs.Webcam();
input.log.LogUpdate += new LogUpdateHandler(...);
But I also write to the log during the construction of the modules. (Currently this throws an error because there isn't a listener.) Is there any way to listen to these events?
This is completely impossible.
Instead, you can use a static event.
Could not you just pass the log handler method to the ctor?
var input = new Inputs.Webcam(new LogUpdateHandler(...));