需要从 PropertyGrid 为 .NET Winforms 控件隐藏设计器专用属性 [英] Need To Hide A Designer-Only Property From PropertyGrid For A .NET Winforms Control

查看:43
本文介绍了需要从 PropertyGrid 为 .NET Winforms 控件隐藏设计器专用属性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我深入研究在我的 C#/.NET 解决方案中使用 Winforms 设计器(System.ComponentModel.Design 命名空间),以便我的用户可以访问我正在运行的应用程序中的表单设计器.其中大部分都运行良好,但我遇到了一个非常具体的问题:我在 Microsoft 控件上遇到了一个仅在设计时出现的属性——即,对于控件的设计时实例.我想取消该属性,以便用户在我的 Winform 设计图面的程序实现上放置该控件的实例时无法修改它.

I am deep into using the Winforms designer (System.ComponentModel.Design namespace) in my C#/.NET solution so that my users have access to a form designer within my running application. Much of it works well, but I ran into a very specific problem: I encountered a property on a Microsoft control that appears only during design-time--i.e., for the design-time instance of the control. I want to suppress that property so that users cannot modify it when they place an instance of that control on my program's implementation of the Winform design surface.

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

Details: When a user drag-and-drops a control from the toolbox to the designer surface, I ensure that the newly added designer instance of the control is selected (so that it present resize handles and so the property grid displays that control's design-time properties). I bind the selected objects on the designer surface to the property grid by using the selection service's GetSelectedComponents() method and assigning the property grid's SelectedObjects property to the result.

我工具箱上的许多控件都是 .NET 控件.其中之一是 .NET Winforms TableLayoutPanel 控件.当您在设计器界面上放置该控件的实例时,您将在绑定的 PropertyGrid 中看到一个 Columns 属性.我想抑制该属性,使其不会出现在 PropertyGrid 中.

Many of the controls on my toolbox are .NET controls. One of them is the .NET Winforms TableLayoutPanel control. When you place an instance of that control on a designer surface, you will see a Columns property in the bound PropertyGrid. I would like to suppress that property so that it doesn't appear in the PropertyGrid.

问题是 TableLayoutPanel 类型的属性列表中似乎不存在此 Columns 属性——因此使用 selectedComponents[0].GetType().GetProperties()例如, 不包含 Columns 属性.此外,我无法为现有的 Columns 属性创建新的或覆盖,因为它在设计时没有显示为 TableLayoutPanel 控件的公开属性——因此我不能用 Browsable(false) 属性装饰它.

The issue is that this Columns property doesn't appear to exist in the properties list for the TableLayoutPanel type--so using selectedComponents[0].GetType().GetProperties(), for example, doesn't contain a Columns property. Also, I cannot create a new or override for the existing Columns property because it doesn't appear as an exposed property for the TableLayoutPanel control at design time--thus I cannot decorate it with the Browsable(false) attribute.

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

I can't seem to leverage PreFilterProperties or PostFilterProperties because I can't interact and customize the TableLayoutPanel's designer.

如何抑制 TableLayoutPanelColumns 设计器属性,使其不出现在 PropertyGrid 中,而无需编写我的自己的设计师?

How can I suppress the Columns designer property for the TableLayoutPanel so that it doesn't appear in the PropertyGrid without having to write my own designer?

推荐答案

如果您想避免自己编写 TableLayoutPanelDesigner,那么这里有一个我可以建议的解决方法.

If you are trying to avoid writing TableLayoutPanelDesigner yourself, then here is a workaround that I can suggest.

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

ITypeDescriptorFilterService is the interface which is responsible for calling PreFilterProperties method of the designer. The DesignSurface class has a an instance of an implementation of this interface registered in its ServiceContainer. So you can remove the existing registered instance and register a new instance of your own implementation of ITypeDescriptorFilterService.

在新的实现中,覆盖FilterProperties,做你认为合适的,比如你可以检查组件的类型是否为TableLayoutPanel,然后不要调用其设计器 PreFilterProperties.

In the new implementation, override FilterProperties and do whatever you think is suitable, for example you can check if the type of the component is TableLayoutPanel, then don't call its designer PreFilterProperties.

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

Then to wrap up the solution, you need to create your own design surface by deriving from DesignSurface class and removing the registered ITypeDescriptorFilterService and registering the desired instance which you created.

示例

仅供参考,您要查找的属性的名称是 ColumnStyles 并且它默认具有 Browsable(false) 属性.但是 TableLayoutPanel 的默认设计器将这个属性替换为一个可浏览的版本.

Just for your information, the name of the property which you are looking for is ColumnStyles and it has Browsable(false) attribute by default. But the default designer of TableLayoutPanel replaces this property with a browsable version.

我在这个例子中所做的是阻止设计者让这些属性可见.

What I've done in this example is stopping the designer from making those properties Visible.

首先提供ITypeDescriptorFilterService 的自定义实现.下面一个实际上是 System.Design 程序集中的现有实现,我已经更改了它的 FilterProperties 方法并检查了组件是否为 TableLayoutPanel,我要求什么都不做.

First provide a custom implementation of ITypeDescriptorFilterService. The following one is in fact the existing implementation in System.Design assembly which I've changed its FilterProperties method and checked if the component is TableLayoutPanel, I've asked to do nothing.

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 派生来创建设计图面:

Then create a design surface by deriving from 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());
    }
}

然后例如以这种方式初始化设计图面:

Then for example initialize the design surface this way:

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();
    }
}

然后运行您的设计器应用程序,您将看到 ColumnsRows 属性按预期隐藏.

Then run your designer application and you will see Columns and Rows properties are hidden as expected.

您需要隐藏 ColumnCountRowCount 属性以及分配给编辑/添加/删除列和行的动词.

You need to hide ColumnCount and RowCount properties and also the verbs assigned to editing/adding/removing columns and rows.

这篇关于需要从 PropertyGrid 为 .NET Winforms 控件隐藏设计器专用属性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