【问题标题】:What is different when accessing BindingContext[dataSource] vs BindingContext[dataSource, dataMember]?访问 BindingContext[dataSource] 与 BindingContext[dataSource, dataMember] 有什么不同?
【发布时间】:2014-08-03 01:41:38
【问题描述】:

我们遇到了problem

  • 我们在 MDI 工作区中有两个相同窗口的实例,绑定到两个单独的对象模型。
  • 对象模型的 .Equals.GetHashCode 方法被覆盖以被视为相等。
  • 在窗口 2 上调用 .EndCurrentEdit() 会触发窗口 1 的绑定更新
  • 两个窗口都设置为使用单独的BindingContext

我们发现问题与调用有关

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

如果我们把它改成

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

它工作正常。如果我们删除 .Equals.GetHashCode 覆盖,它也可以正常工作,因此这两个对象模型不再被视为相等。

这对我来说没有意义,因为窗口是相同的,所以 dataMember 属性也将相同。

来自this link,我相信这些调用的定义是:

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);
    }

我的dataSource 不是ICurrencyManagerProvider

这两个调用之间有什么区别,为什么只通过dataSource 访问PropertyManager 会导致另一个窗口的绑定被更新,其中一个单独的BindingContext 被更新?

【问题讨论】:

  • 很遗憾没有人在这个问题上权衡,我觉得这个问题很有趣。

标签: c# winforms binding .net-3.5


【解决方案1】:

您没有明确说明这一点,所以如果您没有注意到 collection 查找没有按您预期的那样工作,因为 equal 覆盖。

BindingContext[datasource] 是使用 datasource 作为键对集合进行查找。

BindingContext[datasource, datamember] 是对集合的查找使用复合键

从代码中可以清楚地看出,BindingContext 正在维护两个独立的集合。一个是基于数据源键的集合,另一个是基于复合键的集合。

显然,您对 equal 的覆盖将两次将相似的值放置到 BindingContext[datasource] 集合中的数据源中,但会导致一个集合条目,因为值/键是相同的。然而,它将在 BindingContext[datasource, datamember] 中放置两个条目。

如果您检查两个集合并获得计数,您会发现后面的集合有更多条目

您必须记住,您有两个独立的对象,它们的计算结果相等,而不是对同一对象的两个引用。这是问题的症结所在。

当将条目添加到第二个集合 (BindingContext[datasource, datamember]) 时,数据成员的计算结果似乎是唯一的。

【讨论】:

  • 简单地说:虽然它们实际上不是相等的对象,但您的 equals 覆盖正在返回 true。
【解决方案2】:

当您访问BindingContext[dataSource] 时,您实际上是在访问BindingContext[dataSource, ""]。因此,除了使用 DataSourceDataMember 值进行计算的 HashCode 之外没有任何区别,这可以在您的 link 中看到。

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

单独的BindingContext 对象中的问题可能是它们没有正确填充。

【讨论】:

    猜你喜欢
    • 2019-12-25
    • 1970-01-01
    • 2010-10-09
    • 1970-01-01
    • 1970-01-01
    • 2018-08-21
    • 2018-01-28
    • 2020-01-20
    • 2011-02-16
    相关资源
    最近更新 更多