[英]Binding to the Current property of a BindingList
假设我有一个BindingList<Person>
,其中Person
具有一个名为Name
的公共字符串属性。 有没有一种方法可以有效(如果不是直接)绑定到Current
属性(这是一个Person
对象),然后索引到Name
属性?
我在想像这样的绑定设置
nameLabel.DataBindings.Add(
new Binding("Text", this.myBindingListSource, "Current.Name", true));
要么
nameLabel.DataBindings.Add(
new Binding("Text", this.myBindingListSource.Current, "Name", true));
这两种方法都会产生运行时错误。
当前,我只是订阅BindingList的CurrentChanged
事件并在那里处理更新。 这可行,但是如果可能的话,我更喜欢使用DataBinding方法。
使用下面提供的NestedBindingProxy类,您可以
nameLabel.DataBindings.Add(
new Binding("Text", new NestedBindingProxy(this.myBindingListSource, "Current.Name"), true));
以下是NestedBindingProxy的C#代码。 WinForms数据绑定的问题在于,当您使用包含多个属性的导航路径时,它不会检测到值更改。 WPF可以做到这一点。 因此,我创建了进行更改检测的NestedBindingProxy类,它公开了Windows绑定也可以绑定的名为“ Value”的属性。 每当导航路径中的任何属性更改时,都会为“值”属性触发notify属性更改事件。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Threading;
namespace WindowsFormsApplication4
{
public sealed class NestedBindingProxy : INotifyPropertyChanged
{
class PropertyChangeListener
{
private readonly PropertyDescriptor _prop;
private readonly WeakReference _prevOb = new WeakReference(null);
public event EventHandler ValueChanged;
public PropertyChangeListener(PropertyDescriptor property)
{
_prop = property;
}
public object GetValue(object obj)
{
return _prop.GetValue(obj);
}
public void SubscribeToValueChange(object obj)
{
if (_prop.SupportsChangeEvents)
{
_prop.AddValueChanged(obj, ValueChanged);
_prevOb.Target = obj;
}
}
public void UnsubsctribeToValueChange()
{
var prevObj = _prevOb.Target;
if (prevObj != null)
{
_prop.RemoveValueChanged(prevObj, ValueChanged);
_prevOb.Target = null;
}
}
}
private readonly object _source;
private PropertyChangedEventHandler _subscribers;
private readonly List<PropertyChangeListener> _properties = new List<PropertyChangeListener>();
private readonly SynchronizationContext _synchContext;
public event PropertyChangedEventHandler PropertyChanged
{
add
{
bool hadSubscribers = _subscribers != null;
_subscribers += value;
bool hasSubscribers = _subscribers != null;
if (!hadSubscribers && hasSubscribers)
{
ListenToPropertyChanges(true);
}
}
remove
{
bool hadSubscribers = _subscribers != null;
_subscribers -= value;
bool hasSubscribers = _subscribers != null;
if (hadSubscribers && !hasSubscribers)
{
ListenToPropertyChanges(false);
}
}
}
public NestedBindingProxy(object source, string nestedPropertyPath)
{
_synchContext = SynchronizationContext.Current;
_source = source;
var propNames = nestedPropertyPath.Split('.');
Type type = source.GetType();
foreach (var propName in propNames)
{
var prop = TypeDescriptor.GetProperties(type)[propName];
var propChangeListener = new PropertyChangeListener(prop);
_properties.Add(propChangeListener);
propChangeListener.ValueChanged += (sender, e) => OnNestedPropertyChanged(propChangeListener);
type = prop.PropertyType;
}
}
public object Value
{
get
{
object value = _source;
foreach (var prop in _properties)
{
value = prop.GetValue(value);
if (value == null)
{
return null;
}
}
return value;
}
}
private void ListenToPropertyChanges(bool subscribe)
{
if (subscribe)
{
object value = _source;
foreach (var prop in _properties)
{
prop.SubscribeToValueChange(value);
value = prop.GetValue(value);
if (value == null)
{
return;
}
}
}
else
{
foreach (var prop in _properties)
{
prop.UnsubsctribeToValueChange();
}
}
}
private void OnNestedPropertyChanged(PropertyChangeListener changedProperty)
{
ListenToPropertyChanges(false);
ListenToPropertyChanges(true);
var subscribers = _subscribers;
if (subscribers != null)
{
if (_synchContext != SynchronizationContext.Current)
{
_synchContext.Post(delegate { subscribers(this, new PropertyChangedEventArgs("Value")); }, null);
}
else
{
subscribers(this, new PropertyChangedEventArgs("Value"));
}
}
}
}
}
尝试这个:
Binding bind = new Binding("Text", myBindingListSource, "Current");
bind.Format += (s,e) => {
e.Value = e.Value == null ? "" : ((Person)e.Value).Name;
};
nameLabel.DataBindings.Add(bind);
我尚未测试过,但它应该可以工作,我一直在等待您的反馈。
我偶然发现了这个问题(在原始帖子发布四年后),并且在快速阅读之后,我发现对于OP的问题,被接受的答案似乎设计得过分。
我使用了这种方法,并在此处发布了一个答案(希望)帮助其他遇到相同问题的人。
以下应该工作(如果this.myBindingListSource
实现IBindingList )
我只需要创建一个绑定源即可包装我的绑定列表(在我的Form / View中) BindingSource bindingSource = new BindingSource(this.myBindingListSource, string.Empty);
然后像这样绑定到绑定源:
nameLabel.DataBindings.Add(new Binding("Text", bindingSource, "Name"));
我认为OP的原始代码不起作用,因为在BindingList上没有名为“ Current”的成员(除非OP具有未提及的某种特殊类型)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.