c# - MVVM MEF WindowFormHost

标签 c# wpf mvvm mef

我目前正在尝试设计一个通过 MEF 导入加载 View 模型的应用程序。

到目前为止一切顺利,我从 viewmodel 导航到 viewmodel,通过字典加载了每个 vm 数据模板。

每次导航时,我都会在我的 Shell (MainWindow) 中修改主要 contentPresenter 的内容。

其中一个 View 模型允许我为 activeX 控件(例如 acrobat reader)显示 WindowFormHost。由于 WindowFormHost 不允许绑定(bind),所以我在 View 模型中创建了 windowFormHost 并将其绑定(bind)到 View 中的 ContentPresenter。

这就是失败的地方:当返回到相同的 View 模型时, View 会再次创建……抛出“元素已经是另一个元素的子元素”。错误。

我怎样才能防止这种情况?重新加载 View 时我应该卸载 WindowFormHost 吗?或者我可以保留 View 实例,以便每个 View 只保留一个实例并让数据绑定(bind)更新控件吗? (它看起来更好的内存消耗)。

谢谢你的帮助 !

[编辑]

加载字典:

<DataTemplate x:Shared="False" DataType="{x:Type vm:DAVPDC3DVIAControlViewModel}">
    <vw:MyUserControl />
</DataTemplate>

看法 :
<DockPanel>
    <ContentControl Name="WFH3DVia" Content="{Binding Path=Control3DVIA, Mode=OneWay} </ContentControl>"
    <!--<WindowsFormsHost Name="WFH3DVia"></WindowsFormsHost>-->
</DockPanel>

虚拟机(单例,mef 模块):
[Export(typeof(IDAVPDC3DVIAControl))]
public partial class DAVPDC3DVIAControlViewModel : ViewModelBase, IViewModel, IPartImportsSatisfiedNotification

虚拟机(主窗口)
[Export]
public class MainWindowViewModel : ViewModelBase, IPartImportsSatisfiedNotification

//CurrentUC 将主窗口 View 绑定(bind)到 Controller 事件 View 模型
    public IViewModel CurrentUC
    {
        get
        {
            return myAddinManager.CurrentVM;
        }
    }

主视图:

Controller (在事件中显示模块):
    private void ModuleReadyEventAction(string iModuleName)
    {
        if (null != this.Modules && this.Modules.Count() > 0)
        {
            foreach (var item in Modules)
            {
                IBaseModule ibasemodule = item as IBaseModule;
                if (null != ibasemodule)
                {
                    Type tp = ibasemodule.GetType();
                    if (0 == tp.Name.CompareTo(iModuleName))
                    {
                        CurrentVM = ibasemodule.GetViewModel();
                        break;
                    }
                }
            }
        }
    }

最佳答案

我还在使用 Prism v4 和 MVVM 开发 WPF 中的一个项目(除了我使用的是 Unity)。我还至少需要使用两个控件,它们是必须托管在 WindowsFormsHost 中的 Windows 窗体控件。让我解释一下我对这个过程的想法..

在我看来,您正试图避免 View 代码中的任何代码。这是我能想到的将 WindowsFormsHost 移动到 ViewModel 中的唯一原因。我认为这从根本上来说是错误的做法。 WindowsFormsHost 的存在是为了显示图形 Windows 窗体控件。因此,它属于 View !

现在,我了解了 DataBindings 的吸引力。相信我,我希望能够对 WindowForms 控件的许多部分进行 DataBind。当然,要接受 WPF 数据绑定(bind),该属性必须是依赖对象上的依赖属性。最简单的解决方案,也不是不合理的,就是在你的 View 后面的代码中简单地添加代码来配置你的窗体控件。在 ViewModel 中添加 UI 逻辑实际上违反了 MVVM 设计模式,而在后面添加代码是 不是。 (在某些情况下是最好的方法)

我已经看到了试图绕过这个限制的可能的黑客攻击。包括使用注入(inject)数据绑定(bind)的“代理”,或者可能扩展 WindowsFormsHost 并添加包装特定托管控件属性的 DependencyProperties,或者使用反射编写类并尝试抛出 Windows 窗体绑定(bind)。但是,我所看到的任何东西都无法完全解决问题。例如,我的 windows 窗体控件可以包含其他图形组件,这些组件也需要支持绑定(bind)。

最简单的方法是简单地将 View 与 View 代码中的 View 模型同步。您的 View 模型可以保留打开的文件或文档、文件名、标题等,但将显示和显示相关控件留给 View 。

最后,让我更直接地评论你的问题。我需要查看您如何使用 MEF 容器注册 View 和 ViewModel,以及您如何导航以了解您收到该错误的原因。在我看来,您的 View 或 View 模型被创建了不止一次,而另一个则没有。这些是否注册为单例类型?无论如何,我坚持我所说的不将 WindowsFormsHost 包含在您的 ViewModel 中。

关于c# - MVVM MEF WindowFormHost,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12849465/

相关文章:

c# - 多个包装器 - 如何做?

c# - 在 WPF 中移动到 Enter 按键上的下一个控件

c# - 将 Canvas 保存为位图

wpf - 如何将 IsHitTestVisible 设置为 True 的某个对象的子项设置为 false?

c# - WPF 现代用户界面 : Changing the width of links

ItemTemplate 命令的 WPF 依赖属性

c# - 如何通过在页面上显示半透明控件来禁用Windows Phone上的所有控件?

c# - 在展开/折叠时禁用 TreeView 节点上的回发

c# - 数据流的 block 设计受阻

c# - "Request format is invalid"