"Animating" a MapPolyLine in Silverlight - c#

I need to animate a MapPolyLine such that on a given event, the start pin zips up to the end pin. The approach I am considerg is to animate frames such that I divide the MapPolyLine into n number of segments and decrease the TimeSpan ts between each frame along the logic of my chosing (to keep things simple, let's just say ts = ts / 2 after each cycle).
I know that one cannot animate the MapPolyLine, but one can change the appearance of the line by updating the latitude and longitude of the end position. My question concerns timing. My experience with multithreading is minimal, so I did not want to take the risk of a user running into a threading based error that may be difficult to diagnose. Should I:
use a simple DispatcherTimer and tick method
use a BackgroundWorker that reports progress every-time the TimeSpan has elapsed
use a dummy animation and attach an event handler to the rendering event
solution other than the above mentioned options?
Thank you in advance for your help!

Decided to use the DispatcherTimer considering the amount of time the animation is going to take - by creating a separate animation object that holds state and its own dispatch timer, it ended up being more efficient than using separate threads because the callback would mean interrupting the main UI thread and based on the requirements it was highly unlikely that there will be more than 2-3 of these animations occuring simultaneously with 95% or greater being only 1 animation at a time.

Related

Helix Viewport continues zooming while paused at a breakpoint

I am running a Helix viewport and am catching a mousewheeled event with previewmousewheel to run a method. When debugging some changes I made to my methods I found out that when I set a breakpoint (anywhere between the catching of the mousewheeledevent and the subsequent applying of the zoom in the viewport) the amount of zoom from one detent of the mousewheel will increase continuously in proportion to the amount of time the program has been paused (basically the amount of time elapsed from the mousewheeledevent and the applying of the delta to the viewport). This makes debugging my changes the way I normally do seem not possible, though of course I can work around this.
The real problem is that now I realize that the zoom is completely erratic in this way, because some operations take longer than others between the event and the setting of the viewport, depending on what I'm doing.
This seems like a completely haphazard thing to have going on when I'm trying to make changes to a camera and completely control the camera behavior based on details specific to my program.
Is there any way to disable this from happening or mitigate it almost entirely?
The following code is a snippet from my program that seems to be the main driver of the issue, but I'm not sure I can just remove this method of keeping time in the program, because we definitely need an asynchronous timekeeper as far as I know.
private async Task DoWorkAsyncInfiniteLoop()
{
while (true)
{
if (Run)
{
Time.timeElapsed += Time.runSpeed;
Time.simTime += Time.runSpeed;
updateAll();
}
// don't run again for at least 200 milliseconds
await Task.Delay(Time.interval);
}
}
perhaps there is some lines I can add that will basically allow me to apply the zoom to the viewport without waiting for the await Task.Delay(Time.interval) line to run?
I must admit I'm not too clear on how that code works, but I do know that it stops at the await Task.Delay line before finally i hit "step into" (F11) one more time and it somehow just applies the monstrous zoom that was not wanted, without my seeing any code after that being run.
Any workarounds?
Try to set IsInertiaEnabled = false on viewport

How to measure WPF Silverlight FPS or rendering time?

I have a control (for both WPF and Silverlight), represented data as bars. (Small chart). I want write an application, that measure performance of this control. I try to add points in cycle and wait while point will be rendered.
In WPF work this:
//start measuring time
for (int i =10, i<100, i++){
chart.AddRandomPoint(i); //i - argument
System.Windows.Forms.Application.DoEvents();
}
//finish measuring time
But in Silverlight it's impossible to use System.Windows.Forms.Application.DoEvents().
The second way is using DispatcherTimer:
dicpatcherTimer_Tick(object sender, EventArgs e){
chart.AddRandomPoint(i);
}
and subscribe to CompositionTarget.Rendering event. In event handler icrement counter.
Big value of this counter shows good performance.
My question is:
It is possible add point, wait while chart will be rendered, immediately add another one point etc.?
Is the second way (using DispatcherTimer object and CompositionTarget.Rendering event) correct. Can it shows performance? (I need to compare performance before and after refactoring).
Considering that you'are asking about WPF too, I would suggest to look at
WPF Performance Toolkit, especially think that Perforator will help you a lot with this.
Good article on WPF/Silverlight performance is A Critical Deep Dive into the WPF Rendering System

WP7 GeoCoordinateWatcher in the background

I'm wanted to wright a app which would alarm you when you are getting near a location.
I wanted to use the GeoCoordinateWatcher with PeriodicTask, but the test Task is invoked every 15min if i'm not mistaken. Can I somehow force the PeriodicTask to invoke more frequent? Or is there something else I can do to use the GeoCoordinateWatcher in the background which is not invasive for the UX. The app should work like for 2-3 hours and i like to update the location like every 5 minutes.
No, it's not possible for now. You only can run your application in foreground under lock screen to save battery life.
Register to the PositionChanged event of GeoCoordinateWatcher and set a low value of property MovementThreshold of GeoCoordinateWatcher to get the position changed events more frequently.
According to MSDN
This property specifies the minimum change in position that must take place
before the PositionChanged event is raised.
You could use a Timer to Start your Watcher every 5 minutes, just don't forget to Stop it too and so save the battery.

DispatcherTimer and UI refresh limits in C# silverlight

Again I apologize for a question that might be simple to all of you. I have a limited understanding of what goes behind the scenes in Silverlight.
I have a charting app (Visiblox) that I use as a rolling scope updated every 20ms, adding and removing a point. In pseudocode:
List<Point> datapoints= new List<Point>();
Series series = new Series(datapoints);
void timer_tick(){
datapoints.Add(new Point);
datapoints.RemoveAt(0);
// no need to refresh chart, it does refresh automatically
}
When running 6 series in this charting tool, it started to show a bit sluggish. Changing the tick to 10ms made no difference whatsoever, chart was updated at the same speed, so it seems that 20ms is the speed limit (UI or chart?).
I tried with CompositionTarget.Rendering and got the same results: below 20ms there was no difference in speed.
Then I accidentally enabled both and speed doubled. So I tested with multiple threads (2, 3, 4) and speed doubled, tripled and quadrupled. This has no locks yet, as I don't even know what process I need to generate a lock on, but got no data corruption nor memory leaks.
The question I have is why a sluggish chart at 20ms can not run at 10ms but is ridiculously fast when multithreaded? Is the UI refresh process being run faster? Is the chart computation doubled? Or is there a limit to how fast a single DispatcherTimer can be executed?
Thanks!
Edit: I have a background of embedded coding, so when I think of threads and timings, I immediately think of toggling a pin in hardware and hook up a scope to measure process lengths. I am new to threads in C# and there are no pins to hook up scopes. Is there a way to see thread timings graphically?
A DispatcherTimer, which fires its Tick event on the UI thread, is what's considered a low-resolution or low-accuracy timer because its Interval effectively means "tick no sooner than x since the last tick". If the UI thread is busy doing anything (processing input, refreshing the chart, etc.) then it will delay the timer's events. Furthermore, having a bunch of DispatcherTimer's ticking away on the UI thread at very low intervals will also slow down the responsiveness of your application because while the Tick event is being raised, the application can't respond to input.
So as you noted, in order to process data frequently, you should move to a background thread. But there are caveats. The fact that you aren't currently observing corruption or other bugs could be purely coincidental. If the list is being modified on a background thread at the same time the foreground thread is trying to read from it, you will eventually crash (if you're lucky) or see corrupt data.
In your example, you have a comment that says "no need to refresh chart, it does refresh automatically." This makes me wonder how does the chart know that you have changed the datapoints collection? List<T> does not raise events when it is modified. If you were using an ObservableCollection<T> I would point out that each time you remove/add a point you are potentially refreshing the chart, which could be slowing things down.
But if you are in fact using List<T> then there must be something else (perhaps another timer?) that is refreshing the chart. Maybe the chart control itself has a built-in auto-refresh mechanism?
In any event, the problem is a little bit tricky but not completely new. There are ways that you could maintain a collection on a background thread and bind to it from the UI thread. But the faster your UI refreshes, the more likely you'll be waiting for a background thread to release a lock.
One way to minimize this would be to use a LinkedList<T> instead of List<T>. Adding to the end of a LinkedList is O(1), so is removing an item. A List<T> needs to shift everything down by one when you remove an item from the beginning. By using LinkedList you can lock on it in the background thread(s) and you'll minimize the amount of time that you're holding the lock. On the UI thread you would also need to obtain the same lock and either copy the list out to an array or refresh the chart while the lock is held.
Another possible solution would be to buffer "chunks" of points on the background thread and post a batch of them to the UI thread with Dispatcher.BeginInvoke, where you could then safely update a collection.
The key here I think is to realise that Silverlight renders at a maximum frame rate of 60fps by default (customisable through your MaxFrameRate property). That means that the DispatcherTimer ticks will fire at most 60 times per second. Additionally, all the rendering work happens on the UI thread as well so the DispatcherTimer fires at the rate that the drawing is happening at best, as pointed out by the previous poster.
The result of what you're doing by adding three timers is just to fire the "add data" method 3 times per event loop rather than once, so it will look like your charts are going much faster but in fact the frame rate is roughly the same. You could get the same effect with a single DispatcherTimer and just add 3 times as much data on each Tick. You can verify this by hooking into the CompositionTarget.Rendering event and counting the frame rate there in parallel.
The ObservableCollection point made previously is a good one but in Visiblox there is a bit of magic to try and mitigate the effects of that so if you're adding data at a very fast rate the chart updates will be batched up at the rate of the render loop and unnecessary re-renders will be dropped.
Also regarding your point about being tied to the ObservableCollection implementation of IDataSeries, you are entirely free to implement the IDataSeries interface yourself, for example by backing it with a simple List. Just be aware that obviously if you do that the chart will no longer automatically update when data changes. You can force a chart update by calling Chart.Invalidate() or by changing a manually set axis range.

