Hosted Winform控件不响应WPF中的事件



这是我在StackOverflow中的第一个问题。由于缺乏声誉,我无法发布任何链接或图片。我已经为以下问题工作了两天多。如有任何帮助,我们将不胜感激。

在我开始提问之前,以下是我所拥有的和我所期待的:

  • 我有一个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发布到WPF UserControl代码隐藏文件,比如RunView.xaml.cs

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

在代码隐藏文件中,我订阅了如下所示的事件

eventAggregator.GetEvent<ResetDateTimeEvent>().Subscribe(ResetDateTimeHandler);

WPF控件重置为其默认值,但DateTime UserControl不会重置。

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

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

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

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> 

在初始加载时,我正在加载带有Initial Load Text文本的Textbox

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之间的互操作过程中引发问题
我做了很多研究,搜索了很多链接以获取建议。我发现没有人指出这个问题。他们中的一些人关系密切。这里有几个链接:

这建议在"代理Windows Forma消息循环"部分下复制消息循环。

这里还有一个链接解释了嵌套部分下的嵌套问题。

我很抱歉说得太多了。只是想让你们清楚地了解我的问题。如果你对这个帖子有任何问题,请告诉我。如有任何建议,我们将不胜感激。

编辑

我们能够解决这个问题,但这仍然是一个变通办法。以下是我们所做的:有两种方法可以解决这个问题,但都与使用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";
}

这显示前端上的更新值

静态事件聚合器

这项工作是由我们的一位同事提供的。

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

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

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

我们使用过:

ResetDateTimeEvent.Instance.Publish(true);

在订阅中:

ResetDateTimeEvent.Instance.Subscribe(ResetDateTimeHandler);

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

所以,我仍然困惑于为什么以上两种情况能够解决问题。是静态性在解决问题吗?

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

如有任何建议,我们将不胜感激。

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

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

简单的回答是:是的,使用singleton在WinForms代码和WPF代码之间共享引用。这些单线态可以在WPF引导器中输入到容器中,这样注入仍然发生在WPF侧。

最新更新