我想创建一个动态代理,用于将 WinForms 控件绑定到由不同(非 GUI)线程更改的对象。这样的代理将拦截 PropertyChanged 事件并使用适当的 SynchronizationContext 调度它。
这样我就可以使用辅助类来完成这项工作,而不必每次都手动实现同步(if (control.InvokeRequired) etc.
)。
有没有办法使用 LinFu、Castle 或类似的库来做到这一点?
[编辑]
数据源不一定是列表。它可以是任何业务对象,例如:
interface IConnection : INotifyPropertyChanged
{
ConnectionStatus Status { get; }
}
我可以创建一个可以完成这项工作的包装器,它看起来像这样:
public class ConnectionWrapper : IConnection
{
private readonly SynchronizationContext _ctx;
private readonly IConnection _actual;
public ConnectionWrapper(IConnection actual)
{
_ctx = SynchronizationContext.Current;
_actual= actual;
_actual.PropertyChanged +=
new PropertyChangedEventHandler(actual_PropertyChanged);
}
// we have to do 2 things:
// 1. wrap each property manually
// 2. handle the source event and fire it on the GUI thread
private void PropertyChanged(object sender, PropertyChangedEvArgs e)
{
// we will send the same event args to the GUI thread
_ctx.Send(delegate { this.PropertyChanged(sender, e); }, null);
}
public ConnectionStatus Status
{ get { return _instance.Status; } }
public event PropertyChangedEventHandler PropertyChanged;
}
(这段代码可能有一些错误,我正在弥补)
我想做的是为此设置一个动态代理(Reflection.Emit),例如
IConnection syncConnection
= new SyncPropertyChangedProxy<IConnection>(actualConnection);
我想知道使用现有的动态代理实现是否可以实现这样的事情。
一个更普遍的问题是:创建动态代理时如何拦截事件?在所有实现中都很好地解释了拦截(覆盖)属性。
[编辑2]
我需要代理的原因(我认为)是堆栈跟踪如下所示:
在 PropertyManager.OnCurrentChanged(System.EventArgs e) 在 BindToObject.PropValueChanged(对象发送者,EventArgs e) 在 PropertyDescriptor.OnValueChanged(对象组件,EventArgs e) 在 ReflectPropertyDescriptor.OnValueChanged(对象组件,EventArgs e) 在 ReflectPropertyDescriptor.OnINotifyPropertyChanged(对象组件, PropertyChangedEventArgs e) 在 MyObject.OnPropertyChanged(字符串属性名称)
您可以看到BindToObject.PropValueChanged
没有将sender
实例传递给PropertyManager
,并且 Reflector 显示 sender 对象在任何地方都没有被引用。也就是说,当PropertyChanged
事件触发时,组件会使用反射来访问原始(绑定)数据源的属性。
如果我将我的对象包装在一个只包含事件的类中(如Sam建议的那样),那么这样的包装类将不包含任何可以通过反射访问的属性。