8

コントロールを使用するときに、ユーザーが XAML で設定した内容に基づいてユーザー コントロールが初期化されるという問題があります。現在、「Loaded」イベントを使用して、ユーザーが設定したかどうかに基づいて動作していました。

ただし、Loaded イベントの使用に関する問題は、このコントロールの別の兄弟が、Loaded イベントを使用して何かを設定していることです。これは、Loaded イベントがまだ発生していないため、まだ完全に初期化れていません。(もしそうなら、これは UI の競合状態です。)

繰り返しますが、WPF システムはコントロールのコンシューマーの XAML によって指定されたプロパティをまだ設定していないため、コードをコンストラクターに移動することはできません。上記の理由により、Loaded イベントは使用できません。初期化も機能していないようです。

ISupportsInitialize も調べましたが、外部からではなく、コントロールのプロパティをバッチ設定する場所であるため、それも適切ではないようです。

考え?

アップデート

これは特に UserControls の異常であることがわかりました。初期化の処理は異なります。こちらのフォローアップの質問で詳細を確認できます...

...しかし、短いバージョンでは、コンストラクターで InitializeComponent を呼び出すと、実際には Initialized イベントが発生しますが、XAML で定義されたプロパティが実際に設定される前に発生します。コメントアウトすると、Initialized が起動したときにプロパティが設定されるようになりましたが、もちろん、コントロールの UI は読み込まれません! 実際にはちょっとイライラします。

まだ解決策を探しています。コード例と詳細は、そこにあります。

4

3 に答える 3

8

[私の他の質問からの回答をここにコピーします。]

すごいソーセージ!私はそれを考え出した!

通常、Initializedイベントを受け取る (またはオーバーライド内にいるOnInitialized) 場合、XAML 設定のプロパティ値にアクセスできます。ただし、UI をハイドレートし、関連するメンバー変数を設定するために呼び出されるUserControlことに依存するため、クラスの動作は少し異なります。InitializeComponent

問題は、呼び出しがコンストラクター内にあることです。これにより、呼び出しが終了しOnInitialized(したがってInitializedイベントが発生します)、XAML セットのプロパティが適用される前に発生します。つまり、まだそれらにアクセスできないことを意味します。必要です。

Loadedこれらのプロパティに基づいて初期化を完了するために、イベントの良い使い方だと思うかもしれませんが、そこで追加の初期化を実行している場合、消費者がLoadedイベントにサブスクライブする場合に、消費者との潜在的な競合状態を作成しています。あなたの前にそれを取得し、ハンドラーであなたのコントロールにアクセスしようとすると、初期化されていないコントロールにアクセスします。

その後、何かが起こりました...上で示したようにInitializeComponent、コンストラクターから呼び出しを削除すると、Initializedイベントは期待どおりに機能しますが、まだ呼び出していないため、もちろん UI はまだハイドレートされていませんInitializeComponent

OnInitializedでは、その呼び出しをオーバーライドの先頭、つまり への呼び出しのbase.OnInitialized前、つまりInitializedイベントが発生する前に移動するとどうなるでしょうか?

うん!それはうまくいきました!:)

Initializedこの方法では、XAML で設定されたプロパティを取得できるだけでなく、(イベントは言うまでもなく)誰かがイベントを取得する前に UI を完全に読み込むこともできますLoaded。これが、イベントのInitialized使用方法です。

以下は修正されたコードです...

public partial class TestControl : UserControl
{
    protected override void OnInitialized(EventArgs e)
    {
        InitializeComponent();
        base.OnInitialized(e);
    }

    public static readonly DependencyProperty TestValueProperty = DependencyProperty.Register(
        "TestValue",
        typeof(string),
        typeof(TestControl),
        new UIPropertyMetadata("Original Value"));

    public string TestValue
    {
        get { return (string)GetValue(TestValueProperty); }
        set { SetValue(TestValueProperty, value); }
    }

}
  • 注: そこで他のことを行う必要がある場合を除き、コンストラクターはもう必要ありません。その場合は、呼び出しの後まで名前で構成要素のコントロールにアクセスできないことを覚えておいてくださいInitializeComponent。ただし、これは、そのような名前ベースの初期化をInitializeComponentとの間で移動することを計画する必要があることを意味し、問題なくbase.OnInitialize動作します。
于 2014-05-21T14:02:16.457 に答える
2

8 か月前の投稿が 2 日前に回答され、私が現在抱えている正確な問題 (ただし、WPF ではなく WinRT XAML を使用) が回答されたのは偶然です。

Image コントロールを含む UserControl で同じ問題が発生しました。UserControl には、変更ハンドラーが Image.Source を新しい BitmapImage に設定するカスタム整数依存関係プロパティがあります (整数値は、表示するイメージを決定します)。

画像が常に適切に表示されるとは限らない競合状態がありました。非常に断続的で、残念ながら、バグのある Win 8.1 および WinPhone 8.1 アプリを公開しました。うーん。

MarqueIV と Sheridanless の貢献に感謝します。

于 2014-05-24T04:17:30.470 に答える