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.
Related
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. :)
I have been finding that “Windows Forms App (.NET Core)” projects lack the functionality of normal “.NET framework” apps. I'm specifically using .NET Core 3.1.
I want to be able to raise a form event on an object, but cannot find a way to do this. In my example, I want to call click on a System.Windows.Forms.TextBox. I know calling TextBox.Focus() will essentially emulate the behavior, but that's not the point.
Calling an event handler for the forms apps object does not do the job either. It only calls my custom code, not the actual base event handlers. And Control.RaiseEvent does not exist in .NET core. I don't think Control.Invoke can do the job either, but I haven't tested.
The answer is that control events are callable through subclassed controls. For example
public class TestPictureBox : PictureBox
{
public void CallClick(EventArgs e = null) => base.OnClick(e ?? EventArgs.Empty);
public void CallResize(EventArgs e = null) => base.OnResize(e ?? EventArgs.Empty);
}
With these example functions you can raise the control’s events.
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 am dynamically instantiating a Form. I cannot interact with the components (such as a TextBox) on the Form until the handle has been created (else, an exception will be thrown).
Currently I block the thread using a while loop:
public void OutputDesktopFrame(MessagingService service, DesktopFrame desktopFrame)
{
IRemoteDesktopView view = GetView(service);
view.UpdateFrame(desktopFrame);
}
private IRemoteDesktopView GetView(MessagingService service)
{
T view;
bool viewExists = _views.TryGetValue(service, out view);
if (viewExists == false)
{
view = CreateAndShowView(service);
}
return view;
}
private T CreateAndShowView(MessagingService service)
{
T remoteDesktopView = new T();
_views.Add(service, remoteDesktopView);
Thread pumpThread = new Thread(() => remoteDesktopView.ShowDialog());
pumpThread.Start();
while (remoteDesktopView.IsHandleCreated == false)
{
//Do not return until the handle has been created!
}
return remoteDesktopView;
}
I do not like this mechanism. I am looking for an elegant solution.
Please take into account that I am coding against an interface. I thought about using a ManualResetEvent or something of the like but having to implement and handle the ManualResetEvent within each Form that implements the interface doesn't sound appealing to me. If you don't agree with me. that's just fine. I merely suspect my current solutions are not the most elegant.
You can add code to a HandleCreated event handler like this:
private void Form1_HandleCreated(object sender, EventArgs e){
//your code
}
The event is not listed in Properties window, you have to register the event handler using code:
HandleCreated += Form1_HandleCreated;
You have to wait for the handle to be created somehow.
So you will end up with something like while (form.IsHandleCreated == false) { ... } somewhere in your code.
The only question is where to put it.
If you do it like in your example above, you need to code the while loop every time you create a form If you choose the alternative you mentioned, using an event raised by the form, you need to implement it in each form (and create an event handler and hook it up).
I don't know if CreateAndShowForm() is a framework method, or something you can change yourself. If you can change it, that's where I would put the waiting. That way you only need to code it once.
Another approach to avoid the code duplication would be handling it in the form, implementing it in your own abstract form base class, and deriving you actual forms from that class. In my opinion, that is complete overkill for this issue - way too much work for very little gain.
If you can't change CreateAndShowForm(), I recommend going with the example above - yes, it definitely isn't elegant, but it gets the work done, the source code is easy to understand, and it doesn't require the additional work of event handling.
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.