投稿

ラベル(WPF)が付いた投稿を表示しています

システム時刻を変更したときの.Netプログラムの時間関係への影響

サーバー系のプログラムでは一定時間ごとに処理を行う定期処理を組む場合がある。もし動作中にOSのシステム時刻を変更された場合にどうなるのか。今回は.NetでのWindowsのシステム時刻を変更したときの動作を確認した。 SleepとDelay まずはSleep系の挙動を確認する。恐らくクロックカウントを利用しているのでシステム時刻の影響は無いと想定される。 Thread.SleepとTask.Delayで次のようなコードを書いた。なお環境は.Net Core3.1だ。 void TestSleep() { while (true) { Thread.Sleep(10000); Debug.WriteLine("tick"); } } async Task TestDelay() { while (true) { await Task.Delay(10000); Debug.WriteLine("tick"); } } プログラムを起動した状態でシステム時刻を適当にずらす。ストップウォッチを持って計測したところ、システム時刻を進めても戻してもきちんと10秒ごとにデバッグ文が出力された。 Thread.SleepとTask.Delayはシステム時刻に影響を受けないことが確認できた。 DateTime.Now 次にDateTimeの現在日時を確認する。Sleepが定期動作することが分かったので次のコードを書く。 void TestDateTime() { while (true) { Thread.Sleep(10000); Debug.WriteLine($"{DateTime.Now:MM/dd HH:mm:ss}"); } } 結果 11/12 21:40:33 11/12 21:40:43 _ここで5秒時間を戻す 11/12 21:40:48 11/12 21:40:58 当然ではあるがシステム時刻に合わせて日時が変わった。このことからDateTime.Nowを経過時間の判定に利用する場合は、時刻飛びや遡りが起きることに注意が必要だ。 Stopwatch 次は高性能...

WPF DataGridで列選択できるようにする

イメージ
WPFのDataGridはSelectionUnitプロパティをCellOrRowHeaderにすると行ヘッダのクリックで行選択ができる。一方で列選択は用意されていない。必要になったので自前で再現してみたが、案外面倒くさかったので残しておく。 XAML <DataGrid x:Name="MyGrid" SelectionMode="Extended" SelectionUnit="CellOrRowHeader" CanUserSortColumns="False" CanUserReorderColumns="False" CanUserResizeColumns="False" CanUserResizeRows="False"> <DataGrid.ColumnHeaderStyle> <Style TargetType="DataGridColumnHeader"> <EventSetter Event="PreviewMouseDown" Handler="Column_MouseDown" /> <EventSetter Event="PreviewMouseMove" Handler="Column_MouseMove" /> <EventSetter Event="PreviewMouseUp" Handler="Column_MouseUp" /> </Style> </DataGrid.ColumnHeaderStyle> </DataGrid> セルの複数選択が必要なので、SelectionModeをExtended、SelectionUnitをCellまたはCellOrRowHeaderにする。...

WPF FrameがPageのインスタンスを保持してる件

イメージ
WPFでページ遷移を作る場合、XAMLでFrameコントロールを置いてナビゲーションするのが手っ取り早い。しかし今回はちょっとした罠に掛かってしまった。 ページ遷移でメモリリーク? なんか画面移動するたびにメモリが増えていく。まあPageのインスタンスをその都度newしてるので一時的には増えるが、そのうちGCされるだろう。そう思ってたがいつまでも減らない。試しにGC.Collect()してみても減らない。Page内で残ってる参照なども心当たりがない。はて。 犯人はナビゲーション機能 Frameコントロールにはナビゲーションの機能が付いている。NavigationUIVisibility="Visible"を付けると[戻る]とか[進む]のボタンが出てくる。 こういうやつ。見た目がいまいちだしあまり使われてる気はしない。しかしどうもこの[戻る][進む]機能のために、Frameは表示したインスタンスの参照を保持しているようだった。 これはNavigationUIを非表示にしてもやめないし、履歴保持数などのプロパティも設定できない。いったいどの程度持ち続けるのだろうか。まさかメモリが枯渇するまで残し続けることは無いと信じたいが。 対策 前述の通りプロパティなどで無効化することはできないので、履歴を手で消してやる。以下のようなコードをどこかしらに実装する。 while (Frame.CanGoBack) { Frame.RemoveBackEntry(); } RemoveBackEntry()は最後の履歴を1件削除する。全クリアなどのメソッドは無いらしい。しかも履歴が一件も無い状態で呼ぶと例外が発生する。 これをページ遷移の処理部なりで呼んでやれば、とりあえず延々増えてくことは回避できる。確実なのはFrameの遷移完了イベントあたりか。 しかしAddなんちゃらみたいなメソッドではなく、Content=~という代入でキューイングされるのはちょっとイマイチな実装だと思う。