drag and drop - lag in UWP - windows

Hello drag and drop fans,
Can anyone explain why I see a long lag time when using drag and drop with my UWP apps?
I wrote a test app that contains just the drag and drop message handlers and also the pointer handlers for comparison. Here’s the code...
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
grid1.AllowDrop = true;
grid1.DragOver += Grid1_DragOver;
grid1.Drop += Grid1_Drop;
grid1.DragLeave += Grid1_DragLeave;
grid1.PointerEntered += Grid1_PointerEntered;
grid1.PointerExited += Grid1_PointerExited;
}
// Drag Handlers ************************
private void Grid1_DragOver(object sender, DragEventArgs e)
{
msgFromPointer.Text = " drag/drop item has entered";
e.AcceptedOperation = Windows.ApplicationModel.DataTransfer.DataPackageOperation.Copy;
Debug.WriteLine("in grid1 drag over handler");
}
private void Grid1_DragLeave(object sender, DragEventArgs e)
{
msgFromPointer.Text = "";
}
private void Grid1_Drop(object sender, DragEventArgs e)
{
Debug.WriteLine("in grid1 drop handler");
}
// pointer handlers *******************
private void Grid1_PointerEntered(object sender, PointerRoutedEventArgs e)
{
msgFromPointer.Text = "POINTER has entered";
}
private void Grid1_PointerExited(object sender, PointerRoutedEventArgs e)
{
msgFromPointer.Text = "";
}
When doing a drag and drop to my app, there seems to be about a 1/2 second delay before my app receives the dragOver message. In comparison, the pointerOver message seems to arrive almost simultaneously with the pointer movement. The slow behavior is the same when using the touch screen or a mouse. Here’s a video of the behavior…
video of the laggy behavior
The PC I’m using has a touch screen and I’m wondering if there is some sort of touch “driver” or filter that is slowing down the drag and drop message. I've tried a bunch of Windows config settings, like mouse and display settings, but no change. The PC is a Dell Inspiron 3593, with the latest drivers. My Windows 10 version is 1903, build 18362.836
The app I’m developing uses a lot of drag and drop and this slow behavior makes the user interface really difficult. It’s kind of like trying to conduct a phone conversation with a 1/2 second delay.
Any ideas?
Dan

The DragOver event is triggered when the application determines that the element under the current pointer is a potential placement target.
This requires the pointer to hover for a period of time. This may be the reason for the delay you think.
You can try the DragEnter event, which is triggered earlier than DragOver.
Thanks

Related

Xamarin Forms Map Viewable Area event handler

I have a Xamarin form map on my screen and I'm using PropertyChanged event to retrieve geolocation information from my server and display the proper pins on screen.
While coding the solution I noticed the PropertyChanged event is triggered multiple times (up to 10 times) with a single zoom or drag action on the map. This causes unnecessary calls to server which I want to avoid.
Ideally I want to make only one call to server when the final PropertyChanged event is called but I cant's find an easy solution to implement this.
At this point I've added a refresh button to my page that becomes enabled when a PropertyChanged event happens and I disable it after user uses the button.
Obviously this fixed the too many calls to server but made the solution manual.
I was wondering if there is a more elegant way to make the server call but do it automatically.
Thanks in advance.
I just test the PropertyChanged event on iOS side and it just triggered one time with a single zoom or drag action on the map.
While if it really triggered multiple times, you can use a timer to call the server when the final PropertyChanged event is called, for example:
public partial class MapPage : ContentPage
{
Timer aTimer;
public MapPage()
{
InitializeComponent();
customMap.PropertyChanged += CustomMap_PropertyChanged;
}
private void CustomMap_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
if (aTimer != null)
{
aTimer.Enabled = false;
aTimer.Stop();
aTimer.Close();
}
aTimer = new Timer();
aTimer.Interval = 1000;
aTimer.Enabled = true;
aTimer.Elapsed += ATimer_Elapsed;
aTimer.Start();
}
private void ATimer_Elapsed(object sender, ElapsedEventArgs e)
{
aTimer.Stop();
//do web request
Console.WriteLine(sender);
Console.WriteLine("CustomMap_PropertyChanged");
}
}
In the above code, I set the Interval = 1 second, that means in 1 second, whatever how many times PropertyChanged triggered, only the last call will trigger the ATimer_Elapsed function.
The Interval can be set to any value depending on your requirement.

Windows Phone 8.1 App - Auto Logout (Detect if App is Running)

