元のすべてのスタイル、バインディング、ユーザー設定値を保持したまま、WPF依存関係プロパティの値を設定および復元する方法

元のすべてのスタイル、バインディング、ユーザー設定値を保持したまま、WPF依存関係プロパティの値を設定および復元する方法

WPFでコントロールのいくつかのプロパティをバックアップし、何らかの操作を行い、その後これらのプロパティを復元します。

最終更新 2021/11/09 10:08
吕毅
読了目安 3 分
カテゴリ
WPF
タグ
.NET WPF

WPFで、あるコントロールのプロパティをバックアップして、何か魔法のような操作をした後、それらのプロパティを復元する。なんてありふれた操作でしょう!しかし、バックアップの方法は検討に値する問題です。直接代入?それはきっと、いくつかの落とし穴を踏んでいないからでしょう。

本記事の内容

  • シナリオと問題
  • 解決方法と原理
  • 発展

シナリオと問題

ここで、あるシナリオを想像してみましょう(コードを書きやすいように):

  1. あるウィンドウがあり、いくつかのスタイルプロパティが設定されている
  2. 今、このウィンドウを全画面に設定する必要があり、そのためにはいくつかの元のプロパティを変更する必要がある(WPF標準の設定にはバグがあり、それについては別のブログ記事で説明します)
  3. ウィンドウの全画面設定を解除した後、以前に変更したプロパティを「完璧に」復元する

一般的には、次のように書くかもしれません:

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) してください。

さらに探索

関連読書

その他の記事
同じカテゴリ / 同じタグ 2025/09/13

WPF から Avalonia への移行シリーズ:なぜ WPF プログラムを Avalonia に移行しなければならないのか

過去数年間、当社の上位機ソフトウェアは主に WPF と WinForm で開発されてきました。これらの技術は Windows プラットフォームで非常に便利であり、小規模試作から現在の規模拡大による納品まで、私たちを支えてきました。しかし、ビジネスの発展や顧客ニーズの変化に伴い、単一の Windows テクノロジースタックは私たちが必ず乗り越えなければならない壁となってきました。

続きを読む
同じカテゴリ / 同じタグ 2025/01/26

WPF カスタムXMLファイルによる国際化

この記事では、WPFプログラムでカスタムXMLファイルを使用して国際化を実現する方法について詳しく説明します。必要なNuGetパッケージのインストール、言語リストの動的取得、言語の動的切り替え、コードおよびXAMLインターフェースでの翻訳文字列の使用などを含み、ソースコードのリンクも提供し、開発者がWPFアプリケーションの国際化を簡単に実装できるように支援します。

続きを読む