1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

WPFで「なぜか2回動く…」を解決する | イベント多重実行の典型パターン3選

1
Posted at

はじめに

・ボタンを1回押しただけなのに処理が2回動く
・画面を開き直したらイベントが増えていく
・なぜかAPIが複数回呼ばれる

👉 こんな経験ありませんか?

WPFでは、

👉 「イベントの多重登録」

でハマることがよくあります。

しかも厄介なのが、

👉 コードを見てもすぐ気づきにくい

ことです。

この記事では、

👉 WPFでよくあるイベント多重実行パターン

を、実務でよくあるケースベースで整理します。

よくある症状

例えばこんな状態です。

button.Click += OnClick;

これ自体は普通です。

でも、

・画面を開き直したあと
・初期化をやり直したあと
・再読み込みしたあと

に、

👉 同じイベントがもう一度登録される

すると、

👉 1回押しただけなのに2回動く

という状態になります。

なぜ気づきにくいのか

ここが重要です。

多くの場合、

👉 「処理の中身」を疑ってしまう

からです。

例えば、

・APIが重複してる?
・DB更新がおかしい?
・非同期処理の問題?

と考えます。

でも実際には、

👉 “入口が2回登録されている”

だけだったりします。


パターン① Loadedイベントで毎回登録している

一番多いパターンです。

private void Window_Loaded(object sender, RoutedEventArgs e)
{
    button.Click += OnClick;
}

これ、

👉 Loadedのたびに登録されます

つまり、

・画面再表示
・タブ切り替え
・再生成

などで、

👉 イベントが増殖する


症状

1回目 → 1回実行
2回目 → 2回実行
3回目 → 3回実行

👉 どんどん増える


対策

登録前に解除する。

button.Click -= OnClick;
button.Click += OnClick;

または、

👉 Loadedごとに登録しない構造にする


パターン② ViewModel生成時にイベント解除していない

MVVMでかなり多いです。

eventAggregator.SomeEvent += OnEvent;

これを登録したまま、

👉 ViewModelを破棄していない

すると、

👉 古いViewModelもイベントを受け取り続ける


症状

・閉じた画面の処理が動く
・昔のデータが更新される
・メモリリークする


なぜ怖い?

ここかなり重要。


コード上では、

👉 「今の画面だけ動いてるように見える」

でも実際には、

👉 裏で古いインスタンスも動いてる


対策

不要になったら解除。

eventAggregator.SomeEvent -= OnEvent;

または、

👉 Disposeで管理する


パターン③ Command内でイベント登録している

これも実務でかなりあります。

private void Execute()
{
    service.Completed += OnCompleted;
}

Executeが呼ばれるたびに、

👉 Completedが追加登録される


症状

・処理完了時に複数回呼ばれる
・同じメッセージが何回も表示される
・ログが増殖する


なぜハマる?

ここ重要。


多くの場合、

👉 「処理の流れ」は正しい

だからです。

でも、

👉 “イベント登録の寿命”

を意識できていない。


重要なのは「どこで登録し、いつ解除するか」

イベントは、

👉 登録したら終わり

ではありません。

重要なのは、

・いつ登録する?
・いつ不要になる?
・誰が管理する?

です。


「処理が2回動く」の正体

実は、

👉 同じ処理が2回呼ばれている

とは限りません。

多くの場合、

👉 「入口」が複数ある

だけです。

つまり、

処理異常
↓
ではなく

イベント多重登録

だったりします。

調査するときの見方

もし、

👉 「なぜか2回動く」

状態になったら、

まず確認するのはこれです。


✔ イベント登録箇所

+=

を検索。


✔ Loaded / Initialize

何回呼ばれるか確認。


✔ ViewModel生成回数

同じものが増えていないか。


✔ Disposeされているか

不要なイベントが残っていないか。


まとめ

WPFでイベントが多重実行される原因の多くは、

👉 イベントの多重登録

です。

特に多いのが、

・Loadedで毎回登録
・ViewModel破棄漏れ
・Command内登録

です。

そして重要なのは、

👉 「処理がおかしい」

ではなく、

👉 「入口が増えている」

可能性を疑うことです。


✔ 1つだけ意識するなら

👉 「このイベント、いつ解除される?」

これを意識するだけで、

👉 多重実行はかなり防げます

おわりに

WPFでは、

👉 イベントの寿命管理

がかなり重要です。

特にMVVMでは、

・View
・ViewModel
・イベント
・非同期処理

が複雑に絡むため、

👉 「いつ生まれて、いつ消えるか」

を意識しないとハマりやすくなります。

もし、

「こういうケースでも起きた」
「このパターンでハマった」

などあれば、ぜひ教えてください。

今後の記事で取り上げていきます。

1
1
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
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?