I am building a Windows 8.1 Universal app, and at the minute specifically I am working on the Windows Phone side of it. The app is an RT app built using the MVVM pattern, and I am using MVVM Light.
The app is for a financial institunion and exposes payment information. As such, there is a security requirement to log the user out of the app if there is no activity after a period of 2 minutes.
I've searched high and low for a solution to this problem. The only one which really works is to set up gestures in the view, and use a DispatchTimer, which expires and redirects to the app lock screen (not the built-in Windows one) after 2 minutes if no gestures have been detected. A gesture resets the timer. Here is some sample code for the gesture setup:
public MainPage()
{
this.InitializeComponent();
//Register the gestures, for the app timeout
this.PointerPressed += MainPage_PointerPressed;
this.PointerMoved += MainPage_PointerMoved;
this.PointerReleased += MainPage_PointerReleased;
gr.CrossSliding += Gr_CrossSliding;
gr.Dragging += Gr_Dragging;
gr.Holding += Gr_Holding;
gr.ManipulationCompleted += Gr_ManipulationCompleted;
gr.ManipulationInertiaStarting += Gr_ManipulationInertiaStarting;
gr.ManipulationStarted += Gr_ManipulationStarted;
gr.ManipulationUpdated += Gr_ManipulationUpdated;
gr.RightTapped += Gr_RightTapped;
gr.Tapped += Gr_Tapped;
gr.GestureSettings = Windows.UI.Input.GestureSettings.ManipulationRotate | Windows.UI.Input.GestureSettings.ManipulationTranslateX | Windows.UI.Input.GestureSettings.ManipulationTranslateY |
Windows.UI.Input.GestureSettings.ManipulationScale | Windows.UI.Input.GestureSettings.ManipulationRotateInertia | Windows.UI.Input.GestureSettings.ManipulationScaleInertia |
Windows.UI.Input.GestureSettings.ManipulationTranslateInertia | Windows.UI.Input.GestureSettings.Tap;
InitializeTimer();
}
There are methods for receiving gesture inputs on the page, like this:
private void Gr_Tapped(Windows.UI.Input.GestureRecognizer sender, Windows.UI.Input.TappedEventArgs args)
{
ResetTimer();
}
And here is my timer code:
private DispatcherTimer _timer2 { get; set; }
int ticks = 0;
private void InitializeTimer()
{
_timer2 = new DispatcherTimer();
_timer2.Tick += timer2_Tick;
_timer2.Interval = new TimeSpan(00, 0, 1);
bool enabled = _timer2.IsEnabled;
_timer2.Start();
}
void timer2_Tick(object sender, object e)
{
ticks++;
if (ticks >= 120)
{
Timeout();
}
}
private void Timeout()
{
_timer2.Stop();
_timer2 = null;
Frame.Navigate(typeof(LockView));
}
private void ResetTimer()
{
_timer2.Stop();
_timer2.Start();
ticks = 0;
}
This solution is far from perfect. I will have to use it if I can't find a better one, but there are 4 main problems with it;
It breaks the MVVM pattern. All this code has to go in the code behind of the View. I have 7 views which are accessible after the user logs in, so there will be a lot of repitition
It doesn't capture all gestures. For example is seems to ignore when scrolling up and down a listbox full of items
I have to call the ResetTimer() method or _timer2.Stop() from anywhere in the view that might be considered a gesture (even just before navigating away from the view)
It's just a messy and awkward solution
Does anyone know of a better way of achieving this? Surely there's a more elegant solution, maybe something at a higher level, rather than trying to catch every last button press and gesture.
Also, it would be useful if the app could detect whether it was running in the foreground or the background, and auto-navigates to the lock screen if the user navigates away from the app then goes back to it later.
Thanks in advance for any suggestions...

Manipulation_started doesn't work on a map

