WPF工具箱安装程序,用于在不同程序集中定义的类型

6 wpf user-controls install toolbox visual-studio

我正在尝试为WPF控件创建一个VSIX安装程序.

它应该很简单,但"简单"版本假定您在VSIX项目中创建WPF控件.

问题是,我的UserControl深藏在我的一个DLL中,我不相信把它拉出来是最好的设计.我想把它留在那里,但我似乎无法做到这一点并将控件添加到工具箱中.

一种选择是将我需要的代码移动到工具箱中的控件程序集中,但这会向Microsoft.VisualStudio.Shell.Immutable.10.0.dll添加依赖项.安装了Visual Studio的人和在未安装VS的服务中运行的远程服务器都使用该程序集,因此这是不行的.

我尝试的另一个选项是通过将RegistrationAttribute应用于代理来"欺骗"工具箱安装程序VSIX,代理将注册在另一个程序集中定义的类型.认为它会起作用,但奇怪的事情发生了.

工具箱中的各种怪异

我没有得到两个控件,而是在奇怪命名的选项卡中获得了一堆Border控件(标准的WPF边框),其中一些控件回显了我的一些命名空间.

当在VSIX以外的程序集中定义控件时,如何使用工具箱注册WPF UserControl?

Mat*_*att 2

我能够提出类似于您提到的代理想法的概念证明。

您看到的问题是由错误的程序集注册引起的,因此我创建了一个名为 的新注册属性,ProvideProxyToolboxControlAttribute该属性用作 VS 集成程序集中的代理类的属性。它几乎与 相同,ProvideToolboxControlAttribute只是它采用实际控件的类型。当然,这个新属性也将位于您的 VS 程序集中。

例如,假设我的非 VS 程序集中有一个名为 的工具箱控件MyToolboxControl,我会在 VS 程序集中创建一个简单的代理类MyToolboxControlProxy,如下所示:

[ProvideProxyToolboxControl("MyToolboxControl", typeof(NonVsAssembly.MyToolboxControl))]
public class ToolboxControlProxy
{
}
Run Code Online (Sandbox Code Playgroud)

当然,神奇的事情发生在 中ProvideProxyToolboxControlAttribute,它基本上就是这个类(为简洁起见,删除了注释和参数/错误检查):

[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)]
[System.Runtime.InteropServices.ComVisibleAttribute(false)]
public sealed class ProvideProxyToolboxControlAttribute : RegistrationAttribute
{
    private const string ToolboxControlsInstallerPath = "ToolboxControlsInstaller";
    public ProvideProxyToolboxControlAttribute(string name, Type controlType)
    {
        this.Name = name;
        this.ControlType = controlType;
    }

    private string Name { get; set; }

    private Type ControlType { get; set; }

    public override void Register(RegistrationAttribute.RegistrationContext context)
    {
        using (Key key = context.CreateKey(String.Format(CultureInfo.InvariantCulture, "{0}\\{1}",
                                                         ToolboxControlsInstallerPath,
                                                         ControlType.AssemblyQualifiedName)))
        {
            key.SetValue(String.Empty, this.Name);
            key.SetValue("Codebase", ControlType.Assembly.Location);
            key.SetValue("WPFControls", "1");
        }
    }
    public override void Unregister(RegistrationAttribute.RegistrationContext context)
    {
        if (context != null)
        {
            context.RemoveKey(String.Format(CultureInfo.InvariantCulture, "{0}\\{1}",
                                                         ToolboxControlsInstallerPath,
                                                         ControlType.AssemblyQualifiedName));
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

它似乎工作得很好,我验证了该控件位于工具箱中并且添加了正确的注册表项。

希望这可以帮助!