Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is different when accessing BindingContext[dataSource] vs BindingContext[dataSource, dataMember]?

We have run into a problem where

  • We have two instances of the same window in an MDI workspace bound to two separate object models.
  • The object models have their .Equals and .GetHashCode methods overwritten to be considered equal.
  • Calling .EndCurrentEdit() on window 2 is triggering a binding update for Window 1
  • Both windows are setup to use separate a BindingContext

We have discovered the problem has to do with calling

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

If we change that to

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

It works correctly. It also works correctly if we remove our .Equals and .GetHashCode overrides so the two object models are no longer considered equal.

That doesn't make sense to me because the windows are the same, so the dataMember property would be the same too.

From this link, I believe the definition of these calls is:

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 is not an ICurrencyManagerProvider

What is the difference between these two calls, and why does accessing the PropertyManager by only the dataSource result in the bindings for another window with a separate BindingContext being updated?

like image 801
Rachel Avatar asked Jun 12 '14 16:06

Rachel


People also ask

What is BindingContext in c#?

The BindingContext is aware of the first binding ( TextBox1 to Customers. FirstName ), so it would use the same CurrencyManager, as both text boxes are bound to the same dataset ( DataSet1 ). TextBox2.DataBindings.Add("Text", dataSet1, "Customers.LastName") C# Copy. textBox2.

What is a Binding context?

A binding context is an object that holds data that you can reference from your bindings. While applying bindings, Knockout automatically creates and manages a hierarchy of binding contexts. The root level of the hierarchy refers to the viewModel parameter you supplied to ko. applyBindings(viewModel) .


1 Answers

You don't state this explicitly, so in case you haven't noticed it is the collection look up that is not working as you expect, because of the equal override.

BindingContext[datasource] is a lookup against the collection using datasource as the key.

BindingContext[datasource, datamember] is a lookup against the collection using a composite key.

It is clear from the code that BindingContext is maintaining two separate collections. One a collection on a datasource key and the other a collection based on a composite key.

Obviously your override of equal will twice place similar values to datasource in the BindingContext[datasource] collection, but will result in one collection entry, because the values/keys are the same. Whereas, it will place two entries in BindingContext[datasource, datamember].

If you inspect both collections and can get the counts you'll see that the later collection has more entries.

You have to remember that you have two separate objects that evaluate to equal, not two references to the same object. This is the crux of the problem.

It would appear that when adding the entries to the second collection (BindingContext[datasource, datamember]) datamember evaluates to unique.

like image 106
N-ate Avatar answered Sep 16 '22 20:09

N-ate