C# 需要从.NET Winforms控件的PropertyGrid隐藏仅设计器属性

C# 需要从.NET Winforms控件的PropertyGrid隐藏仅设计器属性,c#,.net,winforms,windows-forms-designer,design-surface,C#,.net,Winforms,Windows Forms Designer,Design Surface,我深入研究了在我的C#/.NET解决方案中使用Winforms designer(System.ComponentModel.Design命名空间),以便我的用户能够访问我正在运行的应用程序中的表单设计器。大部分工作正常,但我遇到了一个非常具体的问题:我在Microsoft控件上遇到了一个只在设计时出现的属性,即控件的设计时实例。我希望抑制该属性,以便用户在将该控件的实例放置在我的程序的Winform设计图面实现上时无法修改该属性 详细信息:当用户将控件从工具箱拖放到设计器表面时,我会确保选中该

我深入研究了在我的C#/.NET解决方案中使用Winforms designer(System.ComponentModel.Design命名空间),以便我的用户能够访问我正在运行的应用程序中的表单设计器。大部分工作正常,但我遇到了一个非常具体的问题:我在Microsoft控件上遇到了一个只在设计时出现的属性,即控件的设计时实例。我希望抑制该属性,以便用户在将该控件的实例放置在我的程序的Winform设计图面实现上时无法修改该属性

详细信息:当用户将控件从工具箱拖放到设计器表面时,我会确保选中该控件新添加的设计器实例(以便它显示调整大小句柄,并使属性网格显示该控件的设计时属性)。我使用选择服务的GetSelectedComponents()方法将设计器图面上的选定对象绑定到属性网格,并将属性网格的SelectedObjects属性指定给结果

我工具箱中的许多控件都是.NET控件。其中之一是.NET WinformsTableLayoutPanel控件。将该控件的实例放置在设计器图面上时,将在绑定的PropertyGrid中看到一个Columns属性。我希望抑制该属性,以便它不会出现在属性网格中

问题是此Columns属性似乎不存在于TableLayoutPanel类型的属性列表中,因此使用
selectedComponents[0].GetType().GetProperties()
,例如,不包含Columns属性。此外,我无法为现有的Columns属性创建新属性或替代属性,因为它在设计时未显示为TableLayoutPanel控件的公开属性,因此我无法使用
Browsable(false)
属性对其进行修饰

我似乎无法利用
PreFilterProperties
PostFilterProperties
,因为我无法交互和自定义TableLayoutPanel的设计器


如何抑制TableLayoutPanel设计器属性,使其不出现在属性网格中,而无需编写自己的设计器?

如果您试图避免自己编写
TableLayoutPanelDesigner
,那么,我可以提出一个解决办法

是负责调用设计器方法的接口。该类在其
ServiceContainer
中注册了该接口实现的实例。因此,您可以删除现有的已注册实例,并注册自己实现的
ITypeScriptorFilterService
的新实例

在新的实现中,重写
FilterProperties
并执行您认为合适的操作,例如,您可以检查组件的类型是否为
TableLayoutPanel
,然后不要调用其设计器
预过滤器属性

然后,为了总结解决方案,您需要通过从
DesignSurface
类派生并删除已注册的
ITypeDescriptorFilterService
并注册您创建的所需实例来创建自己的设计图面

示例

仅供参考,您要查找的属性的名称是
ColumnStyles
,默认情况下它具有
Browsable(false)
属性。但是
TableLayoutPanel
的默认设计器将用可浏览的版本替换此属性

我在本例中所做的是阻止设计器使这些属性可见

首先提供
ITypeDescriptorFilterService
的自定义实现。下面的一个实际上是
系统中现有的实现。设计
程序集,我已更改其
过滤器属性
方法,并检查组件是否为
TableLayoutPanel
,我没有要求执行任何操作

using System;
using System.Collections;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Windows.Forms;
public class TypeDescriptorFilterService : ITypeDescriptorFilterService
{
    internal TypeDescriptorFilterService()
    {
    }

    private IDesigner GetDesigner(IComponent component)
    {
        ISite site = component.Site;
        if (site != null)
        {
            IDesignerHost service = site.GetService(typeof(IDesignerHost)) as IDesignerHost;
            if (service != null)
                return service.GetDesigner(component);
        }
        return (IDesigner)null;
    }

