【问题标题】:Accessing additional context data in EditValue of UITypeEditor在 UITypeEditor 的 EditValue 中访问其他上下文数据
【发布时间】:2023-03-30 09:12:01
【问题描述】:

我正在调整一个 WinForms 应用程序。此应用程序有一个Form,其中包含一个PropertyGrid。将一个对象分配给SelectedObject 属性,以便属性网格显示该对象的属性。

分配的对象类型有一个属性,该属性带有一个EditorAttribute,指定一个UITypeEditor

UITypeEditor 的此实现在其对 GetEditStyle 方法的覆盖中返回 UITypeEditorEditStyle.Drop。它的EditValue 方法显示一个ListBox,可以从中分配实例属性的值。

到目前为止一切顺利。

现在我有一个附加要求,它要求根据托管PropertyGridForm 持有的其他状态来修改列表中的可用项目。我不知道如何将这些上下文信息传递给 EditValue 方法。

context 参数上似乎没有任何内容,即使我尝试将其转换为更具体的类型。我也不知道如何添加一些其他服务以从provider 中检索。

有什么想法吗?

【问题讨论】:

    标签: c# winforms propertygrid uitypeeditor


    【解决方案1】:

    我遇到了类似的情况,我想将一个对象注入到我的自定义 UITypeEditor 的构造函数中。

    我在Here 中关注了 Nicolas Cadilhac 的评论,给予他所有的信任。它使用 TypeDescriptionProvider。

    这是完整的代码集。

    class Foo
    {
        public Foo() { Bar = new Bar(); }
        public Bar Bar { get; set; }
    }
    
    class Bar
    {
        public string Value { get; set; }
    }
    
    class BarTypeDescriptionProvider : TypeDescriptionProvider
    {
        private TypeDescriptionProvider _baseProvider;
        string _extraParam;
    
        public BarTypeDescriptionProvider(Type t, string extraParam)
        {
            this._extraParam = extraParam;
            _baseProvider = TypeDescriptor.GetProvider(t);
        }
    
        public string ExtraParam
        { 
            get { return _extraParam; } 
        }
    
        public override ICustomTypeDescriptor GetTypeDescriptor(Type objectType, object instance)
        {
            return new BarTypeDescriptor(this, _baseProvider.GetTypeDescriptor(objectType, instance), objectType);
        }
    }
    
    
    class BarTypeDescriptor : CustomTypeDescriptor
    {
        private Type _objectType;
        private BarTypeDescriptionProvider _provider;
    
        public BarTypeDescriptor(BarTypeDescriptionProvider provider,  ICustomTypeDescriptor descriptor, Type objectType): base(descriptor)
        {
            if (provider == null) throw new ArgumentNullException("provider");
            if (descriptor == null)
                throw new ArgumentNullException("descriptor");
            if (objectType == null)
                throw new ArgumentNullException("objectType");
            _objectType = objectType;
            _provider = provider;
        }
    
        public override object GetEditor(Type editorBaseType)
        {
            return new BarEditor(_provider.ExtraParam);
        }
    }
    
    
    class BarEditor : UITypeEditor
    {
        private string _extraParam;
        public BarEditor(string x)
            : base()
        {
            _extraParam = x;
        }
    
        public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context)
        {
            return UITypeEditorEditStyle.Modal;
        }
        public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value)
        {
            MessageBox.Show(_extraParam);
            return base.EditValue(context, provider, value);
        }
    }
    
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
    
            string extraParam = "Extra param from main form";
    
            TypeDescriptor.AddProvider(new BarTypeDescriptionProvider(typeof(Bar), extraParam), typeof(Bar));
    
            this.propertyGrid1.SelectedObject = new Foo();
        }
    }
    

    迈克尔

    【讨论】:

      【解决方案2】:

      我想知道你正在尝试做的事情是否会通过GetStandardValues 成为TypeConverter 更好?但无论哪种方式,context.Instancecontext.PropertyDescriptor 似乎 都将在快速测试中填充(对于 GetEditStyleEditValue):

      using System;
      using System.ComponentModel;
      using System.Drawing.Design;
      using System.Windows.Forms;
      class MyData
      {
          [Editor(typeof(MyEditor), typeof(UITypeEditor))]
          public string Bar { get; set; }
      
          public string[] Options { get; set; }
      }
      class MyEditor : UITypeEditor
      {
          public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context)
          {
              // break point here; inspect context
              return UITypeEditorEditStyle.DropDown;
          }
          public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value)
          {
              // break point here; inspect context
              return base.EditValue(context, provider, value);
          }
      
      }
      class Program
      {
          [STAThread]
          static void Main()
          {
              Application.EnableVisualStyles();
              Application.Run(new Form
              {
                  Controls =
                  {
                      new PropertyGrid {
                          Dock = DockStyle.Fill,
                          SelectedObject = new MyData()
                      }
                  }
              });
          }
      }
      

      或者作为类型转换器:

      using System;
      using System.ComponentModel;
      using System.Windows.Forms;
      
      class MyData
      {
          [TypeConverter(typeof(MyConverter))]
          public string Bar { get; set; }
      
          public string[] Options { get; set; }
      }
      class MyConverter : StringConverter
      {
          public override bool GetStandardValuesSupported(ITypeDescriptorContext context)
          {
              return true;
          }
          public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
          {
              MyData data = (MyData)context.Instance;
              if(data == null || data.Options == null) {
                  return new StandardValuesCollection(new string[0]);
              }
              return new StandardValuesCollection(data.Options);
          }
      }
      class Program
      {
          [STAThread]
          static void Main()
          {
              Application.EnableVisualStyles();
              Application.Run(new Form
              {
                  Controls =
                  {
                      new PropertyGrid {
                          Dock = DockStyle.Fill,
                          SelectedObject = new MyData()
                      }
                  }
              });
          }
      }
      

      【讨论】:

      • 谢谢 Marc,也许我的问题需要调整,我需要访问 form 持有的值,而 不是 持有的值分配给网格的SelectedObject 属性的对象。
      • @Anthony - 获取表单会很棘手 - 有什么方法可以将它抽象到实例中吗?
      • 我想我可以,但我希望有另一种方法。我真的不想污染我的数据承载对象来服务于应用程序架构的利益。它不一定是表单本身,只是访问其他数据的其他方式,这确实是IServiceProvider 的角色,但我无法在这种情况下找到一种方式来添加我自己的服务。跨度>
      【解决方案3】:

      在重写的 EditValue 方法中,context.Container 将提供编辑器所属的对象。 context.Container.Components 属性将列出所有控件,包括表单及其所有子项。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2013-08-18
        • 2021-11-19
        • 2021-05-17
        • 2014-07-24
        • 1970-01-01
        • 2017-07-08
        • 1970-01-01
        相关资源
        最近更新 更多