سؤال

What I'm looking for is like the Mail application installed on Windows 8.1. You start dragging and at any time, you can press the Escape key to cancel the drag.

I tried two things, but they failed:

  • I keep a reference to DragItemsStartingEventArgs and set "dragItemsStartingEventArgs.Cancel = true" when the Escape key was pressed.
  • I set to false the ListView CanDragItems property.

My hypothesis at the moment is the Mail app is built around HTML5/JS and it has features that XAML app cannot have... I hope I'm wrong.

Thanks ArchieCoder

هل كانت مفيدة؟

المحلول

Ah, sure. You can do this. Here's how.

public sealed partial class MainPage : Page
{
    Pointer _Pointer = default(Pointer);
    public MainPage()
    {
        this.InitializeComponent();

        this.Dispatcher.AcceleratorKeyActivated += (s, e) =>
        {
            if (e.EventType == (CoreAcceleratorKeyEventType.SystemKeyDown & CoreAcceleratorKeyEventType.KeyDown)
                && e.VirtualKey == VirtualKey.Escape)
            { MyListView.ReleasePointerCapture(_Pointer); }
        };

        this.PointerMoved += (s, e) =>
        { _Pointer = e.Pointer; };
    }
}

Also, the ListView is named MyListView.

Best of luck!

نصائح أخرى

I haven't used that drag & drop API too much, so the only things I can see is the ones you tried. I did recently discover though (thanks to Tim Heuer's mention somewhere) this sample on advanced input concepts that might be helpful. I think it describes an API new to 8.1 that allows you to handle manipulation events inside of a ScrollViewer (when you combine System and TranslateX/Y ManipulationModes) and cancel scrolling them you don't want to scroll anymore (e.g. when you start dragging). That could let you implement your own, customized version of drag&drop with any features you need.

I think it is worth discussing why retaining a reference to a cancel event argument is not the solution because of how cancel events are programmed. This will be worthwhile for everyone a little later. So, let's pretend we were going to fire a rocket into space. The Fire() method itself might look like this.

void Fire()
{
    Rocket.Fire();
}

But because we will people to react to it after it was completed we might creat an AfterFire event to let people know it is completed. It would might look like this.

event EventHandler AfterFire;
void Fire()
{
    Rocket.Fire();
    AfterFire(this, EventArgs.Empty);
}

In all reality you would need some error handling to make this right.

But because we want people to interrogate if the rocket launch is safe prior to the actual fire action, we include a BeforeFire event to let people know it is imminent. But in case the rocket is not safe, we want to include the ability to cancel. Like this.

class BeforeFireEventArgs: EventArgs { public bool Cancel { get; set; }}
event EventHandler<BeforeFireEventArgs> BeforeFire;
event EventHandler AfterFire;
void Fire()
{
    var args = new BeforeFireEventArgs();
    BeforeFire(this, args);
    if (args.Cancel)
        return;
    Rocket.Fire();
    AfterFire(this, EventArgs.Empty);
}

The thing to notice here is that the BeforeFireEventArgs are created in this method, passed to the event by this method, and interrogated after the event is returned to this method. If you were to handle the BeforeFire event you could set Cancel to true and it would not fire.

The WinRT GetDeferral() pattern exists to handle this scenario

If, however, you were to handle the BeforeFire event, not set Cancel to true but retain a reference to the BeforeFireEventArgs for later, the handler would release the event and the Cancel would either prevent or allow the rocket to fire.

Then, a minute later if you use that same reference of the BeforeFireEventArgs and set Cancel to true! The timing is all too late. Far too late. The event was already raised. It was already handled. And Cancel was already interrogated.

Make sense?

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top