Ich möchte einen dynamischen Proxy für die Bindung von WinForms-Steuerelementen an Objekte erstellen, die von einem anderen Thread (nicht GUI) geändert wurden. Ein solcher Proxy würde das PropertyChanged-Ereignis abfangen und mit dem richtigen SynchronizationContext absetzen.Erstellen eines INotifyPropertyChanged-Proxys zum Verteilen von Aufrufen an den UI-Thread
So könnte ich eine Helper-Klasse verwenden, um die Aufgabe zu erledigen, ohne jedes Mal die Synchronisation manuell implementieren zu müssen (if (control.InvokeRequired) etc.
).
Gibt es eine Möglichkeit, das mit LinFu, Castle oder einer ähnlichen Bibliothek zu tun?
[Bearbeiten]
Datenquelle ist nicht unbedingt eine Liste. Es kann jedes Business-Objekt, zum Beispiel sein:
interface IConnection : INotifyPropertyChanged
{
ConnectionStatus Status { get; }
}
Ich konnte einen Wrapper erstellen, die den Job machen könnte, und es würde wie folgt aussehen:
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;
}
(es kann einige Fehler in dieser sein Code, ich mache es)
Was ich tun möchte, ist ein dynamischer Proxy (Reflection.Emit) ein Liner dafür, z
IConnection syncConnection
= new SyncPropertyChangedProxy<IConnection>(actualConnection);
und ich wollte wissen, ob so etwas mit vorhandenen dynamischen Proxy-Implementierungen möglich war.
Eine allgemeinere Frage wäre: Wie ein Ereignis beim Erstellen eines dynamischen Proxy abfangen? Abfangen (überschreiben) Eigenschaften wird in allen Implementierungen gut erklärt.
[Edit2]
Der Grund (glaube ich) Ich brauche ein Proxy ist, dass der Stack-Trace wie folgt aussieht:
at PropertyManager.OnCurrentChanged(System.EventArgs e) at BindToObject.PropValueChanged(object sender, EventArgs e) at PropertyDescriptor.OnValueChanged(object component, EventArgs e) at ReflectPropertyDescriptor.OnValueChanged(object component, EventArgs e) at ReflectPropertyDescriptor.OnINotifyPropertyChanged(object component, PropertyChangedEventArgs e) at MyObject.OnPropertyChanged(string propertyName)
Sie können sehen, dass BindToObject.PropValueChanged
nicht die sender
Instanz nicht passiert zu der PropertyManager
, und Reflector zeigt, dass Absenderobjekt nirgendwo referenziert wird. Mit anderen Worten, wenn das Ereignis PropertyChanged
ausgelöst wird, verwendet die Komponente reflection, um auf die Eigenschaft der ursprünglichen (gebundenen) Datenquelle zuzugreifen.
Wenn ich mein Objekt in eine Klasse verpacken würde, die nur das Ereignis enthält (wie Sam vorgeschlagen), würde eine solche Wrapperklasse keine Eigenschaften enthalten, auf die über Reflection zugegriffen werden könnte.
Siehe 'ThreadedBindingList' - hier auf SO wiederholt wurde (http://stackoverflow.com/questions/455766/how-do-you -correctly-update-a-datensatz-datagridview-from-a-background-thread). –