I'm trying to work with Bing Maps in WPF, but everything is confusing as searching online leads me to false hope. I'll search for something, but get the AJAX version instead of the WPF version. If anyone can point me to proper documentation or help with this issue then I will be forever in their debt.
I have a map in my WPF app that I would like to track when a user is scrolling. I tried tying the map to the DragEnter event, but that didn't do anything. My question is if there is an event that I can use to check if the user is panning or zooming through the map?
Thanks in advance.
The event ViewChangeOnFrame seems to do what you want.
See Handing Map Events
<m:Map ViewChangeOnFrame="MyMap_ViewChangeOnFrame" ...>
From MSDN
Assuming you have a TextBlock element named CurrentPosition defined in
the XAML design code, you can track the current position of a map view
while it is animating between locations. This code tracks the
position, in latitude and longitude, of the northwest and southeast
corners of the bounded map view.
void MyMap_ViewChangeOnFrame(object sender, MapEventArgs e)
{
//Gets the map that raised this event
Map map = (Map) sender;
//Gets the bounded rectangle for the current frame
LocationRect bounds = map.BoundingRectangle;
//Update the current latitude and longitude
CurrentPosition.Text += String.Format("Northwest: {0:F5}, Southeast: {1:F5} (Current)",
bounds.Northwest, bounds.Southeast);
}
Related
I am a bit stuck in my current project.
I'm using a terrible API that needs to be told where and when to draw at any give time. This API does not expose any controls, and I need a control in order to place the drawn object properly.
What I have done is I've put a canvas in my grid in my view. This canvas takes up the space that my drawn API element needs to take up. So, by getting the canvas actualwidth and actualheight, I can draw my API element at the proper size. The issue i'm having is the position of the API element. The Canvas is in the proper place at all times, but when the program first starts, Canvas.TranslatePoint(new System.Windows.Point(0, 0), App.Current.MainWindow); returns 0,0. As soon as I manipulate the UI and cause the Canvas to Resize, the location function returns the real location and my API element draws in the proper spot. My question is why is the initial location 0? How can I remedy this? I call the initial draw function from the UserControl_Loaded event.
Thanks
P.S. Would I be wrong in thinking that the initial 0,0 is a relative coordinate, and not an absolute coordinate?
I figured out my issue - my control wasn't part of the PresentationSource. Long story short, you can't get the location of a control that isn't shown on the screen yet. My fix was this:
private void WaveformCanvas_Loaded(object sender, RoutedEventArgs e){
if((sender as Canvas).IsVisible)
{
(this.DataContext as StudioControlViewModel).MoveWaveform();
}
}
For me, the MoveWaveform() function calls WaveformCanvas.TranslatePoint(new System.Windows.Point(0, 0), App.Current.MainWindow);
So now the function only gets called when the control is visible, which has solved all of my issues.
using iOS 6 MapKit, I would like to define an MKAnnotation (such as a pin, or a custom one) that remains fixed on the center of the map view as the user moves the map around. Once the user stops moving the map, I would like to be able to read the new coordinates of the annotation. How can I do this?
Thanks
The easiest way is to simply add your custom UIView to your MKMapView as a subview. This means when your user moves the map it will stay fixed. You will most likely have to pass through the touch events so that users can move over your custom view but worry about that later.
When your map view stops moving take its center coordinate. The MKMapView can calculate its coordinate based on its center etc [mapView centerCoordinate];
I know this is a bit old but I recommend you DSCenterPinMapView
It is a custom MapView with an animated and customizable center pin useful for selecting locations in map.
You should install the Pod and then, as a solution to your question you should implement the delegate so that you can get the location where pin drops.
pinMapView.delegate = self
extension MyViewController: DSCenterPinMapViewDelegate {
func didStartDragging() {
// My custom actions
}
func didEndDragging() {
// My custom actions
selectedLocation = pinMapView.mapview.centerCoordinate
}
}
I'm building an application with an interactive map (using the ArcGIS API for WPF) that runs on the Microsoft Surface 2.0 (now known as PixelSense). In my application I have a librarycontainer containing elements that a user can drag out and place on a certain location on the map. I achieve this by placing a scatterview (that envelopes the entire map) in an elementlayer on the map, like this:
<esri:ElementLayer>
<esri:ElementLayer.Children>
<local:DragDropScatterView esri:ElementLayer.Envelope="-19949487.9573175,-20100080.1372686,20125528.7282505,20131479.5822274" x:Name="ScatterLayer" Background="Transparent" Height="Auto" Width="Auto" ItemContainerStyle="{StaticResource ScatterItemStyle}" />
</esri:ElementLayer.Children>
</esri:ElementLayer>
The problems occur when a user zooms in or out on the map, causing the elements that have been placed in the scatterview to change their position completely.
To fix this issue I tried placing the scatterview inside a viewbox. When I do this, the elements maintains the right positions in the map, but now a new problem occurs: The elements scale up and down when I zoom in and out of the map (e.g. when the map is shown in full extent, the elements are almost invisible), while the preferred behavior is that the elements maintain their size when a user zooms in or out on the map (e.g. like the markers in Google Maps).
Does anyone have a suggestion as to how I can solve this problem?
Cheers
Instead of putting the ScatterView in a Viewbox, you should do the following:
After a ScatterViewItem is placed on the map, transform its Center point (which is in viewport coordinates) to a location in world coordinates (latitude and longitude). The ArcGIS API should provide such a transformation.
When the map is zoomed or otherwise transformed, transform each world location back to viewport coordinates and set each ScatterViewItem's Center property accordingly.
In order to store the world coordinates for each ScatterViewItem, you could create an attached property.
We are using WPF Bing Maps to visiualize clustered data. We are trying to update data on every OnViewChangeOnFrame event (because there is a significant delay in OnViewChangeEnd). However zooming and updating on every frame leads to "jerking" effect. The idea is to find out the target boundary rectangle OnViewChangeStart and update data only once in the beginning of zoom or pan for the target settings.
However there is a problem Bing Maps - Map class does not support TargetBoundingRectangle property. Is there an algorithm knowing viewportsize, target zoomlevel and target center to calculate TargetBoundingRectangle or maybe another Map property which has it?
Thanks!
Got an answer from MSDN forums.
WPF Bing Maps does not provide target boundary property right now.
I'm rendering a WPF grid with multiple elements (buttons, textbox, ...) to a bitmap which is then used as a texture for a 3D surface in a Direct3D scene. For user interaction I create a 3D ray from the 2D mouse cursor position into the 3D scene finding the intersection point with the gui surface. So I know where the user has clicked on the WPF grid, but from there I'm stuck:
How can I simulate mouse events on the WPF elements while they are not actually shown in an open window but rendered off-screen?
Recently, I was looking into UIAutomation and RaiseEvent but these are used to send events to individual elements, not the whole visual tree. Traversing the tree manually and looking for elements at the cursor position would be an option but I haven't found a way to do this accurately. VisualTreeHelper.HitTest is a good start but instead of finding TextBox it finds TextBoxView and instead of ListBox it finds a Border.
EDIT: returning HitTestResultBehavior.Continue in the result callback of HitTest lets me walk through all elements at a given point. I can now send mouse events to all these elements but the values of the MouseEventArgs object are those of the real mouse. So I have to create a custom MouseDevice which apparently is impossible.
PointHitTestParameters p = new PointHitTestParameters(new Point(
((Vector2)hit).X * sourceElement.ActualWidth,
(1 - ((Vector2)hit).Y) * sourceElement.ActualHeight));
VisualTreeHelper.HitTest(sourceElement,
new HitTestFilterCallback(delegate(DependencyObject o)
{
return HitTestFilterBehavior.Continue;
}),
new HitTestResultCallback(delegate(HitTestResult r)
{
UIElement el = r.VisualHit as UIElement;
if (el != null)
{
MouseButtonEventArgs e = new MouseButtonEventArgs(Mouse.PrimaryDevice, 0, MouseButton.Left);
if (leftMouseDown) e.RoutedEvent = Mouse.MouseDownEvent;
else e.RoutedEvent = Mouse.MouseUpEvent;
el.RaiseEvent(e);
}
return HitTestResultBehavior.Continue;
}), p);
You might be able to send windows messages (like WM_MOUSEMOVE) to the WPF window's HWND, via the PostMessage(..) win32 method. I believe these messages would be read by WPF and executed as if it came from a user.
If you are feeling really brave, you can try my hack to get access to the WPF IDirect3DDevice9Ex. From there you can copy the backbuffer in the swapshchain to your d3d scene. If you are using 9Ex (Vista D3D9), you can take advantage of the shared resources (share surfaces/textures/etc between devices and processes) feature to help with performance.
You may still have to do some trickery with windows messages for interactivity.