仅一个数据源需要多个 BindingSource 组件吗?
根据我之前的问题,通过 .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;
有没有办法解决很多问题?
基本上,在使用我的组件时我想要做的是:
- 将我的自定义组件之一拖放到表单上
- 拖放必要的控件(文本框、日期选择器等)
- 将控件的数据绑定分配给相关属性我的自定义组件
如果可能的话,我想避免使用项目数据源、桥接组件以及构造函数中的代码。这一切都是我想避免的。
请注意,我不会要求任何人给我代码。欢迎任何指点。
As per my previous question, Make properties available for data binding through some kind of interface in .NET?, I managed, with the help of @Marc Gravell that by implementing the interface ICustomTypeDescriptor I can provide the form designer with custom properties that may or may not actually be visible on the component in question as real normal properties.
I managed this, but my implementation is flawed. The biggest problem I have now is that if I drop a component on my form, which has two such custom properties, and then drop two textboxes onto the form, and use data binding, the data binding dropdown in the property inspector needs an object data source, but each property I bind to a control adds another BindingSource component onto the form.
Let me rephrase that. I drop my custom component onto the form. It has two properties, that are available through my ICustomTypeDescriptor implementation, but not visible as normal properties.
I then drop two textboxes onto the form. I go to the property inspector for one of them to add data binding for the Text property, and it needs an object data source in the project, and I add that. Then, after binding the Text property on the textbox to the first property of my custom component, the form designer has another component added to it, a "customDataBindingBindingSource", which is used to bridge the data binding between the two. So far, so good.
Then, when I set up data binding for that other textbox in the same way (except that I can now just pick the other property of my custom component), another such bridge is added, "customDataBindingBindingSource1". If I keep switching properties to bind to, one such bridge is added each time.
Is this really necessary?
If not, what did I do wrong in my ICustomTypeDescriptor implementation? Granted, it's naive and simple and far from complete, but I don't know what I need to fix. Any pointers?
Here's my custom class:
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
}
Also, I need to manually hook these bridges up to the component I originally, dropped, in the form constructor, like this:
customDataBindingBindingSource.DataSource = customDataBinding1;
customDataBindingBindingSource1.DataSource = customDataBinding1;
Is there a way to get around a lot of this?
Basically, what I'd like to do when using my components is this:
- Drop one of my custom components onto the form
- Drop the necessary controls (text boxes, date pickers, etc.)
- Assign data binding for the controls to the relevant properties on my custom component
If possible, I'd like to avoid having the project data source, and the bridge components, as well as the code in the constructor. All that I'd like to avoid.
Note that I do not ask for anyone to give me teh codes. Any pointers are welcome.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论