WPF の ComboBox における DataContext のメモリリーク | 理系ママの、育児と家事と山と株とプログラミング

理系ママの、育児と家事と山と株とプログラミング

美容・語学・IT・子供・レジャー・資産運用など、思いつくままに色々と書きたいと思います。ひょっとすると雑貨・介護・風水なんかの話もするかもしれません。

最近プログラミングでハマったバグなどをいくつか。
今日はその第一弾。
 
WPF の ComboBox って、一度ドロップダウンを開けてしまうと DataContext に結びついた ViewModel を握ったまま放してくれなくなるようです。
 
何かの View (Window とか UserControl とか) の上に ComboBox を載せて、VIew の DataContext に View Model のインスタンス①を設定すると、普通に ComboBox の DataContext もそのインスタンス①になります。
新しい View Model のインスタンス②を用意して、View の DataContext をそのインスタンス②にしたら、当然 ComboBox の DataContext もインスタンス②になって、誰も参照していないインスタンス①はガベージコレクションの対象になるはず。
 
ところがインスタンス①が結びついている時に ComboBox のドロップダウンを開けてしまうと、ComboBox の ScrollViewer の Grid の Popup の PopupRoot の DataContext がインスタンス①で固定化されてしまって、その後 View や ComboBox の DataContext をインスタンス②にしても PopupRoot の DataContext はインスタンス①のままになってしまいます。
https://connect.microsoft.com/VisualStudio/feedback/details/796702/wpf-combobox-memory-leak によると、Microsoftさんは修正しない方針のようで。
色々調べましたが、回避方法は見つかりません。
View の View Model を取り替えずに済むようなアーキテクチャにするくらいですかね。
 
ただ、インスタンス①が結びついたまま残っていると言っても、下の図のような感じで結びついているのは PopupRoot だけで、ComboBox 自体は新しいインスタンス②を DataContext として持っています。
 
 
なので ComboBox のドロップダウンの中の項目が更新されない、とか、新しい View Model の機能が使えない、というわけではないのでご安心を。
 
メモリリークといえばメモリリークですが、最大でも画面内の ComboBox の数+1個の View Model のインスタンスが残ってしまうだけで、画面を開くたびに新しい View Model ができてインスタンス数が無限に増えていく、というわけではないので致命的ではなさそう。
 
懸念事項が一つだけあって、それはガベージコレクションされていると思っていた古い View Model のインスタンスが、頑固に生き残って想定外のイベントハンドリングとかで静的なデータを更新してしまったりするんじゃないかと。
そうならないように、この WPF のバグを理解した上で使わないといけませんね。
 
あ、ComboBox だけでなくドロップダウン式のコントロール一般のバグらしいです。
調べていないですが Menu とかもそうかなあ。