
WPFで、あるコントロールのプロパティをバックアップして、何か魔法のような操作をした後、それらのプロパティを復元する。なんてありふれた操作でしょう!しかし、バックアップの方法は検討に値する問題です。直接代入?それはきっと、いくつかの落とし穴を踏んでいないからでしょう。
本記事の内容
- シナリオと問題
- 解決方法と原理
- 発展
シナリオと問題
ここで、あるシナリオを想像してみましょう(コードを書きやすいように):
- あるウィンドウがあり、いくつかのスタイルプロパティが設定されている
- 今、このウィンドウを全画面に設定する必要があり、そのためにはいくつかの元のプロパティを変更する必要がある(WPF標準の設定にはバグがあり、それについては別のブログ記事で説明します)
- ウィンドウの全画面設定を解除した後、以前に変更したプロパティを「完璧に」復元する
一般的には、次のように書くかもしれません:
private Window _window;
private WindowStyle _oldStyle;
private void OnEnterFullScreen()
{
_oldStyle = _window.WindowStyle;
_window.WindowStyle = WindowStyle.None;
}
private void OnExitFullScreen()
{
_window.WindowStyle = _oldStyle;
}
しかし:
- もし誰かが
WindowStyleに動的なスタイルを設定していたらどうなるか?——もちろん、動的ではなくなります(スタイル値が上書きされるため) - もし誰かが
WindowStyleにバインディングを設定していたらどうなるか?——もちろん、それも効かなくなります(バインディングがあなたの代入によって上書きされるため)
解決方法と原理
WPFの入門書の多くがWPF依存関係プロパティの優先順位メカニズムについて説明しているので、基本的に皆さんご存知でしょう。知らない方は、すぐにこちらをご覧ください:依存関係プロパティ値の優先順位 - WPF Microsoft Docs。
優先順位は次のとおりです:強制 > アニメーション > ローカル値 > テンプレート > 暗黙のスタイル > スタイルトリガー > テンプレートトリガー > スタイル > 既定のスタイル > プロパティ値の継承 > メタデータの既定値。
XAMLやC#コードで直接代入すると設定されるのは「ローカル値」です。そのため、ローカル値を設定すると、それより低い優先順位のスタイルはすべて無効になります。
では、バインディングはどうでしょうか?バインディングは依存関係プロパティの優先順位には存在しません。バインディングは実際には「ローカル値」を介して実装されており、バインディング式を「ローカル値」に設定し、値が必要になったときに ProvideValue で値を提供します。したがって、ローカル値を再設定すると、バインディングの設定は上書きされてしまいます。
しかし、SetCurrentValue はまさにこのためのものです!
SetCurrentValue は、依存関係プロパティの既存の値を変更せずに、プロパティの現在の値を設定するように設計されています。
_window.SetCurrentValue(Window.WindowStyleProperty, WindowStyle.None);
そして、SetCurrentValue による変更を元に戻すだけで、この依存関係プロパティに設定されたすべての値を復元できます:
_window.InvalidateProperty(Window.WindowStyleProperty);
ClearValue ではないことに注意してください。それはローカル値をクリアしてしまいます。
しかし、もう一つ不足があります。SetCurrentValue を適用している間にバインディングが変更された場合、この代入によってバインディングが即座に有効になるわけではありません。そのため、手動でバインディングを再度更新させる必要があります:
BindingOperations.GetBindingExpression(_window, Window.WindowStyleProperty)?.UpdateTarget();
では、これらを総合すると、この記事の最初のコードは次のように更新されます:
private Window _window;
private void OnEnterFullScreen()
{
_window.SetCurrentValue(Window.WindowStyleProperty, WindowStyle.None);
}
private void OnExitFullScreen()
{
_window.InvalidateProperty(Window.WindowStyleProperty);
BindingOperations.GetBindingExpression(_window, Window.WindowStyleProperty)?.UpdateTarget();
}
発展
コードを汎用的にしてみましょう:
static void ApplyTempProperty(DependencyObject d, DependencyProperty dp, object tempValue)
{
d?.SetCurrentValue(dp, tempValue);
}
static void RestoreProperty(DependencyObject d, DependencyProperty dp)
{
d.InvalidateProperty(dp);
BindingOperations.GetBindingExpression(d, dp)?.UpdateTarget();
}
この記事は頻繁に更新されます。原文をご覧ください: https://blog.walterlv.com/post/change-and-restore-wpf-dependency-value-without-disabling-the-declared-use-of-the-property.html 。古くなった誤った情報に惑わされず、より良い読書体験を得るためです。
私の最新のブログを継続して読みたい方は、RSSフィード をクリックするか、CSDNで私のホームページをフォロー してください。
クリエイティブ・コモンズ・ライセンス この作品は クリエイティブ・コモンズ 表示 - 非営利 - 継承 4.0 国際 ライセンス の下に提供されています。転載、使用、再配布は自由ですが、必ず記事の著者である 吕毅 (リンク: https://blog.walterlv.com )を明記し、営利目的での使用は禁止し、この記事を元に変更した作品は同じライセンスで公開しなければなりません。ご質問がある場合は、私に連絡 (walter.lv@qq.com) してください。