9 Answers, 1 is accepted
First, let me make the note that RadMap does not decide which items are added on ZoomLevel X and which are removed on ZoomLevel Y. Map just throws the mentioned MapItemReqest event handler and you decide what to include. Items outside viewport will be cleared at certain moment. To better specify how the event is called on changing zoom levels, you need to define ZoomLevelGridLists:
<
telerik:VisualizationLayer
x:Name
=
"visualizationLayer"
ItemTemplateSelector
=
"{StaticResource StoreTemplateSelector}"
VirtualizationSource
=
"{StaticResource MyVirtualizationSource}"
>
<
telerik:VisualizationLayer.ZoomLevelGridList
>
<
telerik:ZoomLevelGrid
MinZoom
=
"3"
/>
<
telerik:ZoomLevelGrid
MinZoom
=
"9"
/>
</
telerik:VisualizationLayer.ZoomLevelGridList
>
</
telerik:VisualizationLayer
>
For example with the following setup, starting at zoom level 3, MapItemRequest will be fired for the regions in the ViewPort. If you zoom on single point with no panning, the event will be fired when you reach zoom level 9 and won't be fired for zoom levels 4 5 6 7 8.
I hope this explanation could help you move forward in your scenario. On the other hand, I highly encourage you to upgrade to our latest official Release and check if the behavior you encountered is still reproducible.
Regards,
Petar Mladenov
Progress Telerik
Petar,
I found the problem, although I don't understand Telerik's code enough to know if this is a "bug" or if it's something in my app. All comments refer to the VisualizationLayer class.
Good app: When I change the zoom, UpdateVirtualItemsForZoom is called first. matrixIndex != this.lastRequestedIndex so ClearItems is called and all is well.
Bad app: When I change the zoom, UpdateThreadParameters is called first. lastRequestedIndex is updated to be matrixIndex. Then UpdateVirtualItemsForZoom is called. Now, matrixIndex = this.lastRequestedIndex, to ClearItems is not called and the layer contains the items from the previous zoom level.
Both apps are WinForms and the map control is hosted. The Map control is contained in a WPF DLL.
This seems a threading issue since UpdateThreadParameters is called by background threads via Dispatcher in order to execute the method on the main UI thread. For us it is of high importance to reproduce such issue locally in order to log it and investigate it further. Is there any chance you can isolate the the 'bad app' further and send it here ? Also, since the root project is Winforms, we need to say we have RadMap in our Win Forms components too so you can give it a try.
RadMap for Winforms Overview
Regards,
Petar Mladenov
Progress Telerik
Ok, I figured it out. When the zoom changes, I have to create a new tiled provider (unrelated to the visualization layer) because the data cannot be scaled and has to be redrawn each time. I need to know when the map finished rendering my new data, so I have this code:
System.Windows.Application.Current.Dispatcher.Invoke(New Action(AddressOf MapDrawFinished), System.Windows.Threading.DispatcherPriority.ContextIdle)
If I take that line out, everything works. If I change it BeginInvoke, it will also work. I'll see if I still need this or if using BeginInvoke is acceptable or if there is another alternative. Any ideas why this would cause problems?I am not sure what this MapDrawfFinished action / event does because it is part of your application / custom component. I guess you call it in MapItemRequest which is fired by background threads and your BeginInvoke invocation throws the action to the UI (Main UI Thread) which performs UI operation (hide/ move) of UI Elements. Again, as I am not sure if this answers your questions, please bring more details regarding your scenario if necessary. Thank you in advance.
Regards,
Petar Mladenov
Progress Telerik
HI Petar. Thanks for your patience. I currently have everything working. I just want to find out if the problem is due to my lack of experience with threading or if there's something different that RadMap could do, as I've spent countless hours on this.
I've attached a simplified sample (finally!). Change extension from gif to zip. It draws text with the following labels: 500, 1500, 2000. At zoom level 16, all labels should be visible. At zoom level 15, only 1000 should be visible. There are two calls to write "ZoomChanged" to the Console. If you use BeginInvoke, everything will work. If you use Invoke, it will not work. While it makes sense that BeginInvoke is correct, I don't understand why Invoke would break it. How to replicate:
- Start the app.
- Make the window tall enough that you can see at least two labels.
- Zoom out to level 15. At least 2 of the labels will be visible (incorrect). If you pan the map so that all the labels are outside of the window and then pan back, the map will now be correct.
I see the same issue if I call Windows.Forms.Application.DoEvents. I also see the same issue if I use the VisualizatinLayer's Dispatcher.
Thank you for your isolation. I managed to reproduce the difference in behavior when using Dispatcher with BeginInvoke or Invoke. Also I noticed when nothing is performed in ZoomChanged, the behavior seems correct. From what I debugged in our RadMap solution I think this is a very complex threading issue. The code which adds and removes objects in VisualizationLayer is executed in background threads and they siglal each other with ManualResetEvents. My best guess is that Dispatcher.Invoke breaks the sequence of signals or some background thread receives false signal. One is for sure, this is a problem in RadMap, not in your application.
Regards,
Petar Mladenov
Progress Telerik