Ok so I am aware there are some similar questions such as:
Adding and Removing Anonymous Event Handler
Unsubscribe anonymous method in C#
But I don't understand the concept of delegates.
I am starting to use the Plugin.BLE in a .Net Maui app.
The scanning operation is started from a button and then either times out (by use of a Timer) or is stopped by pressing the button again.
However in my button command (MVVM) I have the following snippet of code:
...
adapter.DeviceDiscovered += (s, a) =>
{
if (a.Device.Name != null && a.Device.Name != String.Empty)
{
...
}
};
await adapter.StartScanningForDevicesAsync();
...
I note that each time I hit the button I get two more discovered items (I'm not sure why I'm getting 2 yet?) (This is from Pixel 5 emulator)
This makes some kind of sense as I am adding another event to the same adapter!
So I need to convert the anonymous function
adapter.DeviceDiscovered += (s, a) =>
{
}
into a non anonymous function, so that I can add the handler and then remove it when the timer stops or I stop the function.
I have no idea how to go about this, especially in dealing with the s and the a.
I'd be grateful for any pointers, code.
Thanks, G.
Edit: link to Plguin.BLE https://github.com/xabre/xamarin-bluetooth-le
Well, I am truly astonished by Visual Studio.
After hacking away for a while trying to create functions and delegates I commented out the code and typed in
adapter.DeviceDiscovered +=
and visual studio created the rest of the code and the event handler for me.
So I have:
adapter.DeviceDiscovered += Adapter_DeviceDiscovered;
...
private void Adapter_DeviceDiscovered(object s, Plugin.BLE.Abstractions.EventArgs.DeviceEventArgs a)
{
Debug.WriteLine("Got here");
}
I changed the original sender to s and the original e to a to match the code I was using.
Well so far it seems to work.
Now all I need to do is figure out why this is getting called twice! :sigh. :)
Related
I'm currently building an application for iOS and Android using Xamarin and MonoTouch. In the application there is going to be a lot of data loaded from JSON, and therefore I wanted to incorporate a unified loader, an object that runs on application start to check whether it needs to re-download information or not.
The loading class is done and is fully functional, and has the following methods that I want to be able to bind events to. See below:
BeginLoading
ReloadPosts
ReloadLayers
ReloadRunners
FinishedLoading
These are all self contained and run in the loader class which I initiate in ViewDidLoad in my main screen (MainScreen.cs) using the following code:
var loader = new UnifiedLoader();
This starts the process of checking the local cache, last reload time etc and either starts the reloading process - posts, layers, runners or jumps straight to FinishedLoading.
What I'd like to be able to do is to listen for these "events" in some fashion, and I have no idea how to go about doing so. Please look below for an example.
var loader = new UnifiedLoader();
loader.LoadingDidBegin += () => {
Console.Out.WriteLine("Loading started");
// Display spinner or something...
};
loader.DidReloadPosts += () => {
Console.Out.WriteLine("Posts were reloaded");
// Update reloading percentage, show user...
};
loader.DidReloadLayers += () => {
Console.Out.WriteLine("Layers were reloaded");
// Update reloading percentage, show user...
};
loader.DidReloadRunners += () => {
Console.Out.WriteLine("Runners were reloaded");
// Update reloading percentage, show user...
};
loader.LoadingDidFinish += () => {
Console.Out.WriteLine("Loading finished");
// Remove spinner, proceed...
};
As of now I have no idea how I would go about implementing these events in the loading class. I've been searching and going through the API documentation but found nothing to aid me.
I would be more than thankful if someone could help me solve this.
Thanks in advance,
Jonathan
The preferred way would be to just write:
public EventHandler LoadingDidBegin;
This saves you from declaring the delegates and conforms to coding guidelines: http://msdn.microsoft.com/en-us/library/w369ty8x.aspx
I solved it by finding the Microsoft documentation for C# events. It was as simple as using the following code to register the event delegates and events.
This code goes outside of the class:
public delegate void LoadingDidBegin();
And this code goes inside the class:
public event LoadingDidBegin LoadingDidBegin;
And in the method where you want to invoke the event, call this:
// Trigger event:
if (this.CheckingDidBegin != null){
this.CheckingDidBegin ();
}
And last, in the class where you bind the event, bind the delegate like this:
var loader = new UnifiedLoader ();
loader.LoadingDidBegin += delegate {
// Do something here, show a HUD for instance...
};
loader.InitiateLoader ();
That's pretty much it, just remember to register the delegates before initiating the methods that carry the event triggers, otherwise they will just return null and you will get no feedback.
Good luck!
I have a program with the following design
A couple of separate classes, each implementing one type of
algorithm
A windows form interface for providing input to run
different algorithms AND Speech Commands to do exactly the same.
Each algorithm is run by clicking a separate
button
Each algorithm raises some events (specific to the algorithms)
The event listeners in turn outputs through
The labels on the form AND through the speech API, speaks the results using speakers
The problem I am facing is that while debugging, if something goes wrong in one algorithm, other algorithms get initiated automatically sometimes. I want to be able to know what event listeners are registered with some event if any, at any point in time. I am using VS2008 with C#.
I also want to know if we use a Timer as a local variable and add an event listener to that timer in each class. Is is possible that the timer of one class triggers the listeners in other classes. I am new to this event listeners stuff, and not sure if I am missing some basic information that led me asking this question or its a problem with some ground.
i would suggest you get basics of debugging, i think this is all that you need for now. Here is a tutorial to basics of debugging. Get yourself familiar with F10 and F11 keys. by using breakpoints you can get the execution sequence of your algorithms.
2nd it is possible to that the timer of one class triggers the listeners in other classes Here is an example.
MyClass myClass = new MyClass();
Timer timer1 = new Timer();
timer1.Tick += myClass.TimerCallback; // subscribe to other's class method
timer1.Interval = 1000;
timer1.Start();
public class MyClass
{
public void TimerCallback(object sender, EventArgs eventArgs)
{
Console.WriteLine("Timer Called by: " + sender);
}
}
if you want to get list of callbacks subscribe to your callback use this answer, but i think you dont need that for now if you get use to debugging.
I'm working on a Windows Service that where I am attempting to use Parallel.ForEach to spawn unique timed threads. The problem is that if I leave the code alone for several hours in VS or if I stop the service for a few hours and start anything back up - the initial start up code executes twice. Here is a snippet from the static void that the service's OnStart is calling.
Parallel.ForEach(urls, url =>
{
PageGrabber pagegrab = new PageGrabber(url);
if (url.Type.ToLower() == "http")
{
pagegrab.Elapsed += (obj, e) =>
{
pagegrab.CheckNormal();
};
pagegrab.CheckNormal();
}
else
{
pagegrab.Elapsed += (obj, e) =>
{
pagegrab.CheckXML();
};
pagegrab.CheckXML();
}
}
);
This works great if I use Threads directly, but really wanted to update this code a bit. The duplicate execution happens immediately. The PageGrabber object is pretty simple in that it simply uses a WebClient to download either HTML or XML as a string - pretty boring.
I think the problem is that you've subscribed to the Elapsed event by pageGrabber.Elapsed +=...
It is possible for that event to be raised or not.
So in some conditions if the event raised, your method will be called twice, otherwise it will be called once.
I don't think that you could resolve this problem by changing the parallel implementation (using task array instead of Parallel.Foreach). It just might cause the problem occur less often, which is a very bad symptom in parallel programming. You shouldn't let the problems to fade out by making their preconditions of happening harder! You should totally remove them!
So mehrandvd was on the right path. When creating an instance of my class, that used a System.Timers.Timer, it was firing the Elapsed event immediately because the Interval property wasn't being set correctly. Thus:
pagegrab.Elapsed += (obj, e) =>
{
pagegrab.CheckXML();
};
pagegrab.CheckXML();
Caused duplicate execution when nothing had happened in a while because the instance of the class that had the Interval set correctly was no longer in memory. My stupidity - all fixed now. Thanks for all the comments and suggestions.
I have a Silverlight app that utilizes the Bing Maps control. Data loads when ever the maps view stops changing. I saw an example where someone used the ASP.Net version of the control and was able to acheive this. Is this same thing possible in Silverlight?
Microsoft.Maps.Events.addThrottledHandler(map, 'viewchangeend', UpdatePOIData, 250);
rx (unless Im behind) is not yet built into silverlight and seems a little overkill to have the client download all the rx dll just for throttling unless you are going to use it extensively.
At its simplest create your own throttling class using a dispatchtimer which takes the initial call waits x seconds and then checks if another call has come in since before executing your action.
Sorry I dont have any code to hand
You could do it with Reactive Extensions. The Throttle method exists for this purpose:
var observable =
Observable.FromEventPattern<MapEventArgs>(
handler => map.ViewChangeEnd += handler,
handler => map.ViewChangeEnd -= handler);
observable.Throttle(TimeSpan.FromSeconds(1))
.Subscribe(ev => map_ViewChangeEnd(ev.Sender, ev.EventArgs));
...
void map_ViewChangeEnd(object sender, MapEventArgs e)
{
...
}
(untested)
To get around the Invalid cross-thread access ( UnauthorizedAccessExcecption) while using Subscribe function error you'll get using this code.
Use the following:
using System.Reactive.Concurrency;
using System.Reactive.Linq;
var observable = Observable.FromEventPattern<MapEventArgs>(
handler => MyMap.ViewChangeEnd += handler,
handler => MyMap.ViewChangeEnd -= handler);
observable.Throttle(TimeSpan.FromSeconds(2)).ObserveOn(DispatcherScheduler.Current).Subscribe(ev => MyMap_ViewChangeEnd(ev.Sender, ev.EventArgs));
You have to add the ObserveOn(DispatcherScheduler.Current) to make it work. And add references for System.Reactive.Core, System.Reactive.Interfaces, System.Reactive.Linq and System.Reactive.Windows.Threading.
I am maintaining some code which has two FileSystemWatcher events that makes it difficult to debug (and it has an error). So my idea is to simplify the code by making the execution sequential. Pretty much like this:
Main method
1) normal code here
2) enable event 1, let it check for files, disable it when it is done running once
3) enable event 2, let it check for files, disable it when it is done running once
Then the database logs would make more sense. I would be able to see which part of the program that is doing something wrong.
private void InitializeFileSystemWatcher()
{
this.MessageMonitor = new FileSystemWatcher(this.MessagePath, this.MessageFilter);
this.MessageMonitor.IncludeSubdirectories = true; // Recursive.
this.MessageMonitor.Created += new FileSystemEventHandler(OnMessageReceived);
this.MessageMonitor.EnableRaisingEvents = true;
}
From the main, I can set the EnableRaisingEvents=true to EnableRaisingEvents=false. Both events indexes the files in some folder and enacts a callback method.
My question is this: If the event is currently executing and I set EnableRaisingEvents=false, will it pause or continue to execute until it finishes?
If it does continue, I figure just to have a bool doRUN variable set at beginning and the end of the event as a check for the main method.
You should just detach the event handler after you check to make sure that it is working properly and then instantiate the second FileSystemWatcher.
Inside of the OnMessageReceived you could od something like
public void OnMessageRecieved(Object sender, Events e) //Not the real signature
{
MessageMonitor.Created -= OnMessageReceived();
//Do Your things
OtherMessageMonitor.Created += OnMessageReceived();
}