Hi to all I'm trying to set a listener for the ManipulationStarted, ManipulationDelta, ManipulationCompleted of a map to detect if the user drag a map around, but looks like none of those events are launched if I drag the map. If I set a tap listener for the map ManipulationStarted is correctly launched.
What I'm doing wrong?
xaml code:
<Controls:Map x:Name="myMap"
Grid.Row="0"
Loaded="myMap_Loaded"
ManipulationDelta="myMap_ManipulationDelta"
ManipulationCompleted="myMap_ManipulationCompleted"
ManipulationStarted="myMap_ManipulationStarted"
Tap="myMap_Tap">
code behind:
private void myMap_ManipulationDelta(object sender, System.Windows.Input.ManipulationDeltaEventArgs e)
{
Debug.WriteLine("Event:: MyMap_manipulationdelta");
}
private void myMap_ManipulationCompleted(object sender, System.Windows.Input.ManipulationCompletedEventArgs e)
{
Debug.WriteLine("Event:: MyMap_manipulationcompleted");
}
private void myMap_ManipulationStarted(object sender, System.Windows.Input.ManipulationStartedEventArgs e)
{
Debug.WriteLine("Event:: MyMap_manipulationstarted");
}
private void myMap_Tap(object sender, System.Windows.Input.GestureEventArgs e)
{
Debug.WriteLine("Event:: MyMap_tap");
}
I'm on a normal page, no pivot or panorama.
I'm afraid that you won't be able to handle those events because Map control intercepts them. Although there is a property UseOptimizedManipulationRouting, but as I've tested it - it doesn't help much in this situation.
I dont't know what you are trying to achieve, but if you don't need ManipulationDeltaEventArgs then maybe you consider using different events such as: MouseEnter, ResolveCompleted and CenterChanged.
If you need them then as JustinAngel suggested here you can follow these instructions and use Touch.FrameReported event for your purpose.
EDIT - code sample
If I've understood you properly, you would like to know when the User touches the Map, MouseEnter won't be the best choice as it will work only first time, then if mouse didn't leave the Map (user touched somewhere else), it won't fire again. Better solution here (following instructions above) can be such a code:
public MainPage()
{
InitializeComponent();
Touch.FrameReported += Touch_FrameReported;
}
private void Touch_FrameReported(object sender, TouchFrameEventArgs e)
{
TouchPoint point = e.GetPrimaryTouchPoint(myMap);
if (point.Action == TouchAction.Move && point.Position.Y > 0)
{
MessageBox.Show("User is Moving Finger over the Map!");
}
}

Caliburn.Micro(.WP7) and Bing Maps Crashing

I have an app that I'm upgrading from some beta bits - and my map screen is crashing. So to try to get to the bottom of it - I started a brand new - blank "Win Phone Application".
Referenced Caliburn.Micro (just built from new code last night) Version: caliburnmicro_1296ea635677 (from codeplex)
referenced Microsoft.phone.controls.map.dll
and in the MainPage I added
<Grid>
<Maps:Map />
</Grid>
and I add a bootstrapper to app.xaml
<WP7:PhoneBootStrapper x:Name="bootstrapper" />
when the page runs in the phone emulator - the main page renders and I see a map of the world. if I click anywhere on the page - I get an unhandled exception of "The parameter is incorrect"
if I remove the
from the app.xaml - the map works correctly.
What do you think?
Thanks for any advice?
I have found the answer.
The key here - is that I had this setup and wroking with the Beta Templates - and it stopped working when I moved to the WinPhone RTM Templates in VS2010.
Caliburn does some work on my behalf, that was "ADDED" to the RTM templates - which were conflicting with each other. In the end This problem has/had nothing to do with the Bing Maps control - it just so happens that - that was my first screen - so that's where I was trying to solve the problem.
This was the ever so Not-Helpful exception:
The parameter is incorrect
Which, I'm pretty sure would happen on any screen - if you went to the upgrade path of templates, like I did. So here is what I had to remove - to get everything back to normal. In the new App.Xaml.cs - I removed (by commenting) in the App Ctor ...
// Phone-specific initialization
// InitializePhoneApplication();
// Global handler for uncaught exceptions.
// UnhandledException += Application_UnhandledException;
And then I removed these method bodies, because it's just dead code after removing the InitializePhoneApplication() call from ctor ...
// Code to execute when the application is launching (eg, from Start)
// This code will not execute when the application is reactivated
private void Application_Launching(object sender, LaunchingEventArgs e)
{
}
// Code to execute when the application is activated (brought to foreground)
// This code will not execute when the application is first launched
private void Application_Activated(object sender, ActivatedEventArgs e)
{
}
// Code to execute when the application is deactivated (sent to background)
// This code will not execute when the application is closing
private void Application_Deactivated(object sender, DeactivatedEventArgs e)
{
}
// Code to execute when the application is closing (eg, user hit Back)
// This code will not execute when the application is deactivated
private void Application_Closing(object sender, ClosingEventArgs e)
{
}
// Code to execute if a navigation fails
private void RootFrame_NavigationFailed(object sender, NavigationFailedEventArgs e)
{
if (System.Diagnostics.Debugger.IsAttached)
{
// A navigation has failed; break into the debugger
System.Diagnostics.Debugger.Break();
}
}
// Code to execute on Unhandled Exceptions
private void Application_UnhandledException(object sender, ApplicationUnhandledExceptionEventArgs e)
{
if (System.Diagnostics.Debugger.IsAttached)
{
// An unhandled exception has occurred; break into the debugger
System.Diagnostics.Debugger.Break();
}
}
#region Phone application initialization
// Avoid double-initialization
private bool phoneApplicationInitialized = false;
// Do not add any additional code to this method
private void InitializePhoneApplication()
{
if (phoneApplicationInitialized)
return;
// Create the frame but don't set it as RootVisual yet; this allows the splash
// screen to remain active until the application is ready to render.
RootFrame = new PhoneApplicationFrame();
RootFrame.Navigated += CompleteInitializePhoneApplication;
// Handle navigation failures
RootFrame.NavigationFailed += RootFrame_NavigationFailed;
// Ensure we don't initialize again
phoneApplicationInitialized = true;
}
// Do not add any additional code to this method
private void CompleteInitializePhoneApplication(object sender, NavigationEventArgs e)
{
// Set the root visual to allow the application to render
if (RootVisual != RootFrame)
RootVisual = RootFrame;
// Remove this handler since it is no longer needed
RootFrame.Navigated -= CompleteInitializePhoneApplication;
}
#endregion
Special Thanks to Rob for his help solving this mystery!

