首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >NET Core 3.1 WinForms设计器与WPF用户控件不兼容

NET Core 3.1 WinForms设计器与WPF用户控件不兼容
EN

Stack Overflow用户
提问于 2021-04-14 20:50:47
回答 1查看 828关注 0票数 2

一年多前,我开始使用Windows编写.NET Framework4.6.1应用程序。当时我知道WPF,但熟悉Windows窗体,它拥有我所需要的大多数控件。对于缺少的控件,我用Windows窗体编写了两个控件,用WPF编写了一个控件。所有这些都很好地共存,WPF控件被包含在一个元素主机中。

本周,我开始了向.NET Core3.1的迁移过程。我对项目副本的测试是阳性的,以及实际迁移的初步结果。在小规模重构之后,解决方案构建并运行,没有问题。然后,gremlin在WinForms设计器中打开主UI表单后出现。回到.NET框架中,我所有的自定义控件都出现在设计器的工具箱中,可以方便地拖放到窗体上。在.NET核心中,只有我的WinForms控件出现在工具箱中,而不是我的WPF控件中。由于设计器看不到该控件,因此它从窗体的设计器代码中删除它,留下一个空的元素宿主。

这是铁杆。在还原设计器的更改后,任何直接手工编辑表单的设计器代码都会被接受,并且生成项目会成功并运行良好。因此,出于某种原因,设计人员不喜欢WinForms中的WPF控件。

我尝试过的事情:

  • 在我的测试中,我发现主WinForms UI需要将"UseWindowsForms“和"UseWPF”设置为"true“才能编译。然后,我将"UseWindowsForms“参数添加到WPF用户控件库中。这导致控件出现在设计器的工具箱中,但试图添加控件却导致此错误:“未能创建组件..确保该类型实现IComponent并提供适当的公共构造函数。适当的构造函数要么不接受参数,要么接受单个IContainer参数。”代码中的和现有的WPF控件仍然被删除。
  • 我将WPF控件从库复制到主UI项目,编辑命名空间,并删除库项目引用。结果和上面一样。
  • 创建一个新的库,将"UseWPF“添加到项目中,并将WPF控件复制到此库中。结果和上面一样。
  • 回到我的项目的测试副本,我遵循了微软的“尝试转换”和“升级助手”指南。后者一开始似乎很有希望,因为它取代、修改或删除了过时的参考和软件包。但是没有成功。
  • 使用.NET Core3.1和.NET 5尝试了上述迁移步骤,结果相同。

我现在的重点是继续手工编辑表单的设计器代码。对于大型更改并不理想,如果/当此项目传递给另一个开发人员时,也是不可持续的。有什么想法吗?我是否应该尝试将Windows窗体UI移植到WPF?或者这仅仅是一个相对较新的.NET核心Windows设计器的成熟度问题?

Visual版本:社区2019 16.9.3

IComponent错误的截图:在这里输入图像描述

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-04-28 13:22:08

我终于想出了一个解决办法;这个想法是由ElementHost控件的Microsoft Docs页面:https://learn.microsoft.com/en-us/dotnet/api/system.windows.forms.integration.elementhost?view=netcore-3.1引发的。

本质上,将托管的WPF控件从主UI移动到WinForms控件库中。因此,这个WinForms控件库中的用户控件将是WPF控件的包装器。下面是我在测试和解决方案中所采取的步骤:

  1. 从我在测试期间添加的主UI项目文件中删除"true“条目。
  2. 在新的WinForms控件库中,将"true“添加到"true”条目下的该项目文件中。这使得库能够成为两个UI框架之间的桥梁。
  3. 如果要宿主的WPF控件位于专用控件库中(如我的控件库),则将此项目作为依赖项添加到WinForms控件库中。
  4. 在WinForms库中创建一个新的用户控件(如果还没有)。
  5. 在设计器中,将面板容器添加到控件中,并使用“填充”停靠。我把我的小组命名为"panelWpf“。
  6. 这里是Microsoft Doc进来的地方。在WinForms控件背后的代码中,我首先添加了一个ElementHost控件和WPF控件作为私有全局变量。然后,在WinForms "Load“事件中,我设置了ElementHost停靠样式,将WPF作为子级添加,最后将ElementHost作为控件添加到"panelWpf”容器中。下面是该文件的代码。"WpfControlLibrary31“是我的WPF控件库项目,"TestControl31”是WPF控件本身。最后,"WpfTest“是包装器WinForms用户控件的名称。
  7. 在构建WinForms控件库之后,它出现在主UI项目的工具箱中,我可以像其他任何WinForms控件一样将它添加到窗体中。接下来的步骤将是为所需的交互向控件添加事件处理程序、getter、setter等。
代码语言:javascript
运行
复制
using System;
using System.Windows.Forms;
using System.Windows.Forms.Integration;


namespace WinFormsLibrary
{
    public partial class WpfTest : UserControl
    {
        // ElementHost for the WPF control
        private ElementHost host = new ElementHost();
        // WPF control to be hosted
        private WpfControlLibrary31.TestControl31 uc = new WpfControlLibrary31.TestControl31();

        public WpfTest()
        {
            InitializeComponent();
        }

        private void WpfTest_Load(object sender, EventArgs e)
        {
            // set the docking style for the ElementHost
            host.Dock = DockStyle.Fill;

            // add the WPF control as a child of ElementHost
            host.Child = uc;

            // add the ElementHost as a control of the panel container
            panelWpf.Controls.Add(host);
        }
    }
}

Thoughts

  1. 有些人可能想知道为什么我使用面板容器。在这个简单的实验中,它太过分了;我本可以简单地将ElementHost停靠到控件本身。但是,如果WinForms用户控件有一个更复杂的设计,那么面板将是一个占位符,同时仍然允许使用设计器。另外,如果在WPF控件周围需要一个边框或类似的设计,那么这在面板上应该是可能的。
  2. 将ElementHost和WPF控件对象作为全局对象允许访问所有控件的方法,显然,就像添加到设计器本身中的任何控件一样。
  3. 要宿主的WPF控件不需要位于专用的WPF控件库项目中。如果它是一个预先存在的WPF控件(例如MediaElement),那么将它用于全局WPF对象。
  4. 我一直需要这个WinForms控件库来巩固和提高自定义控件的效率。因此,与.NET核心WinForms设计人员的这一问题被证明是一种伪装的福气。

你的想法是什么?谢谢你的集思广益!

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/67098947

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档