托管的Winform控件不响应来自WPF的事件

raj*_*raj 5 wpf prism mvvm elementhost winforms

这是我在StackOverflow中的第一个问题。由于缺乏声誉,我无法发布任何链接或图像。我处理以下问题已经超过2天。任何帮助将不胜感激。

在我提出问题之前,这是我所拥有的和期望的:

  • 我有一个Windows窗体,该窗体ElementHost控件中承载WPF
  • 然后,我有一个类似于DateTimePicker 的Winforms UserControl。它
    托管在WindowsFormsHost控件中。

由于以下原因,上述情况是不可避免的:

  • 我们所有应用程序的授权对话框都是在Winforms中开发的,并以Winforms实例为参数。尚未引入WPF版本。因此,我必须使用ElementHost在Windows窗体内托管我的视图。
  • 我的WPF中托管的Winforms控件也是不可避免的。我们有自己的DateTime Winforms UserControl,其行为类似于DateTimePicker Winforms控件,但涉及的复杂性更高。因此,用WPF版本替换此控件是毫无疑问的。

预期功能:
我有一个

  • WPF控件(例如,一个文本框)

  • 我上面提到的DateTime Winforms UserControl。

  • 还有一个“取消”按钮,基本上可以重设以上控件。

当我打的取消按钮,我发布从一个事件ViewModel,说RunViewModelWPF用户控件隐藏文件的代码,说RunView.xaml.cs。

eventAggregator.GetEvent<ResetDateTimeEvent>().Publish(true);
Run Code Online (Sandbox Code Playgroud)

在文件背后的代码中,我已订阅该事件,如下所示

eventAggregator.GetEvent<ResetDateTimeEvent>().Subscribe(ResetDateTimeHandler);
Run Code Online (Sandbox Code Playgroud)

WPF控件重置为默认值,但日期时间用户控件 无法复位。

因此,出于测试目的,我删除了ElementHost控件,只使用了带有WindowsFormsHost控件的WPF视图,该控件承载DateTime Winforms UserControl和WPF“取消”按钮。

当我单击按钮时,DateTime控件上的值将重置为其默认值。

然后,我认为这可能是我的DateTime Winforms UserControl的问题。因此,在我的实际应用程序中,我用Winforms Textbox控件替换了DateTime Winforms UserControl 。所以现在嵌套如下:

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> 
Run Code Online (Sandbox Code Playgroud)

在初始加载时,我正在加载Textboxwith Initial Load Text文本

private void Window_Loaded(object sender, EventArgs e)
{
  ReportFromDateTime.Text = "Initial Load Text";
}
Run Code Online (Sandbox Code Playgroud)

正如我上面提到的,当我点击“取消”按钮时,会发生以下情况:

  • 从ViewModel发布事件

    eventAggregator.GetEvent()。Publish(true);

  • 在文件(xaml.cs)后面的代码中订阅事件:

    eventAggregator.GetEvent()。Subscribe(ResetDateTimeHandler);

  • 已发布事件的EventHandler。

    私人无效ResetDateTimeHandler(bool cancelClicked){ReportFromDateTime.Text =“重置为默认”; }

如您在上面的代码中看到的,我在单击“取消”按钮时重置了“文本”。

在调试过程中,我可以看到Text属性已更改为“ Reset to Default”,但UI并未显示这些更改。

这是奇怪的部分:

儿童在WindowsFormsHost控件属性是从实际的“ReportFromDateTime”文本框控件不同。

调试时,我可以看到WindowsFormsHost控件上的Child和Name属性是不同的。Name属性为空,

ReportFromDtTmHost.Child.Name = ""
Run Code Online (Sandbox Code Playgroud)

而是应该是ReportFromDateTime

似乎主机和子控件正在重新创建。

据我所知,我认为嵌套的额外级别(WinForms-ElementHost-WPF-WindowsFormsHost-Winforms文本框)可能会在WPF和Winforms之间的互操作期间引起问题。
我已经做了很多研究,并在很多链接中搜索了建议。我发现没有人指出这个问题。他们中有些接近。这里有几个链接:

这表明重现“代孕视窗FORMA消息循环”部分下消息循环。

在“嵌套”部分下,还有一个链接说明了嵌套问题。

我很抱歉。只是希望你们能清楚地了解我的问题。如果您对此帖子有任何疑问,请告诉我。任何建议将不胜感激。

编辑

我们能够解决此问题,但是仍然可以解决。这是我们所做的事情:有两种方法可以解决此问题,但是两种方法都与使用静态方法有关。

静态Winforms控件:

我们使用了以下静态Winforms控件

public static class ControlHolder
{
  public static TextBox ReportFromDateTimeInstance;
}
Run Code Online (Sandbox Code Playgroud)

在“实际”控件的OnChanged事件中,我们将实际控件ReportFromDateTime转储到静态控件ReportFromDateTimeInstance。

private void ReportFromDateTime_TextChanged(object sender, EventArgs e)
{
  ControlHolder.ReportFromDateTimeInstance = (TextBox)sender;
}
Run Code Online (Sandbox Code Playgroud)

从那时起,无论我们在哪里更新实际控件(如ResetDateTimeHandler方法),我们都将更新静态控件

private void ResetDateTimeHandler(bool cancelClicked)
{
  ControlHolder.ReportFromDateTimeInstance = "Text changed";
}
Run Code Online (Sandbox Code Playgroud)

这显示了前端的更新值

静态EventAggregator

此变通办法是由我们的一位同事提供的。

在这种情况下,我们使用的是实际控件ReportFromDateTime,而不是静态控件,ControlHolder.ReportFromDateTimeInstance

我们使用静态事件聚合器来发布/订阅ResetDateTimeEvent,而不是使用Unity Container提供的Event Aggregator实例。所以,代替

eventAggregator.GetEvent<ResetDateTimeEvent>.Publish(true);
Run Code Online (Sandbox Code Playgroud)

我们用了:

ResetDateTimeEvent.Instance.Publish(true);
Run Code Online (Sandbox Code Playgroud)

并在订阅中:

ResetDateTimeEvent.Instance.Subscribe(ResetDateTimeHandler);
Run Code Online (Sandbox Code Playgroud)

我知道在这种情况下我们不需要使用静态事件聚合器,因为我们使用的是Unity Container提供的实例(可确保所有ViewModel共享一个实例),但这也解决了该问题。

因此,对于上述两种情况为什么能解决问题,我仍然感到困惑。这是不是静态的,其解决问题-ness?

就像我已经说过的那样,我觉得控件正在被重新创建,并且当我们手头有控件时,它们已经被重新创建了。

任何建议将不胜感激。

out*_*red 0

我之前在一个 WinForms 控件内有 WPF 控件的应用程序中做过同样的事情。WPF 使用 Prism/Unity(后来改用 MEF)来启动一切。然而,这默认在引导程序中创建了一个全新的 EventAggregator,因此我用静态的 IEventAggregator 覆盖了容器中的默认 IEventAggregator,因为 WinForm 端已经创建并且正在使用其自己的 IEventAggregator 实例。症状类似,未收到已发布的事件。

在像您这样的混合系统中,单例非常适合确保所有内容都来自相同的引用,特别是当您的启动处于阶段性阶段时(WinForms 然后是 WPF)。

简单的答案:是的,使用单例在 WinForms 代码和 WPF 代码之间共享引用。这些单例可以被送入 WPF 引导程序中的容器中,以便注入仍然发生在 WPF 端。