Laden...

Control.DataBindings unter Win8 - Breaking Change?

Erstellt von gelöschtem Konto vor 10 Jahren Letzter Beitrag vor 10 Jahren 1.469 Views
Gelöschter Account
vor 10 Jahren
Control.DataBindings unter Win8 - Breaking Change?

Ich habe folgende Zeile Code die auf WinXP,Vista,7 32/64Bit problemlos läuft, jedoch auf allen Win8 Entwicklermaschinen eine TargetInvocation Exception auslöst. > Fehlermeldung:

TargetInvocation Exception
(ContainsLocalChanges - Das Objekt stimmt nicht mit dem Zieltyp überein)


buttonProxyCancelChanges.DataBindings.Add("Enabled", control.Context, "ContainsLocalChanges", false, DataSourceUpdateMode.Never);

Ich meine mich an ein Gespräch zu erinnern wo mir gegenüber mal jemand erwähnte das dies so unter Win8 nicht mehr läuft. Dagegen spricht allerdings das ich im Internet keine Topics dazu finde. Hat jemand ne Idee woran das liegen könnte?

Gelöschter Account
vor 10 Jahren

Hallo,

Nach zig Stunden Diagnose bin ich dem Problem im Debugger auf die Spur gekommen. Es handelt sich scheinbar tatsächlich um einen Breaking Change. Ich kanns eigentlich garnicht glauben, evtl. kann mir das ja jemand testweise bestätigen.

Gegeben sei folgende (symbolische) Klassendefinition

class Customers : IEnumerable<Customer>, INotifyPropertyChanged
{
    public ReadOnly{get;set;}
}

class Customer : INotifyPropertyChanged
{
   string Name{get;set;}
}

Eine Instanz der Klasse Customers binden wir jetzt an ein Control, sagen wir mal ein Button.


control.DataBindings.Add("Enabled", _customers, "ReadOnly", false, DataSourceUpdateMode.Never);

Dieser Code funktioniert unter XP, Vista, 7 aber nicht unter Win8.

Warum ist das so?

Die IEnumerable<T> Implementierung von Customers sorgt dafür das der Binding Manager von Windows Forms sich unter Win8 keine Propertydescriptoren unserer Instanz von Customers zieht sondern das er GetEnumerator aufruft und sich die erste Instanz der Auflistung rausgreift. Für diese erste Instanz zieht er sich dann die Propertydescriptoren. Unter früheren Windows Versionen passiert das nicht, hier wird die Instanz von Customers verwendet, unabhängig davon was für Interfaces sie implementiert.

Ich habe ein Sample Projekt angefügt. Es wäre schön wenn mir jemand meine Analyse bestätigen könnte. Also:Läuft mit W7(ich nutze XP), läuft nicht mit W8 und läuft mit W8 wenn man IEnumerable<T> rausschmeisst.

EDIT: Ich habe im Test .NET 4.0 verwendet
EDIT2: Aus versehen doppelter Text

S
145 Beiträge seit 2013
vor 10 Jahren

Kann mich zwar grad irren aber das verhalten meine ich auch schon aus Win7 und XP zu kennen (mit .Net 2.0).
Jedenfalls kommt mir das problem ziemlich bekannt vor und ich achte deshalb schon länger drauf bei gebundenen Objekten.

Gelöschter Account
vor 10 Jahren

Ich habs auf unzähligen XP,W7,W8 Systemen mit meinem Minimalprojekt getestet. Da waren virtuelle Maschinen dabei oder einfach nur die Rechner der Kollegen, das Ergebniss war immer das gleiche (wie beschrieben).

Anyway, ich überlege nun wie ich einen Workarround für das Problem finde. Mein erster Gedanke war die betreffende Instanz in der Bindingsanweisung auf INotifyPropertyChanged zu casten, 4 Sekunden später war mir klar das dies mit Sicherheit nix bringt. Der Binding Manager wird immer noch erfolgreich feststellen das die Instanz IEnumerable unterstützt(die T Variante interessiert ihn garnicht, nicht ganz untypisch für WindowsForms das man leider nicht mehr weiterentwickelt und deswegen nie für Generics fit gemacht hat)

Ich tendiere dazu einen nackten NotifyPropertyChanged Proxy zur erstellen der quasi als Wrapper fungiert und damit als Brücke zwischen den beiden Binding-Parteien kommuniziert.

So oder so würde ich dieses Rätsel nur zu gerne auflösen.
(Wenn ich morgen dazu komme, werde ich das mal in .NET 2 zwischen XP und 7 testen, wenn du richtig liegst bin ich dann allerdings noch viel verwirrter als jetzt schon)

49.485 Beiträge seit 2005
vor 10 Jahren

Hallo Sebastian.Lange,

eine verbindliche Antwort wirst du vermutlich erst finden, wenn du dir den DataBinding-Code im .NET Framework mit dem Debugger und/oder dem Relfector in der jeweiligen Umgebung anschaust und vergleichst. Wenn es wirklich einen (Breaking) Change gibt, dann müsste sich ja ein Unterschiede im Code des jeweiligen .NET-Frameworks auf dem jeweiligen System finden lassen.

herbivore

4.221 Beiträge seit 2005
vor 10 Jahren

Hast Du mal mit ITypedList experimentiert (auf Customers implementieren)...

Dann fragt der BindingManager IMMER deine GetProperties-Methode ab... und DU kannst ihm übergeben welche TypeDescriptors er verwenden soll.

Früher war ich unentschlossen, heute bin ich mir da nicht mehr so sicher...

Gelöschter Account
vor 10 Jahren

Hallo Programmierhans,

Das ITypedList Interface hat konkret die Aufgabe die Beschreibung der Kind Elemente einer Liste zurück zu geben. Genau das passiert hier, aus meiner Sicht irrtümlich. Selbst wenn das funktioniert, möchte ich das ITypedList Interface nicht gegen seine Absicht missbrauchen. Vielmehr werde ich herbivore's Hinweis nochmal aufgreifen und den Source Code des .NET Frameworks auf den jeweiligen Systemen untersuchen. Es muss hier einen Unterschied geben. Ich habe mittels des System.Diagnostic Namespaces schon die StackFrames untersucht und diese unterscheiden sich tatsächlich sehr stark voneinander. (Ich muss aus gesundheitlichen Gründen jetzt für ein paar Tage ReHa aussetzen, danach aber, sobald ich das Problem geklärt habe, poste ich sofort die Auflösung)

Hinweise zu ITypedList:
Für untypisierte und typisierte Listen rufen bindbare Anzeigeelemente(z.B. ein DataGrid) normalerweise das erste Element innerhalb der Liste auf, die Typeninformationen werden dann genutzt um die Darstellung(Spalten, etc) zu initialisieren. Das funktioniert leider nur so lange wie es wenigstens ein Element innerhalb der Liste gibt. Aus diesem Grund wurde das ITypedList Interface geboren. Controls die Auflistungen darstellen möchten versuchen zuallerst die Datenquelle auf ITypedList zu casten um daraufhin ihre Darstellung für die Kind Elemente zu aktualisieren.