【WPF】KeyBinding with TriggerAction
追記。これ、このままじゃData Binding動かへん。書き直します。。
KeyBindingで実行対象がCommandなら別になんてことないんですけどね。
TriggerAction使う場合ね。
いつも通りおもむろに以下を作りましょう。
using System; using System.Windows; using System.Windows.Input; using System.Windows.Interactivity; namespace Hoge.Action { public class InputBindingTrigger : TriggerBase<FrameworkElement>, ICommand { 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); } public event EventHandler CanExecuteChanged = delegate { }; protected override void OnAttached() { if (InputBinding != null) { InputBinding.Command = this; AssociatedObject.InputBindings.Add(InputBinding); } base.OnAttached(); } public bool CanExecute(object parameter) => true; public void Execute(object parameter) => InvokeActions(parameter); } }
使い方
こんなTriggerActionが用意してあります。フォルダ選択ダイアログですね。
namespace Hoge.Action { /// <summary> /// FolderBrowserDialog Confirmation /// </summary> public sealed class FolderBrowserDialogConfirmation : Confirmation { public Boolean? ShowNewFolderButton { get; set; } public String SelectedPath { get; set; } public Environment.SpecialFolder? RootFolder { get; set; } public String Description { get; set; } public Object Tag { get; set; } } /// <summary> /// FolderBrowserDialog表示アクション /// </summary> public sealed partial class ShowFolderBrowserDialogAction { public Boolean? ShowNewFolderButton { get => (Boolean?)GetValue(ShowNewFolderButtonProperty); set => SetValue(ShowNewFolderButtonProperty, value); } private static readonly DependencyProperty ShowNewFolderButtonProperty = DependencyProperty.Register("ShowNewFolderButton", typeof(Boolean?), typeof(ShowFolderBrowserDialogAction), new PropertyMetadata(null)); public String SelectedPath { get => (String)GetValue(SelectedPathProperty); set => SetValue(SelectedPathProperty, value); } private static readonly DependencyProperty SelectedPathProperty = DependencyProperty.Register("SelectedPath", typeof(String), typeof(ShowFolderBrowserDialogAction), new PropertyMetadata(null)); public Environment.SpecialFolder? RootFolder { get => (Environment.SpecialFolder)GetValue(RootFolderProperty); set => SetValue(RootFolderProperty, value); } private static readonly DependencyProperty RootFolderProperty = DependencyProperty.Register("RootFolder", typeof(Environment.SpecialFolder), typeof(ShowFolderBrowserDialogAction), new PropertyMetadata(null)); public String Description { get => (String)GetValue(DescriptionProperty); set => SetValue(DescriptionProperty, value); } private static readonly DependencyProperty DescriptionProperty = DependencyProperty.Register("Description", typeof(String), typeof(ShowFolderBrowserDialogAction), new PropertyMetadata(null)); public Object Tag { get => GetValue(TagProperty); set => SetValue(TagProperty, value); } private static readonly DependencyProperty TagProperty = DependencyProperty.Register("Tag", typeof(Object), typeof(ShowFolderBrowserDialogAction), new PropertyMetadata(null)); } public sealed partial class ShowFolderBrowserDialogAction : TriggerAction<DependencyObject> { private static readonly FolderBrowserDialogConfirmation NullObject = new FolderBrowserDialogConfirmation(); protected override void Invoke(object parameter) { var param = parameter as InteractionRequestedEventArgs; var confirmation = param == null ? NullObject : param.Context as FolderBrowserDialogConfirmation; var dialog = GenerateDialog(confirmation); if (dialog.ShowDialog() == DialogResult.OK) { confirmation.Confirmed = true; ApplyDialogPropertyValues(confirmation, dialog); } else { confirmation.Confirmed = false; } param?.Callback(); } private FolderBrowserDialog GenerateDialog(FolderBrowserDialogConfirmation confirmation) { var dlg = new FolderBrowserDialog(); dlg.ShowNewFolderButton = confirmation.ShowNewFolderButton ?? ShowNewFolderButton ?? dlg.ShowNewFolderButton; dlg.RootFolder = confirmation.RootFolder ?? RootFolder ?? dlg.RootFolder; dlg.Description = confirmation.Description ?? Description ?? dlg.Description; dlg.Tag = confirmation.Tag ?? Tag ?? dlg.Tag; SelectedPath = string.Empty; return dlg; } private void ApplyDialogPropertyValues(FolderBrowserDialogConfirmation n, FolderBrowserDialog dlg) { if (n != NullObject) { n.ShowNewFolderButton = dlg.ShowNewFolderButton; n.SelectedPath = dlg.SelectedPath; n.RootFolder = dlg.RootFolder; n.Description = dlg.Description; n.Tag = dlg.Tag; } ShowNewFolderButton = dlg.ShowNewFolderButton; SelectedPath = dlg.SelectedPath; RootFolder = dlg.RootFolder; Description = dlg.Description; Tag = dlg.Tag; } } }
んで、xaml。コードビハインドとViewModelは省略。ReactiveProperty使ってます。
<Window x:Class="Hoge.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:action="clr-namespace:HogeAction" mc:Ignorable="d" d:DesignHeight="450" d:DesignWidth="800"> <Grid> <i:Interaction.Triggers> <action:InputBindingTrigger> <action:InputBindingTrigger.InputBinding> <KeyBinding Modifiers="Ctrl" Key="N"/> </action:InputBindingTrigger.InputBinding> <action:ShowFolderBrowserDialogAction Description="フォルダを選択してください" SelectedPath="{Binding SelectedPath.Value, Mode=OneWayToSource}" /> </action:InputBindingTrigger> </i:Interaction.Triggers> <Grid.RowDefinitions> <RowDefinition Height="Auto" /> <RowDefinition /> </Grid.RowDefinitions> <Menu Grid.Row="0" > <MenuItem Header="ファイル(_F)"> <MenuItem Header="新規(_N)" InputGestureText="Ctrl+N"> <i:Interaction.Triggers> <i:EventTrigger EventName="Click"> <action:ShowFolderBrowserDialogAction Description="フォルダを選択してください" SelectedPath="{Binding SelectedPath.Value, Mode=OneWayToSource}" /> </i:EventTrigger> </i:Interaction.Triggers> </MenuItem> </MenuItem> </Menu> </Grid> </Window>