代码之家  ›  专栏  ›  技术社区  ›  Szybki

使Propertygrid在运行时显示绑定的属性符号

  •  2
  • Szybki  · 技术社区  · 7 年前

    当您使用数据绑定将控件的属性绑定到数据源时,属性网格将在该属性共同响应的网格项中显示一个紫色或黑色的小符号。

    即使将PropertyGrid放置在表单上,并将其SelectedObject属性设置为具有绑定属性的控件,表单上的PropertyGrid也会显示该符号。

    但仅在设计时。

    有没有一种(简单的)方法可以使相同的PropertyGrid在运行时显示此符号?

    1 回复  |  直到 7 年前
        1
  •  2
  •   Reza Aghaei    7 年前

    它由Visual Studio designer内部事物处理。但您也可以将此功能添加到 PropertyGrid :

    enter image description here

    您需要实施 IPropertyValueUIService 并使用反射,将服务的一个实例分配给应该显示图示符的网格条目。此实现有一个方法 GetPropertyUIValueItems 可用于提供图示符和工具提示,以便在中的特性标签附近显示 属性表格 . 这些值将用于 PaintLabel 属性网格条目的方法。

    然后创建继承的 属性表格 和覆盖 OnSelectedObjectsChanged OnPropertySortChanged . 在这些方法中,对于表示数据绑定集合中的属性的每个属性网格条目项,设置实现的 IPropertyValueUIService 作为的值 pvSvc 私有财产 属性表格 并附加一个事件处理程序,当 属性表格 请求有关该物业的其他信息。通过使用 GetPropertyUIValueItems 到,可以返回要在属性前面显示的工具提示和图像。

    实例

    您可以在此处下载完整示例:

    您可以找到实现的主要类,如下所示。

    PropertyValueUIService属性

    using System;
    using System.Collections;
    using System.ComponentModel;
    using System.Drawing.Design;
    
    namespace PropertyGridDataBindingGlyph
    {
        public class PropertyValueUIService : IPropertyValueUIService
        {
            private PropertyValueUIHandler handler;
            private ArrayList items;
    
            public event EventHandler PropertyUIValueItemsChanged;
            public void NotifyPropertyValueUIItemsChanged()
            {
                PropertyUIValueItemsChanged?.Invoke(this, EventArgs.Empty);
            }
            public void AddPropertyValueUIHandler(PropertyValueUIHandler newHandler)
            {
                handler += newHandler ?? throw new ArgumentNullException("newHandler");
            }
            public PropertyValueUIItem[] GetPropertyUIValueItems(ITypeDescriptorContext context, PropertyDescriptor propDesc)
            {
                if (propDesc == null)
                    throw new ArgumentNullException("propDesc");
                if (this.handler == null)
                    return new PropertyValueUIItem[0];
                lock (this)
                {
                    if (this.items == null)
                        this.items = new ArrayList();
                    this.handler(context, propDesc, this.items);
                    int count = this.items.Count;
                    if (count > 0)
                    {
                        PropertyValueUIItem[] propertyValueUiItemArray = new PropertyValueUIItem[count];
                        this.items.CopyTo((Array)propertyValueUiItemArray, 0);
                        this.items.Clear();
                        return propertyValueUiItemArray;
                    }
                }
                return null;
            }
            public void RemovePropertyValueUIHandler(PropertyValueUIHandler newHandler)
            {
                handler -= newHandler ?? throw new ArgumentNullException("newHandler");
    
            }
        }
    }
    

    ExPropertyGrid

    using System;
    using System.Collections;
    using System.ComponentModel;
    using System.Drawing;
    using System.Drawing.Design;
    using System.Linq;
    using System.Reflection;
    using System.Windows.Forms;
    using System.Windows.Forms.Design;
    
    namespace PropertyGridDataBindingGlyph
    {
        public class ExPropertyGrid : PropertyGrid
        {
            Bitmap dataBitmap;
            public ExPropertyGrid()
            {
                dataBitmap = new Bitmap(typeof(ControlDesigner).Assembly
                     .GetManifestResourceStream("System.Windows.Forms.Design.BoundProperty.bmp"));
                dataBitmap.MakeTransparent();
            }
            protected override void OnSelectedObjectsChanged(EventArgs e)
            {
                base.OnSelectedObjectsChanged(e);
                this.BeginInvoke(new Action(() => { ShowGlyph(); }));
            }
            protected override void OnPropertySortChanged(EventArgs e)
            {
                base.OnPropertySortChanged(e);
                this.BeginInvoke(new Action(() => { ShowGlyph(); }));
            }
            private void ShowGlyph()
            {
                var grid = this.Controls[2];
                var field = grid.GetType().GetField("allGridEntries",
                System.Reflection.BindingFlags.NonPublic |
                System.Reflection.BindingFlags.Instance | BindingFlags.FlattenHierarchy);
                var value = field.GetValue(grid);
                if (value == null)
                    return;
                var entries = (value as IEnumerable).Cast<GridItem>().ToList();
                if (this.SelectedObject is Control)
                {
                    ((Control)this.SelectedObject).DataBindings.Cast<Binding>()
                        .ToList().ForEach(binding =>
                        {
                            var item = entries.Where(x => x.PropertyDescriptor?.Name == binding.PropertyName).FirstOrDefault();
                            var pvSvcField = item.GetType().GetField("pvSvc", BindingFlags.NonPublic |
                                BindingFlags.Instance | BindingFlags.FlattenHierarchy);
                            IPropertyValueUIService pvSvc = new PropertyValueUIService();
                            pvSvc.AddPropertyValueUIHandler((context, propDesc, valueUIItemList) =>
                            {
                                valueUIItemList.Add(new PropertyValueUIItem(dataBitmap, (ctx, desc, invokedItem) => { }, GetToolTip(binding)));
                            });
                            pvSvcField.SetValue(item, pvSvc);
                        });
                }
            }
            private static string GetToolTip(Binding binding)
            {
                var value = "";
                if (binding.DataSource is ITypedList)
                    value = ((ITypedList)binding.DataSource).GetListName(new PropertyDescriptor[] { });
                else if (binding.DataSource is Control)
                    value = ((Control)binding.DataSource).Name;
                else if (binding.DataSource is Component)
                    value = ((Component)binding.DataSource).Site?.Name;
    
                if (string.IsNullOrEmpty(value))
                    value = "(List)";
                return value + " - " + binding.BindingMemberInfo.BindingMember;
            }
        }
    }