Чем отличается доступ к BindingContext [dataSource] и BindingContext [dataSource, dataMember]?

Мы столкнулись с проблемой , где

  • У нас есть два экземпляра одного окна в рабочей области MDI, связанное с двумя отдельными объектными моделями.
  • Объектные модели имеют свои методы .Equals и .GetHashCode, которые считаются равными.
  • Вызов .EndCurrentEdit() в окне 2 запускает обновление привязки для окна 1
  • Оба окна настроены на использование отдельных BindingContext

Мы обнаружили, что проблема связана с вызовом

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

Если мы изменим это на

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

Он работает правильно. Он также работает правильно, если мы удалим наши переопределения .Equals и .GetHashCode, поэтому две объектные модели больше не считаются равными.

Это не имеет смысла для меня, потому что окна одинаковы, поэтому свойство dataMember будет таким же.

От эта ссылка, я считаю, что определение этих вызовов:

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 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 не является ICurrencyManagerProvider

В чем разница между этими двумя вызовами и почему доступ к PropertyManager только с помощью dataSource приводит к привязкам для другого окна с обновляемым отдельным BindingContext?

Ответ 1

Вы не указали это явно, поэтому, если вы не заметили, что это поиск коллекции, который не работает так, как вы ожидаете, из-за equal переопределить.

BindingContext [datasource] - это поиск по коллекции с использованием источника данных в качестве ключа.

BindingContext [datasource, datamember] - это поиск по коллекции с использованием составного ключа.

Из кода видно, что BindingContext поддерживает две отдельные коллекции. Одна коллекция с ключом datasource, а другая - на основе составного ключа.

Очевидно, что ваше переопределение равных будет дважды помещать аналогичные значения в источник данных в коллекции BindingContext [datasource], но приведет к одной записи коллекции, поскольку значения/ключи одинаковы. Принимая во внимание, что в BindingContext [datasource, datamember] будут помещены две записи.

Если вы проверите обе коллекции и получите количество, вы увидите, что в более поздней коллекции больше записей.

Вы должны помнить, что у вас есть два отдельных объекта, которые оцениваются равными, а не две ссылки на один и тот же объект. В этом суть проблемы.

Похоже, что при добавлении записей во второй набор (BindingContext [datasource, datamember]) datamember оценивается как уникальный.

Ответ 2

При обращении к BindingContext[dataSource] вы фактически получаете доступ к BindingContext[dataSource, ""]. Таким образом, нет никакой разницы, кроме HashCode, которая использует значения DataSource и DataMember для расчета, которые можно увидеть в вашей .

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

Проблема в отдельных объектах BindingContext может заключаться в том, что они не заполнены правильно.