別の (非 GUI) スレッドによって変更されたオブジェクトに WinForms コントロールをバインドするための動的プロキシを作成したいと考えています。このようなプロキシは、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)を1つのライナーにすることです。
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 で (文字列 propertyName)
がインスタンスを にBindToObject.PropValueChanged
渡していないことがわかります。Reflector は、sender オブジェクトがどこにも参照されていないことを示しています。つまり、イベントがトリガーされると、コンポーネントはリフレクションを使用して元の (バインドされた) データ ソースのプロパティにアクセスします。sender
PropertyManager
PropertyChanged
イベントのみを含むクラスでオブジェクトをラップした場合 ( Samが提案したように)、そのようなラッパー クラスには、Reflection を介してアクセスできるプロパティは含まれません。