3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

WPFアプリで、Ctrl+Sが押されたときに保存処理を呼ぶ

Last updated at Posted at 2022-12-06

はじめに

「ネットワーク接続してるような外部アプリ使うと、入力した内容が漏洩する可能性あるよね?
だからtrelloやらなんやらみたいなタスク管理ツールは使っちゃだめだよ」
と言われ、経験ないながら一からタスク管理ツールを作りました。

その最中で壁にぶち当たったので残しておこうと思います。

やりたかったこと

よくある編集アプリのように、

  • Ctrl+Sを押されたら
  • 1回きりだけ
  • 保存処理を呼び出す
  • 当然、呼び出し処理の成功確率は100%

これがしたかっただけなのですが、うまくいかずあれやこれや試したので色々残そうと思います。

いい感じに動いたパターン

これだとうまく動きました。

protected override void OnKeyDown(KeyEventArgs e)
{
    if (!e.IsRepeat
        & Keyboard.GetKeyStates(Key.LeftCtrl).HasFlag(KeyStates.Down) 
        & Keyboard.GetKeyStates(Key.S).HasFlag(KeyStates.Down))
    {
        RegistData();
    }
}

e.IsRepeatで、キー長押しで呼ばれたのかどうかを判定して何度も登録処理が走るのを防いでいます。

それと、LeftCtrlとSの状態がDownになっているかを、==ではなくHasFlagで判定しているのがポイントでした。
デバッグしてわかったんですが、ここの状態はDown, Toggleみたいな感じで複数の状態を持つことがあるようです。

だめだったパターン

キーの状態を==で比較 & e.IsRepeatを判定してない

さっき書いた通り、状態が複数になっていると==ではないため、falseとなり登録処理が走らないことがある。
体感だと成功率70%くらい。

protected override void OnKeyDown(KeyEventArgs e)
{
    if (Keyboard.GetKeyStates(Key.LeftCtrl) == KeyStates.Down 
        & Keyboard.GetKeyStates(Key.S) == KeyStates.Down)
    {
        RegistData();
    }
}

コマンドバインドを使う

押した時にちゃんと動きはするものの、長押しするとするだけ登録処理が呼び出されちゃう。

xml MainWindow.xaml
<Window x:Class="Test.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:Test"
        Title="MainWindow" Height="350" Width="525">
    <Window.CommandBindings>
        <CommandBinding 
            Command="{x:Static local:MainWindow.RegistCommand}" 
            Executed="CommandBinding_Executed"/>
    </Window.CommandBindings>
    <Window.InputBindings>
        <KeyBinding Gesture="Ctrl+S" Command="{Binding RegistCommand}"/>
    </Window.InputBindings>
    <!-- なんかいろんな要素 -->
</Window>
c# MainWindow.xaml.cs
public RoutedCommand RegistCommand = new RoutedCommand();

// なんかいろんな処理

private void CommandBinding_Executed(object sender, ExecutedRoutedEventArgs e)
{
    RegistData();
}

あとがき

ネットで調べてるとe.KeyCodeとかKeys.Controlみたいな書き方がよくあったんだけど、僕の環境だとそもそも存在しないプロパティでした。
(はるか昔にどっかで使ったことある気もする)
見てる感じだとe.KeyCodeに関しては、オブジェクトがSystem.Windows.Forms.KeyEventArgsじゃなくてSystem.Windows.Input.KeyEventArgsだったからっぽい。
なんでなんだろう。

textboxとかのOnKeyDownじゃなくてwindow自体の関数だから、とか・・?
普段業務でやってる言語と違って、同じC#かつ同じオブジェクト名でも、微妙に使えたり使えなかったりするからてんやわんやでした。

ただ、自分でアプリを作ると「この機能が欲しい!」→ すぐ作ることできるから良いですね。
楽しい。

3
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?