这是我在StackOverflow中的第一个问题。由于缺乏声誉,我无法发布任何链接或图像。
我已经处理以下问题超过2天了。任何帮助将不胜感激。
在我提出问题之前,这是我所拥有的和期望的:
托管在 WindowsFormsHost 控件中。
由于以下原因,上述情况是不可避免的:
Winforms,并将Winforms实例作为其参数。没有
WPF版本尚未推出。因此,我不得不使用ElementHost来
在Windows窗体中托管我的 View 。
有我们自己的DateTime Winforms UserControl,其行为类似于
DateTimePicker Winforms控件,但复杂得多
涉及。因此,用WPF版本替换此控件已成问题
问题。
预期功能:
我有一个
当我单击“取消”按钮时,我正在发布
ViewModel
中的事件,例如 RunViewModel 到文件后面的 WPF UserControl 代码,例如 RunView.xaml.cs。 eventAggregator.GetEvent<ResetDateTimeEvent>().Publish(true);
在文件背后的代码中,我已订阅该事件,如下所示
eventAggregator.GetEvent<ResetDateTimeEvent>().Subscribe(ResetDateTimeHandler);
WPF 控件重置为默认值,但是 DateTime用户控件 不会重置。
因此,出于测试目的,我删除了ElementHost控件,并使用带有WindowsFormsHost控件的WPF View ,该控件承载DateTime Winforms UserControl和WPF“取消”按钮。
当我单击按钮时,DateTime控件上的值会将重置为其默认值。
然后,我认为这可能是DateTime Winforms UserControl的问题。
因此,在我的实际应用程序中,我用 Winforms 文本框控件替换了DateTime Winforms UserControl的。所以现在嵌套如下:
WinForms-ElementHost-WPF-WindowsFormsHost-Winforms Textbox
这是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";
}
正如我上面提到的,当我按下“取消”按钮时,会发生以下情况:
eventAggregator.GetEvent()。Publish(true);
eventAggregator.GetEvent()。Subscribe(ResetDateTimeHandler);
私有(private)void ResetDateTimeHandler(bool cancelClicked)
{
ReportFromDateTime.Text =“重置为默认值”;
正如您在上面的代码中看到的那样,我在单击“取消”按钮时重置了“文本”。
在调试期间,我可以看到Text属性已更改为的“重置为默认值”,但UI并未显示这些更改。
这是奇怪的部分:
WindowsFormsHost控件上的子属性与实际的“ReportFromDateTime”文本框控件不同。
调试时,我可以看到WindowsFormsHost控件上的Child和Name属性是不同的。
Name属性为空,
ReportFromDtTmHost.Child.Name = ""
而是应该为 ReportFromDateTime 。
似乎主机和子控件正在重新创建。
据我所知,我认为嵌套(WinForms-ElementHost-WPF-WindowsFormsHost-Winforms文本框)的额外级别可能会在WPF和Winforms之间的互操作期间引起问题。
我做了很多研究,并在很多链接中搜索了建议。我发现没有人指出这个问题。他们中有些接近。这里有几个链接:
this suggests在“Surrogate Windows Forma消息循环”部分下重现消息循环。
Here is one more link在“嵌套”部分下说明了嵌套问题。
我很抱歉。只是希望你们能清楚地了解我的问题。如果您对此帖子有任何疑问,请告诉我。任何建议将不胜感激。
编辑:
我们能够解决此问题,但是仍然可以解决。这是我们所做的:
有两种方法可以解决此问题,但都与使用静态方法有关。
静态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
此变通办法是由我们的一位同事提供的。
在这种情况下,我们使用的是实际控件 ReportFromDateTime ,而不是静态控件
ControlHolder.ReportFromDateTimeInstance
我们使用静态事件聚合器来发布/订阅ResetDateTimeEvent,而不是使用Unity Container提供的Event Aggregator实例。所以,代替
eventAggregator.GetEvent<ResetDateTimeEvent>.Publish(true);
我们用了:
ResetDateTimeEvent.Instance.Publish(true);
并在订阅中:
ResetDateTimeEvent.Instance.Subscribe(ResetDateTimeHandler);
我知道在这种情况下我们不需要使用静态事件聚合器,因为我们使用的是Unity Container提供的实例(可确保所有ViewModel共享一个实例),但这也解决了该问题。
因此,对于上述两种情况为什么能解决问题,我仍然感到困惑。解决问题的是静态 -ness吗?
就像我已经说过的那样,我感觉控件正在重新创建的,并且到我们手头的控件出现时,它们已经被重新创建了。
任何建议将不胜感激。
最佳答案
在之前在WinForms控件中具有WPF控件的应用程序中,我已经做过同样的事情。 WPF使用Prism/Unity(后来切换为MEF)来启动一切。但是,默认情况下,这会在 bootstrap 中创建一个全新的EventAggregator,因此我已使用静态的b/c(已创建WinForm端并正在使用其自己的IEventAggregator实例)覆盖了容器中的默认IEventAggregator。症状类似,因为未收到已发布的事件。
在像您这样的混合系统中,单例非常适合确保所有内容都来自同一引用,尤其是在启动阶段(WinForms然后是WPF)时。
简单的答案:是的,对WinForms代码和WPF代码之间的共享引用使用单例。可以将这些单例内容放入WPF bootstrap 的容器中,以便仍然在WPF一侧进行注入(inject)。
关于wpf - 托管的Winform控件不响应来自WPF的事件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28957228/