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