开发者

ALT+F4 and the IsCancel button

开发者 https://www.devze.com 2023-01-27 02:42 出处:网络
Is it possible to have Alt+F4 (as well as the X close button + <system menu> :: Close) trigger the button that is marked as IsCancel? I\'d like to have it b开发者_JAVA百科ehave in the same way t

Is it possible to have Alt+F4 (as well as the X close button + <system menu> :: Close) trigger the button that is marked as IsCancel? I'd like to have it b开发者_JAVA百科ehave in the same way to pressing the Esc key.

Note: I am using Prism and the dialog is being created in a RegionBehavior so I cannot directly access the button


Alt+F4 should trigger the CloseCommand (RoutedUICommand, Property from static class ApplicationCommands). If you define a CommandBinding for this Command, you should be able to react on it (i.e. call the StopCommand or cancel some other way) and mark it as handled, otherwise the Window will handle it and close.

If this is not possible, you could just detach the KeyGesture Alt+F4 from the CloseCommand (on application startup) and map it to some other action that does your cancelling.


I ended up supporting this via a custom behavior, the code for which is below. I'm more than happy to switch to a cleaner implementation (one that does not require adding a behavior to the button, for example) if anyone can think of one.

A few notes on the implementation (which is based on Rx):

  • It assumes that clicking the cancel button will always result in the window being closed. If your cancel button can be cancelled (so to speak) it will result in the button not being clicked when the window is closed.
  • If the button is somehow removed from the window (in our case, different content is swapped into a region), it will detatch the behavior.
  • All event handlers are removed at the end of the sequence, regardless of whether the window was closed, the button was clicked, or the button was removed.

And here is the code:

public class DialogCancelButtonBehavior : Behavior<Button>
{
    protected override void OnAttached()
    {
        base.OnAttached();

        Button button = AssociatedObject;

        GetWindowAsync(button)
            .SelectMany(window => GetWindowClosed(window))
            .Where(_ => button.IsCancel)
            .TakeUntil(GetButtonClicked(button))
            .TakeUntil(GetButtonUnloaded(button))
            .Subscribe(_ => ClickButton(button));
    }

    private IObservable<Window> GetWindowAsync(Button button)
    {
        var buttonLoaded = Observable.FromEvent<RoutedEventHandler, RoutedEventArgs>(
            h => new RoutedEventHandler(h),
            h => button.Loaded += h,
            h => button.Loaded -= h);

        return button.IsLoaded
            ? Observable.Return(Window.GetWindow(button))
            : buttonLoaded.Take(1).Select(_ => Window.GetWindow(button));
    }

    private IObservable<IEvent<EventArgs>> GetWindowClosed(Window window)
    {
        return Observable.FromEvent<EventHandler, EventArgs>(
            h => new EventHandler(h),
            h => window.Closed += h,
            h => window.Closed -= h);
    }

    private IObservable<IEvent<RoutedEventArgs>> GetButtonClicked(Button button)
    {
        return Observable.FromEvent<RoutedEventHandler, RoutedEventArgs>(
            h => new RoutedEventHandler(h),
            h => button.Click += h,
            h => button.Click -= h);
    }

    private IObservable<IEvent<RoutedEventArgs>> GetButtonUnloaded(Button button)
    {
        return Observable.FromEvent<RoutedEventHandler, RoutedEventArgs>(
            h => new RoutedEventHandler(h),
            h => button.Unloaded += h,
            h => button.Unloaded -= h);
    }

    private void ClickButton(Button button)
    {
        ButtonAutomationPeer peer = 
            (ButtonAutomationPeer)UIElementAutomationPeer.CreatePeerForElement(button);

        IInvokeProvider invokeProv = 
            peer.GetPattern(PatternInterface.Invoke) as IInvokeProvider;

        invokeProv.Invoke(); 
    }
}
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号