2014-06-12 34 views
12

Mamy napotkasz problem gdzieCo jest innego podczas uzyskiwania dostępu do BindingContext [dataSource] vs BindingContext [dataSource, dataMember]?

  • mamy dwie instancje tego samego okna w obszarze roboczym MDI związanej z dwóch oddzielnych modeli obiektowych.
  • Modele obiektów mają zastąpione metody i .GetHashCode, aby można je było uznać za równe.
  • Wywołanie .EndCurrentEdit() na okno 2 jest wyzwalanie aktualizacji wiązania na oknie 1
  • Oba okna są ustawione w użyciu oddzielnego BindingContext

Odkryliśmy problem ma związek z wywołaniem

((PropertyManager)ctrl.BindingContext[dataSource]).EndCurrentEdit(); 

Jeśli zmienimy to na

((PropertyManager)ctrl.BindingContext[dataSource, dataMember]).EndCurrentEdit(); 

Działa poprawnie. Działa również poprawnie, jeśli usuniemy nasze nadpisania .Equals i .GetHashCode, aby dwa modele obiektów nie były już uznawane za równe.

To nie ma dla mnie sensu, ponieważ okna są takie same, więc właściwość dataMember również byłaby taka sama.

Od this link, uważam, że definicja tych połączeń jest:

public BindingManagerBase this[object dataSource] { 
    get { 
     return this[dataSource, ""]; 
    } 
} 

public BindingManagerBase this[object dataSource, string dataMember] { 
    get { 
     return EnsureListManager(dataSource, dataMember); 
    } 

internal BindingManagerBase EnsureListManager(object dataSource, string dataMember) { 
    BindingManagerBase bindingManagerBase = null; 

    if (dataMember == null) 
     dataMember = ""; 

    // Check whether data source wants to provide its own binding managers 
    // (but fall through to old logic if it fails to provide us with one) 
    // 
    if (dataSource is ICurrencyManagerProvider) { 
     bindingManagerBase = (dataSource as ICurrencyManagerProvider).GetRelatedCurrencyManager(dataMember); 

     if (bindingManagerBase != null) { 
      return bindingManagerBase; 
     } 
    } 

    // Check for previously created binding manager 
    // 
    HashKey key = GetKey(dataSource, dataMember); 
    WeakReference wRef; 
    wRef = listManagers[key] as WeakReference; 
    if (wRef != null) 
     bindingManagerBase = (BindingManagerBase) wRef.Target; 
    if (bindingManagerBase != null) { 
     return bindingManagerBase; 
    } 

    if (dataMember.Length == 0) { 
     // No data member specified, so create binding manager directly on the data source 
     // 
     if (dataSource is IList || dataSource is IListSource) { 
      // IListSource so we can bind the dataGrid to a table and a dataSet 
      bindingManagerBase = new CurrencyManager(dataSource); 
     } 
     else { 
      // Otherwise assume simple property binding 
      bindingManagerBase = new PropertyManager(dataSource); 
     } 
    } 
    else { 
     // Data member specified, so get data source's binding manager, and hook a 'related' binding manager to it 
     // 
     int lastDot = dataMember.LastIndexOf("."); 
     string dataPath = (lastDot == -1) ? "" : dataMember.Substring(0, lastDot); 
     string dataField = dataMember.Substring(lastDot + 1); 

     BindingManagerBase formerManager = EnsureListManager(dataSource, dataPath); 

     PropertyDescriptor prop = formerManager.GetItemProperties().Find(dataField, true); 
     if (prop == null) 
      throw new ArgumentException(SR.GetString(SR.RelatedListManagerChild, dataField)); 

     if (typeof(IList).IsAssignableFrom(prop.PropertyType)) 
      bindingManagerBase = new RelatedCurrencyManager(formerManager, dataField); 
     else 
      bindingManagerBase = new RelatedPropertyManager(formerManager, dataField); 
    } 

My dataSource nie jest ICurrencyManagerProvider

Jaka jest różnica między tymi dwoma połączeniami, i dlaczego dostępu do PropertyManager przez tylko dataSource powoduje powiązanie dla innego okna z aktualizacją osobnego BindingContext?

+0

To wstyd, że nikt nie rozważył tej kwestii, uważam, że to pytanie jest intrygujące. – DonBoitnott

Odpowiedz

0

Podczas uzyskiwania dostępu do BindingContext[dataSource], faktycznie uzyskujesz dostęp do BindingContext[dataSource, ""]. Tak więc nie ma żadnej różnicy z wyjątkiem HashCode, który używa zarówno wartości DataSource i DataMember do obliczeń, które można zobaczyć w swoim link.

public override int GetHashCode() { 
    return dataSourceHashCode * dataMember.GetHashCode(); 
} 

Problem w oddzielnych BindingContext obiektów może być tak, że nie są one wypełnione poprawnie.

1

Nie stwierdza to wyraźnie, tak w przypadku, gdy nie zauważył, że jest to kolekcja patrzeć, że nie działa zgodnie z oczekiwaniami, ze względu na równego ręcznym.

BindingContext [źródło danych] jest wyszukiwanie przeciwko kolekcji używając źródło danych jako kluczowy.

BindingContext [źródła danych, DataMember] jest wyszukiwanie na gromadzenie użyciu klucza kompozytowego.

Jest jasne z kodu, który BindingContext utrzymuje dwa oddzielne zbiory. Jedna kolekcja na kluczu źródła danych , a druga kolekcja na podstawie klucza kompozytowego .

Oczywiście zastąpienie równej wartości dwukrotnie spowoduje umieszczenie podobnych wartości do źródła danych w kolekcji BindingContext [źródło danych], ale spowoduje powstanie jednego wpisu kolekcji, ponieważ wartości/klucze są takie same. Natomiast umieści dwa wpisy w BindingContext [źródło danych, datamember].

Jeśli wglądu obu kolekcji i można uzyskać liczy zobaczysz, że później kolekcja ma więcej wpisów.

Należy pamiętać, że istnieją dwa oddzielne obiekty, które oceniają się jako równe, a nie dwa odniesienia do tego samego obiektu. To jest sedno problemu.

Wygląda na to, że podczas dodawania wpisów do drugiej kolekcji (BindingContext [źródło danych, datamember]) datamember ocenia wartość na unikatową.

+1

Mówiąc po prostu: Twoje równe zastąpienie zwraca true, chociaż nie są one w rzeczywistości równymi obiektami. – pashute