これは、StackOverflow での最初の質問です。評判が悪いため、リンクや画像を投稿できませんでした。私は次の問題に 2 日以上取り組んできました。どんな助けでも大歓迎です。
質問に入る前に、私が持っているものと期待しているものは次のとおりです。
- ElementHostコントロール でWPFをホストするWindows フォームがあります。
- そして、DateTimePicker に似たWinforms UserControlがあります。これは、 WindowsFormsHostコントロール
内でホストされます。
上記のシナリオは、次の理由により避けられません。
- すべてのアプリケーションへの認証ダイアログは Winforms で開発されており、Winforms インスタンスをパラメーターとして取ります。WPF のバージョンはまだ導入されていません。したがって、ElementHost を使用して Windows フォーム内でビューをホストする必要がありました。
- 私の WPF 内でホストされている Winforms コントロールも避けられません。DateTimePicker Winforms コントロールと同様に動作する独自の DateTime Winforms UserControl がありますが、より複雑な操作が必要です。したがって、このコントロールを WPF バージョンに置き換えることは論外です。
期待される機能
:
WPF コントロール (たとえば、テキスト ボックス)
上で言及した DateTime Winforms UserControl。
そして基本的に上記のコントロールをリセットするキャンセルボタン。
[キャンセル] ボタンをクリックするとViewModel
、たとえばRunViewModelからWPF UserControlコード ビハインド ファイル (たとえばRunView.xaml.cs) にイベントが発行されます。
eventAggregator.GetEvent<ResetDateTimeEvent>().Publish(true);
コード ビハインド ファイルでは、次のようにイベントをサブスクライブしました。
eventAggregator.GetEvent<ResetDateTimeEvent>().Subscribe(ResetDateTimeHandler);
WPFコントロールはデフォルト値にリセットされますが、DateTime UserControlはリセットされ ません。
したがって、テスト目的で、ElementHost コントロールを削除し、WPF ビューに、DateTime Winforms UserControl をホストする WindowsFormsHost コントロールと、WPF の [キャンセル] ボタンを追加しました。
ボタンをクリックすると、DateTime コントロールの値がデフォルト値にリセットされます。
次に、これは私の DateTime Winforms UserControl の問題であると考えました。そこで、実際のアプリケーションでDateTime Winforms UserControl をWinforms Textboxコントロールに置き換えました。したがって、ネストは次のようになります。
WinForms-ElementHost-WPF-WindowsFormsHost-Winforms テキストボックス
これがxamlコードです。
<WindowsFormsHost x:Name="ReportFromDtTmHost" Margin="8,0" Grid.Column="0"
LostFocus="ReportFromDtTmHost_LostFocus">
<WindowsFormsHost.Child>
<winforms:TextBox x:Name="ReportFromDateTime"/>
</WindowsFormsHost.Child>
</WindowsFormsHost>
初期ロードでは、テキストをロードTextbox
していますInitial Load Text
private void Window_Loaded(object sender, EventArgs e)
{
ReportFromDateTime.Text = "Initial Load Text";
}
上で述べたように、[キャンセル] ボタンを押すと、次のようになります。
ViewModel からイベントを発行する
eventAggregator.GetEvent().Publish(true);
コード ビハインド ファイル (xaml.cs) でイベントをサブスクライブします。
eventAggregator.GetEvent().Subscribe(ResetDateTimeHandler);
パブリッシュされたイベントの EventHandler。
private void ResetDateTimeHandler(bool cancelClicked) { ReportFromDateTime.Text = "デフォルトにリセット"; }
上記のコードでわかるように、[キャンセル] ボタンをクリックするとテキストがリセットされます。
デバッグ中に、Text プロパティが「デフォルトにリセット」に変更されているのを確認できましたが、UI にはこれらの変更が表示されません。
ここに奇妙な部分があります:
WindowsFormsHost コントロールのChildプロパティは、実際の "ReportFromDateTime" Textbox コントロールとは異なります。
デバッグ中に、WindowsFormsHost コントロールの Child プロパティと Name プロパティが異なることがわかりました。Name プロパティが空です。
ReportFromDtTmHost.Child.Name = ""
むしろReportFromDateTimeである必要があります。
Host コントロールと Child コントロールが再作成されているようです。
私が見る限り、追加レベルのネスト(WinForms-ElementHost-WPF-WindowsFormsHost-Winforms Textbox)が、WPF と Winforms 間の相互運用中に問題を引き起こしている可能性があると思います。
私は多くの調査を行い、提案のために多くのリンクを検索しました。この問題を指摘しているものはありませんでした。それらのいくつかは近くにありました。ここにいくつかのリンクがあります:
これは、「Surrogate Windows Forma Message Loop」セクションでメッセージ ループを再現することを示唆しています。
ネスティングセクションの下のネスティングの問題を説明するもう1つのリンクがあります。
冗長で申し訳ありません。私の問題を明確に理解してもらいたかっただけです。投稿に関してご不明な点がございましたら、お気軽にお問い合わせください。どんな提案でも大歓迎です。
編集:
この問題は解決できましたが、それでも回避策です。この問題を解決するには 2 つの方法がありましたが、どちらも static の使用に関連していました。
静的 Winforms コントロール:
次の静的 Winforms コントロールを使用しました
public static class ControlHolder
{
public static TextBox ReportFromDateTimeInstance;
}
「実際の」コントロールのOnChangedイベントでは、実際のコントロール ReportFromDateTime を静的コントロール ReportFromDateTimeInstance にダンプします。
private void ReportFromDateTime_TextChanged(object sender, EventArgs e)
{
ControlHolder.ReportFromDateTimeInstance = (TextBox)sender;
}
それ以降、(メソッドのように)実際のコントロールを更新するたびに、静的コントロールを更新します。ResetDateTimeHandler
private void ResetDateTimeHandler(bool cancelClicked)
{
ControlHolder.ReportFromDateTimeInstance = "Text changed";
}
これは、フロントエンドで更新された値を示しています
静的 EventAggregator
この回避策は、同僚の 1 人によって提供されました。
この場合、静的コントロールではなく、実際のコントロールReportFromDateTimeを使用しています。ControlHolder.ReportFromDateTimeInstance
Unity Container が提供するイベント アグリゲーター インスタンスを使用する代わりに、ResetDateTimeEvent の発行/サブスクライブに静的イベント アグリゲーターを使用しました。だから、代わりに
eventAggregator.GetEvent<ResetDateTimeEvent>.Publish(true);
使用したもの:
ResetDateTimeEvent.Instance.Publish(true);
そしてサブスクリプションで:
ResetDateTimeEvent.Instance.Subscribe(ResetDateTimeHandler);
Unity Container によって提供されるインスタンスを使用しているため (これにより、単一のインスタンスがすべての ViewModel で共有されるようになります)、このシナリオでは静的イベント アグリゲーターを使用する必要がないことはわかっていますが、これにより問題も解決されました。
そのため、上記の 2 つのシナリオで問題が解決される理由について、私はまだ混乱しています。問題を解決しているのは静的ですか?
すでに述べたように、コントロールが再作成されていると感じており、コントロールを手にするまでに、それらはすでに再作成されています。
どんな提案でも大歓迎です。