raj*_*raj 5 wpf prism mvvm elementhost winforms
这是我在StackOverflow中的第一个问题。由于缺乏声誉,我无法发布任何链接或图像。我处理以下问题已经超过2天。任何帮助将不胜感激。
在我提出问题之前,这是我所拥有的和期望的:
由于以下原因,上述情况是不可避免的:
预期功能:
我有一个
WPF控件(例如,一个文本框)
我上面提到的DateTime Winforms UserControl。
还有一个“取消”按钮,基本上可以重设以上控件。
当我打的取消按钮,我发布从一个事件ViewModel,说RunViewModel到WPF用户控件隐藏文件的代码,说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?
就像我已经说过的那样,我觉得控件正在被重新创建,并且当我们手头有控件时,它们已经被重新创建了。
任何建议将不胜感激。
我之前在一个 WinForms 控件内有 WPF 控件的应用程序中做过同样的事情。WPF 使用 Prism/Unity(后来改用 MEF)来启动一切。然而,这默认在引导程序中创建了一个全新的 EventAggregator,因此我用静态的 IEventAggregator 覆盖了容器中的默认 IEventAggregator,因为 WinForm 端已经创建并且正在使用其自己的 IEventAggregator 实例。症状类似,未收到已发布的事件。
在像您这样的混合系统中,单例非常适合确保所有内容都来自相同的引用,特别是当您的启动处于阶段性阶段时(WinForms 然后是 WPF)。
简单的答案:是的,使用单例在 WinForms 代码和 WPF 代码之间共享引用。这些单例可以被送入 WPF 引导程序中的容器中,以便注入仍然发生在 WPF 端。