    bool ITypeDescriptorFilterService.FilterAttributes(IComponent component, IDictionary attributes)
    {
        if (component == null)
            throw new ArgumentNullException("component");
        if (attributes == null)
            throw new ArgumentNullException("attributes");
        IDesigner designer = this.GetDesigner(component);
        if (designer is IDesignerFilter)
        {
            ((IDesignerFilter)designer).PreFilterAttributes(attributes);
            ((IDesignerFilter)designer).PostFilterAttributes(attributes);
        }
        return designer != null;
    }

    bool ITypeDescriptorFilterService.FilterEvents(IComponent component, IDictionary events)
    {
        if (component == null)
            throw new ArgumentNullException("component");
        if (events == null)
            throw new ArgumentNullException("events");
        IDesigner designer = this.GetDesigner(component);
        if (designer is IDesignerFilter)
        {
            ((IDesignerFilter)designer).PreFilterEvents(events);
            ((IDesignerFilter)designer).PostFilterEvents(events);
        }
        return designer != null;
    }

    bool ITypeDescriptorFilterService.FilterProperties(IComponent component, IDictionary properties)
    {
        if (component == null)
            throw new ArgumentNullException("component");
        if (properties == null)
            throw new ArgumentNullException("properties");
        if (typeof(TableLayoutPanel).IsAssignableFrom(component.GetType()))
            return true;
        IDesigner designer = this.GetDesigner(component);
        if (designer is IDesignerFilter)
        {
            ((IDesignerFilter)designer).PreFilterProperties(properties);
            ((IDesignerFilter)designer).PostFilterProperties(properties);
        }
        return designer != null;
    }
}
然后通过从
DesignSurface
派生来创建设计图面:

using System;
using System.Collections;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Windows.Forms;
public class MyDesignSurface : DesignSurface
{
    public MyDesignSurface() : base()
    {
        this.ServiceContainer.RemoveService(typeof(ITypeDescriptorFilterService));
        this.ServiceContainer.AddService(typeof(ITypeDescriptorFilterService), new TypeDescriptorFilterService());
    }
}
然后,例如,通过以下方式初始化设计图面:

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
        var surface = new MyDesignSurface();
        var host = (IDesignerHost)surface.GetService(typeof(IDesignerHost));
        var selectionService = (ISelectionService)surface.GetService(typeof(ISelectionService));
        surface.BeginLoad(typeof(Form));
        var root = (Form)host.RootComponent;
        var tableLayoutPanel1 = (Control)host.CreateComponent(typeof(TableLayoutPanel), "tableLayoutPanel1");
        root.Controls.Add(tableLayoutPanel1);
        var view = (Control)surface.View;
        view.Dock = DockStyle.Fill;
        this.Controls.Add(view);
        selectionService.SetSelectedComponents(new[] { tableLayoutPanel1 });
        var propertyGrid1 = new PropertyGrid() { Dock = DockStyle.Right, Width = 200 };
        this.Controls.Add(propertyGrid1);
        propertyGrid1.SelectedObjects = selectionService.GetSelectedComponents().Cast<object>().ToArray();
    }
}
公共部分类表单1:表单
{
公共表格1()
{
初始化组件();
var surface=新的MyDesignSurface();
var host=(IDesignerHost)surface.GetService(typeof(IDesignerHost));
var selectionService=(ISelectionService)surface.GetService(typeof(ISelectionService));
表面。开始加载(类型(形式));
var root=(Form)host.RootComponent;
var tableLayoutPanel1=(Control)host.CreateComponent(typeof(TableLayoutPanel),“tableLayoutPanel1”);
添加(tableLayoutPanel1);
var view=(Control)surface.view;
view.Dock=DockStyle.Fill;
this.Controls.Add(视图);
selectionService.SetSelectedComponents(新[]{tableLayoutPanel1});
var propertyGrid1=new PropertyGrid(){Dock=DockStyle.Right,Width=200};
this.Controls.Add(propertyGrid1);
propertyGrid1.SelectedObjects=selectionService.GetSelectedComponents().Cast().ToArray();
}
}
然后运行designer应用程序,您将看到
属性按预期隐藏


您需要隐藏
ColumnCount
RowCount
属性,以及指定用于编辑/添加/删除列和行的谓词。

如果有帮助,属性名称为
ColumnStyles
Columns
是它的显示名。哇,我没有想到这一点,我很惊讶微软决定将ColumnStyles作为属性名而不是ColumnStyles(我想知道他们为什么这么做)