Phone 7 Bing map control - Add a pushpin when tap

I am using the latest Phone 7 RTM tools ( downloaded it today, October 7 2010).
I am trying to do a simple thing here:
when the user taps once on the map control, i want to put a pushpin there.
also, i want to keep the regular built-in behavior of the map control ( tap twice to zoom).
(If it's not possible to keep both behaviors , then maybe a long press on the map to put pushpin).
When trying figuring this out, i came across this documentation of the changes made to the control map for Phone7:
http://msdn.microsoft.com/en-us/library/ff955762.aspx
Then i saw the new class MapInputEventArgs, which has a ViewportPoint member.
When looking at code examples on the regular SilverLight map control i saw something like this:
private void OnMouseClick(object sender, MapMouseEventArgs e)
{
Point clickLocation = e.ViewportPoint;
Location location = x_Map.ViewportPointToLocation(clickLocation);
Pushpin pushpin = new Pushpin();
m_PushpinLayer.AddChild(pushpin, new Location(latitude, longitude));
}
But in Phone7 case, I can't find the appropriate event handler, and I could not find who uses MapInputEventArgs in the map control.
Searching it on google gets me only 1 result !!
So , where is the appropriate event for "Tap once", and how can i get a ViewportPoint after this event has been fired ?
Thanks in advance.
Just figured this out if you are still having problems.
The MouseLeftButtonUp and MouseLeftButtonDown Events have a GetPosition Method that will return the point your looking for
private void MapMain_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
Point p = e.GetPosition(this.MapMain);
GeoCoordinate geo = new GeoCoordinate();
geo = MapMain.ViewportPointToLocation(p);
MapMain.ZoomLevel = 17;
MapMain.Center = geo;
//---create a new pushpin---
Pushpin pin = new Pushpin();
//---set the location for the pushpin---
pin.Location = geo;
//---add the pushpin to the map---
MapMain.Children.Add(pin);
}
Unless I'm reading your question wrong, this seems to be exactly what you're looking for:
Silverlight - Add Pushpin to Bing Maps via C#
Okay, it's not pretty, but I have the same problem and I came up with a workaround of sorts that kicks in when you release your fingers from the screen. I instantiate a boolean:
bool noPin = false;
I then use this to determine whether zoom or pan is being done by the user (these fire between the MouseLeftButtonDown and MouseLeftButtonUp events). On the Up event, I then check whether the user was zooming or panning and, if not, place my pushpin.
private void mHome_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
noPin = false;
}
private void mHome_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
if (!noPin)
PlacePushPin();
}
private void mHome_MapPan(object sender, MapDragEventArgs e)
{
tbTemp.Text += "pan";
}
private void mHome_MapZoom(object sender, MapZoomEventArgs e)
{
tbTemp.Text += "zoom";
}
It's not beautiful but, well, it was the best I could manage.

Resources