Fixed issue when bindingContext is bound more than once.

This commit is contained in:
Nedyalko Nikolov
2015-04-30 13:48:52 +03:00
parent 315959a590
commit 2e4b2eacf2
10 changed files with 136 additions and 46 deletions

View File

@@ -7,13 +7,19 @@ import types = require("utils/types");
import trace = require("trace");
import polymerExpressions = require("js-libs/polymer-expressions");
import bindingBuilder = require("../builder/binding-builder");
import viewModule = require("ui/core/view");
var bindingContextProperty = new dependencyObservable.Property(
"bindingContext",
"Bindable",
new dependencyObservable.PropertyMetadata(undefined, dependencyObservable.PropertyMetadataSettings.Inheritable) // TODO: Metadata options?
new dependencyObservable.PropertyMetadata(undefined, dependencyObservable.PropertyMetadataSettings.Inheritable, onBindingContextChanged)
);
function onBindingContextChanged(data: dependencyObservable.PropertyChangeData) {
var bindable = <Bindable>data.object;
bindable._onBindingContextChanged(data.oldValue, data.newValue);
}
var contextKey = "context";
var resourcesKey = "resources";
@@ -73,24 +79,21 @@ export class Bindable extends dependencyObservable.DependencyObservable implemen
public _onPropertyChanged(property: dependencyObservable.Property, oldValue: any, newValue: any) {
trace.write("Bindable._onPropertyChanged(" + this + ") " + property.name, trace.categories.Binding);
super._onPropertyChanged(property, oldValue, newValue);
if (property === Bindable.bindingContextProperty) {
this._onBindingContextChanged(oldValue, newValue);
}
var binding = this._bindings[property.name];
if (binding) {
// we should remove (unbind and delete) binding if binding is oneWay and update is not triggered
// by binding itself.
var shouldRemoveBinding = !binding.updating && !binding.options.twoWay;
if (shouldRemoveBinding) {
trace.write("_onPropertyChanged(" + this + ") removing binding for property: " + property.name, trace.categories.Binding);
this.unbind(property.name);
if (this instanceof viewModule.View) {
if ((<viewModule.View>(<any>this))._isInheritedChange() === true) {
return
}
else {
}
var binding = this._bindings[property.name];
if (binding && !binding.updating) {
if (binding.options.twoWay) {
trace.write("_updateTwoWayBinding(" + this + "): " + property.name, trace.categories.Binding);
this._updateTwoWayBinding(property.name, newValue);
}
else {
trace.write("_onPropertyChanged(" + this + ") removing binding for property: " + property.name, trace.categories.Binding);
this.unbind(property.name);
}
}
}
@@ -99,8 +102,7 @@ export class Bindable extends dependencyObservable.DependencyObservable implemen
for (var p in this._bindings) {
binding = this._bindings[p];
if (binding.options.targetProperty === Bindable.bindingContextProperty.name && binding.updating) {
// Updating binding context trough binding should not rebind the binding context.
if (binding.updating) {
continue;
}

View File

@@ -23,9 +23,19 @@ function validateRegisterParameters(name: string, ownerType: string) {
}
}
function getPropertyByNameAndType(name: string, ownerType: string): Property {
var key = generatePropertyKey(name, ownerType);
return propertyFromKey[key];
function getPropertyByNameAndType(name: string, owner: any): Property {
var baseClasses = types.getBaseClasses(owner);
var i;
var result;
var key;
for (i = 0; i < baseClasses.length; i++) {
key = generatePropertyKey(name, baseClasses[i]);
result = propertyFromKey[key];
if (result) {
break;
}
}
return result;
}
export module PropertyMetadataSettings {
@@ -254,13 +264,10 @@ export class PropertyEntry implements definition.PropertyEntry {
}
export class DependencyObservable extends observable.Observable {
// TODO: measure the performance of the dictionary vs. JS Object with numeric keys
// private _values = new containers.Dictionary<string, any>(new containers.StringComparer());
private _propertyEntries = {};
public set(name: string, value: any) {
// TODO: Properties must be registered with the correct owner type for this routine to work
var property = getPropertyByNameAndType(name, this.typeName);
var property = getPropertyByNameAndType(name, this);
if (property) {
this._setValue(property, value, ValueSource.Local);
} else {
@@ -269,7 +276,7 @@ export class DependencyObservable extends observable.Observable {
}
public get(name: string): any {
var property = getPropertyByNameAndType(name, this.typeName);
var property = getPropertyByNameAndType(name, this);
if (property) {
return this._getValue(property);
} else {

View File

@@ -133,6 +133,7 @@ export class View extends proxy.ProxyObject implements definition.View {
public _cssClasses: Array<string> = [];
private _gesturesObserver: gestures.GesturesObserver;
private _updatingInheritedProperties: boolean;
public _options: definition.Options;
@@ -397,24 +398,40 @@ export class View extends proxy.ProxyObject implements definition.View {
public _onPropertyChanged(property: dependencyObservable.Property, oldValue: any, newValue: any) {
super._onPropertyChanged(property, oldValue, newValue);
// Implement Binding inheritance here.
if (this._childrenCount > 0) {
var shouldUpdateInheritableProps = ((property.metadata && property.metadata.inheritable) &&
property.name !== "bindingContext" &&
!(property instanceof styling.Property));
var that = this;
if (shouldUpdateInheritableProps) {
var notifyEachChild = function (child: View) {
child._setValue(property, newValue, dependencyObservable.ValueSource.Inherited);
child._setValue(property, that._getValue(property), dependencyObservable.ValueSource.Inherited);
return true;
};
this._updatingInheritedProperties = true;
this._eachChildView(notifyEachChild);
this._updatingInheritedProperties = false;
}
}
this._checkMetadataOnPropertyChanged(property.metadata);
}
public _isInheritedChange() {
if (this._updatingInheritedProperties) {
return true;
}
var parentView: View;
parentView = <View>(this.parent);
while (parentView) {
if (parentView._updatingInheritedProperties) {
return true;
}
parentView = <View>(parentView.parent);
}
return false;
}
public _checkMetadataOnPropertyChanged(metadata: dependencyObservable.PropertyMetadata) {
if (metadata.affectsLayout) {
this.requestLayout();
@@ -675,21 +692,6 @@ export class View extends proxy.ProxyObject implements definition.View {
return changed;
}
public _onBindingContextChanged(oldValue: any, newValue: any) {
super._onBindingContextChanged(oldValue, newValue);
if (this._childrenCount === 0) {
return;
}
var thatContext = this.bindingContext;
var eachChild = function (child: View): boolean {
child._setValue(bindable.Bindable.bindingContextProperty, thatContext, dependencyObservable.ValueSource.Inherited);
return true;
}
this._eachChildView(eachChild);
}
private _applyStyleFromScope() {
var rootPage = getAncestor(this, "Page");
if (!rootPage || !rootPage.isLoaded) {
@@ -784,7 +786,7 @@ export class View extends proxy.ProxyObject implements definition.View {
private _inheritProperties(parentView: View) {
var that = this;
var inheritablePropertySetCallback = function (property: dependencyObservable.Property) {
if (property instanceof styling.Property || property.name === "bindingContext") {
if (property instanceof styling.Property) {
return true;
}
if (property.metadata && property.metadata.inheritable) {
@@ -827,7 +829,7 @@ export class View extends proxy.ProxyObject implements definition.View {
view._setValue(bindable.Bindable.bindingContextProperty, undefined, dependencyObservable.ValueSource.Inherited);
var inheritablePropertiesSetCallback = function (property: dependencyObservable.Property) {
if (property instanceof styling.Property || property.name === "bindingContext") {
if (property instanceof styling.Property) {
return true;
}
if (property.metadata && property.metadata.inheritable) {
@@ -892,4 +894,4 @@ export class View extends proxy.ProxyObject implements definition.View {
public focus(): boolean {
return undefined;
}
}
}

1
ui/core/view.d.ts vendored
View File

@@ -386,6 +386,7 @@ declare module "ui/core/view" {
// TODO: Implement logic for stripping these lines out
//@private
_isInheritedChange(): boolean;
_domId: number;
_cssClasses: Array<string>;