5

这是我在 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。

  • 还有一个取消按钮,它基本上重置了上述控件。

当我点击 Cancel 按钮时,我将一个事件从ViewModelRunViewModel发布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”文本框控件不同。

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

ReportFromDtTmHost.Child.Name = ""

而应该是ReportFromDateTime

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

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

建议在“Surrogate Windows Forma Message Loop”部分下重现消息循环。

这是另一个链接,解释了嵌套部分下的嵌套问题。

我为冗长而道歉。只是想让你们清楚地了解我的问题。如果您对帖子有任何疑问,请告诉我。任何建议将不胜感激。

编辑

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

静态 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";
}

这显示了前端的更新值

静态事件聚合器

这个解决方法是由我们的一位同事提供的。

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

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

eventAggregator.GetEvent<ResetDateTimeEvent>.Publish(true);

我们用了:

ResetDateTimeEvent.Instance.Publish(true);

在订阅中:

ResetDateTimeEvent.Instance.Subscribe(ResetDateTimeHandler);

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

所以,我仍然对为什么上述两种情况正在解决问题感到困惑。是解决问题的静态性吗?

正如我已经说过的,我觉得控件正在重新创建,当我们掌握控件时,它们已经重新创建了。

任何建议将不胜感激。

4

1 回答 1

0

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

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

简单的回答:是的,使用单例在 WinForms 代码和 WPF 代码之间共享引用。这些单例可以在 WPF 引导程序中输入到容器中,以便在 WPF 端仍然进行注入。

于 2015-08-26T19:58:09.180 回答