1

根据我之前的问题,通过 .NET 中的某种接口使属性可用于数据绑定?,我在@Marc Gravell的帮助下进行了管理,通过实现接口ICustomTypeDescriptor我可以为表单设计器提供自定义属性,这些属性可能会或可能不会作为真正的普通属性在相关组件上实际可见。

我做到了这一点,但我的实施存在缺陷。我现在遇到的最大问题是,如果我在我的表单上拖放一个组件,它有两个这样的自定义属性,然后将两个文本框拖放到表单上,并使用数据绑定,属性检查器中的数据绑定下拉菜单需要一个对象数据源,但我绑定到控件的每个属性都会在表单上添加另一个BindingSource组件。

让我重新表述一下。我将自定义组件放到表单上。它有两个属性,可通过我的ICustomTypeDescriptor实现获得,但作为普通属性不可见。

然后我将两个文本框放到表单上。我去属性检查器让其中一个为 Text 属性添加数据绑定,它需要项目中的对象数据源,我添加了它。然后,在将文本框上的 Text 属性绑定到我的自定义组件的第一个属性之后,表单设计器添加了另一个组件,即“customDataBindingBindingSource”,用于桥接两者之间的数据绑定。到目前为止,一切都很好。

然后,当我以相同的方式为该其他文本框设置数据绑定时(除了我现在可以选择自定义组件的其他属性),添加了另一个这样的桥,“customDataBindingBindingSource1”。如果我不断切换要绑定的属性,则每次都会添加一个这样的桥。

这真的有必要吗?

如果不是,我在ICustomTypeDescriptor实现中做错了什么?诚然,这很天真、简单而且远未完成,但我不知道我需要解决什么问题。任何指针?

这是我的自定义类:

public class CustomDataBinding : Component, ICustomTypeDescriptor, INotifyPropertyChanged
{
    private String _Property1;
    private String _Property2;

    public class MyPropertyDescriptor : PropertyDescriptor
    {
        private String _Name;

        public MyPropertyDescriptor(String name)
            : base(name, null)
        {
            _Name = name;
        }

        public override bool CanResetValue(object component)
        {
            return true;
        }

        public override Type ComponentType
        {
            get { return typeof(CustomDataBinding); }
        }

        public override object GetValue(object component)
        {
            CustomDataBinding source = (CustomDataBinding)component;
            switch (_Name)
            {
                case "Property1":
                    return source._Property1;
                    break;

                case "Property2":
                    return source._Property2;
                    break;

                default:
                    return null;
            }
        }

        public override bool IsReadOnly
        {
            get { return false; }
        }

        public override Type PropertyType
        {
            get { return typeof(String); }
        }

        public override void ResetValue(object component)
        {
            SetValue(component, _Name);
        }

        public override void SetValue(object component, object value)
        {
            CustomDataBinding source = (CustomDataBinding)component;
            switch (_Name)
            {
                case "Property1":
                    source._Property1 = Convert.ToString(value);
                    Debug.WriteLine("Property1 changed to " + value);
                    break;

                case "Property2":
                    source._Property2 = Convert.ToString(value);
                    Debug.WriteLine("Property2 changed to " + value);
                    break;

                default:
                    return;
            }
            source.OnPropertyChanged(_Name);
        }

        public override bool ShouldSerializeValue(object component)
        {
            return false;
        }
    }

    public CustomDataBinding()
    {
        _Property1 = "Property1";
        _Property2 = "Property2";
    }

    #region ICustomTypeDescriptor Members

    public AttributeCollection GetAttributes()
    {
        return new AttributeCollection(null);
    }

    public string GetClassName()
    {
        return null;
    }

    public string GetComponentName()
    {
        return null;
    }

    public TypeConverter GetConverter()
    {
        return null;
    }

    public EventDescriptor GetDefaultEvent()
    {
        return null;
    }

    public PropertyDescriptor GetDefaultProperty()
    {
        return null;
    }

    public object GetEditor(Type editorBaseType)
    {
        return null;
    }

    public EventDescriptorCollection GetEvents(Attribute[] attributes)
    {
        return new EventDescriptorCollection(null);
    }

    public EventDescriptorCollection GetEvents()
    {
        return new EventDescriptorCollection(null);
    }

    public PropertyDescriptorCollection GetProperties(Attribute[] attributes)
    {
        return new PropertyDescriptorCollection(new PropertyDescriptor[] {
            new MyPropertyDescriptor("Property1"),
            new MyPropertyDescriptor("Property2") });
    }

    public PropertyDescriptorCollection GetProperties()
    {
        return GetProperties(null);
    }

    public object GetPropertyOwner(PropertyDescriptor pd)
    {
        return this;
    }

    #endregion

    #region INotifyPropertyChanged Members

    public event PropertyChangedEventHandler PropertyChanged;

    public void OnPropertyChanged(String name)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(name));
    }

    public void SetValues(String p1, String p2)
    {
        _Property1 = p1;
        _Property2 = p2;

        OnPropertyChanged("Property1");
        OnPropertyChanged("Property2");
    }

    #endregion
}

此外,我需要在表单构造函数中手动将这些桥连接到我最初删除的组件,如下所示:

customDataBindingBindingSource.DataSource = customDataBinding1;
customDataBindingBindingSource1.DataSource = customDataBinding1;

有没有办法解决很多问题?

基本上,在使用我的组件时我想做的是:

  1. 将我的自定义组件之一拖放到表单上
  2. 删除必要的控件(文本框、日期选择器等)
  3. 将控件的数据绑定分配给我的自定义组件上的相关属性

如果可能的话,我想避免项目数据源、桥接组件以及构造函数中的代码。我想避免的一切。

请注意,我不要求任何人给我代码。欢迎任何指点。

4

0 回答 0