【WPF】KeyBinding with TriggerAction(Data Binding対応版)
はい。昨日こんなの書きました。動きませんでした。
参考記事によるとTriggerBaseはFreeazableだから、当然TriggerBaseを継承しているやつなら問題ないと思ったんですけどね。ICommandを実装してるとだめらしい。
というわけで書き直しました。
InputBindingTrigger
using System; using System.Diagnostics; using System.Windows; using System.Windows.Input; using System.Windows.Interactivity; namespace Hoge.Trigger { public class InputBindingTrigger : TriggerBase<FrameworkElement> { public static readonly DependencyProperty InputBindingProperty = DependencyProperty.Register("InputBinding", typeof(InputBinding) , typeof(InputBindingTrigger) , new UIPropertyMetadata(null)); public InputBinding InputBinding { get => (InputBinding)GetValue(InputBindingProperty); set => SetValue(InputBindingProperty, value); } private InputBindingCommand command = new InputBindingCommand(); protected override void OnAttached() { if (InputBinding == null) { base.OnAttached(); return; } InputBinding.Command = command; command.OnExecute += Command_OnExecute; if (AssociatedObject.Focusable) AssociatedObject.InputBindings.Add(InputBinding); else { FrameworkElement root = null; AssociatedObject.Loaded += delegate { root = GetRootElement(AssociatedObject); if (!root.InputBindings.Contains(InputBinding)) root.InputBindings.Add(InputBinding); }; AssociatedObject.Unloaded += delegate { root.InputBindings.Remove(InputBinding); }; } base.OnAttached(); } private FrameworkElement GetRootElement(FrameworkElement frameworkElement) { var parent = frameworkElement.Parent as FrameworkElement; if (parent == null) { Debug.Assert(frameworkElement.Focusable); frameworkElement.Focus(); return frameworkElement; } return GetRootElement(parent); } protected override void OnDetaching() { command.OnExecute -= Command_OnExecute; base.OnDetaching(); } private void Command_OnExecute(object parameter) => InvokeActions(parameter); } internal class InputBindingCommand : ICommand { public event EventHandler CanExecuteChanged = delegate { }; public Action<object> OnExecute = delegate { }; public bool CanExecute(object parameter) => true; public void Execute(object parameter) => OnExecute.Invoke(parameter); } }
ICommandを実装するのやめただけですね。
あと、RootElement取得するように変えてるっす。ので、ちょっとxamlが変わります。
ルート要素のFocusableをTrueに。
TriggerActionはTrigger.Actionsに。
なお、TriggerActionは前回用意したやつなので省略。
<Window x:Class="Hoge.Views.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" xmlns:action="clr-namespace:Hoge.Action" xmlns:trigger="clr-namespace:Hoge.Trigger" Focusable="True"> <Grid> <i:Interaction.Triggers> <trigger:InputBindingTrigger> <trigger:InputBindingTrigger.InputBinding> <KeyBinding Modifiers="Ctrl" Key="N"/> </trigger:InputBindingTrigger.InputBinding> <trigger:InputBindingTrigger.Actions> <action:ShowFolderBrowserDialogAction Description="選択せーや" SelectedPath="{Binding SelectedPath.Value, Mode=OneWayToSource}" /> </trigger:InputBindingTrigger.Actions> </trigger:InputBindingTrigger> </i:Interaction.Triggers> </Grid> </Window>
参考:
qiita.com