Simultaneous updates across two display contexts in openGL

I have a C# .NET application with which I've created a custom image display control. Each image display represents its own display context and draws the image using glDrawPixels (Yes I know it would be better to use textures, I plan to in the futures but this app is already too far along and my time is limited).
I am now trying to have both images pan simultaneously. That is, when one image is moved down ten pixels, the second image moves down ten pixels. Like so:
imageOne.YPan -= 10;
imageTwo.YPan -= 10;
imageOne.Invalidate(); //This forces a redraw.
imageTwo.Invalidate(); //This forces a redraw.
Alright so here is the problem I am having. Only one of the images displays is redrawing. If I place a pause in between the two Invalidate calls and make the pause duration at least 110 milliseconds both will redraw, but not simultaneously. So it looks as if the second image is always trying to catch up to the first. Plus, a 110 millisecond pause slows down the motion too much.
I have tried placing the updating and invalidating of each image in its own thread but this did not help.
At the beginning of drawing I make the appropriate context is current, and at the end I am calling swapbuffers(). I tried adding a glFinish to the end of the draw function, but there was no change.
Could it be that its the graphics card that is the problem? I am stuck using an integrated gpu that only has openGL 1.4.
Hopefully, I have provided enough detail that the answer to my problem can be found.
Its difficult telling what's wrong with what you do since you give so little detail. Here are some pointers which may help.
- before doing something in a context, make sure you make it the current one. If you want to pan two contexts, make the first one current, pan it and then make the second one current and pan it. These is no real reason why this should not work.
- If it looks like there is a timing problem, adding glFinish() at strategic places may help weed the problem out
- As should always be done, on occasions call glError() and see that everything went well.
- I'm not sure how this is done in the framework you're talking about but you should make sure that both contexts get a swapBuffers() call for every frame.
Invalidate doesn't force an immediate redraw. It marks the window invalid, and when the message queue runs out of other messages, a paint message will be created and processed. But that won't happen until you finish processing the current message and return to the main message loop, and it may be delayed even more than that.
Generally OpenGL animation is an exception to the rule of doing all drawing inside Control.OnPaint (or in a handler for the Control.Paint event).

Categories