在工具箱中隐藏所有来自程序集的WPF用户控件

4
我希望在我的项目中,将几个程序集中所有编写的WPF用户控件从Visual Studio工具箱中隐藏起来。我知道可以使用[DesignTimeVisible(false)]属性标记每个控件来隐藏它们。但是,是否有另一种解决方案可通过程序集上的一个属性来隐藏所有控件?我不想为每个新控件都打上标记。遗憾的是,该属性无法从其父类继承,因此我甚至不能创建一个具有DesignTimeVisible(false)属性的基础控件。你有什么想法吗?

你打算使用哪个Visual Studio版本? - Il Vic
Visual Studio 2012 - 2015 - 20XX - Mohnkuchenzentrale
1
我不会回答你的问题,但我建议采用另一种方法。使用AOP工具为每个控件添加属性,或者使用IL Weaving(例如Fody)来实现相同的目的。 - Eli Dagan
2个回答

2
作为首选,如果这些控件应该在容器项目中可见,则可以将它们设置为“internal”。根据要求,您可以将它们设置为公共。此外,作为“internal”,它们也可以在友元程序集中使用。
无论如何,如果您正在寻找减少打开/关闭“DesignTimeVisible”的难度的方法,可以考虑以下选项:
选项1
作为一种选择,您可以降低打开/关闭“DesignTimeVisible”属性的难度。您只需一次为所有类装饰上“DesignTimeVisible”,但可以从一个中心点控制其值。
为此,请创建一个类来保存设置:
public class MyGlobalSettings
{
    public const bool DesignTimeVisible = false;
}

然后按照这种方式装饰控件:
[DesignTimeVisible(MyGlobalSettings.DesignTimeVisible)]
public partial class UserControl1 : UserControl

英译中:

然后,要在工具箱中打开/关闭显示控件,只需设置DesignTimeVisible即可。这样,它只是一个单点设置。

选项2

另一种选择是使用T4模板为您的控件生成部分类。在文件中,您可以拥有一个变量,该变量将用作DesignTimeVisible属性的值。然后在T4模板中,使用指定的值装饰所有部分类,并将其标记为DesignTimeVisible。您只需在一个单点更改值即可。

类名可以使用代码自动生成,但在此示例中,我使用了静态类名:

<#@ template debug="false" hostspecific="false" language="C#" #>
<#@ assembly name="System.Core" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ output extension=".cs" #>
<#  var designTimeVisibleValue = "false"; #>
using System.Windows.Controls;
using System.ComponentModel;
namespace WpfCustomControlLibrary1
{
    [DesignTimeVisible(<#=designTimeVisibleValue#>)]
    public partial class UserControl1 : UserControl{}

    [DesignTimeVisible(<#=designTimeVisibleValue#>)]
    public partial class UserControl2 : UserControl{}
}

注意:
正如在评论中提到的,您可以使用像Fody、PostSharp、dIHook等工具来在构建时修改程序集。仅为此要求使用这些库过于繁琐。这些工具可能有很多好处,但仅为此要求使用它们并不是一个好主意。

感谢您的努力,Reza。中央处理真/假是一个很好的点,但仍然需要额外的工作来装饰每个控件,尽管我知道我不想显示其中任何一个 :( - Mohnkuchenzentrale
1
顺便问一下,为什么不把它们设为“internal”? - Reza Aghaei
好点。默认情况下,这样的控件是公共的。我的真实问题是,在解决方案上有大约12-15名开发人员工作,其中一些人简单地忘记隐藏他们的用户控件。因此,每个在解决方案上工作的人在他们的工具箱中都有很多用户控件。我知道这是纪律和惯例的问题,但我认为可能会有一个更全局的解决方案。我猜我们会建立一个代码检查解决方案,每个用户控件都应该是内部的。 - Mohnkuchenzentrale
顺便说一下,如果你对自动T4解决方案感兴趣,请告诉我。正如我所说,这不是我的个人偏好,但它是适用的。 - Reza Aghaei
是的,更好的选择是更改您的项目模板,并询问开发人员默认情况下是否可以将事物设置为内部。感谢反馈 :) - Reza Aghaei
显示剩余5条评论

1

也许我来晚了,但是如果:

  1. 你的控件程序集没有在GAC中注册
  2. 你的控件程序集项目不在你正在工作的解决方案中

那么你可以使用WPF Designer Extensibility。实际上,你可以通过使用属性扩展Visual Studio WPF设计器。

我们需要的属性是ToolboxBrowsableAttribute。这个框架更重要的特性是它允许在一个单独的程序集中(称为设计程序集)为我们的控件定义属性。

所以假设这些是我们的自定义控件:

namespace CustomControls
{
    public class CustomTextBox : TextBox
    {
    }

    public class CustomButton : Button
    {
    }

    public class CustomComboBox : ComboBox
    {
    }
}

自定义控件在名为CustomControls.dll的程序集中;为了给每个控件添加所需的属性,需要创建一个名为CustomControls.Design.dll的新程序集。这个新程序集必须引用以下内容:
  • PresentationCore
  • PresentationFramework
  • System.Xaml
  • WindowsBase
  • Microsoft.Windows.Design.Extensibility
  • Microsoft.Windows.Design.Interaction

在AssemblyInfo中添加以下代码:

[assembly: ProvideMetadata(typeof(CustomControls.Design.Metadata))]

该属性指出哪个类将为设计师提供属性。 因此,让我们来看看 Metadata 类的代码:
namespace CustomControls.Design
{
    public class Metadata : IProvideAttributeTable
    {
        AttributeTable IProvideAttributeTable.AttributeTable
        {
            get
            {
                AttributeTableBuilder builder = new AttributeTableBuilder();
                Assembly assembly = Assembly.GetAssembly(typeof(CustomControls.CustomButton));

                foreach (Type objectType in assembly.GetTypes())
                {
                    if (objectType.IsPublic && typeof(FrameworkElement).IsAssignableFrom(objectType))
                    {
                        builder.AddCustomAttributes(objectType,
                            ToolboxBrowsableAttribute.No);
                    }
                }

                return builder.CreateTable();
            }
        }
    }
}

通过这种方式,我将ToolboxBrowsable属性添加到扩展FrameworkElement类的CustomControl程序集的每个公共对象中,无需逐个装饰每个控件。

CustomControls.Design.dll必须与CustomControls.dll位于同一文件夹中。

您可以在这里找到有用的信息(即使该代码涉及略有不同的参数)。

请注意:如果条件1和条件2都未满足,则此方法无效,并且Reza Aghaei的解决方案可能更适合。

希望能对您有所帮助。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接