diff --git a/BCL.csproj b/BCL.csproj
index 84ea30936..b5e8216d0 100644
--- a/BCL.csproj
+++ b/BCL.csproj
@@ -152,6 +152,15 @@
text.d.ts
+
+
+ text-view.d.ts
+
+
+
+
+ text-view.d.ts
+
diff --git a/ui/core/observable.ts b/ui/core/observable.ts
index 19a76f130..0213f18bb 100644
--- a/ui/core/observable.ts
+++ b/ui/core/observable.ts
@@ -1 +1,112 @@
-
\ No newline at end of file
+export enum ChangePhase {
+ Changing,
+ Changed
+}
+
+export interface ChangeData {
+ eventName: string;
+ sender: Observable;
+ phase?: ChangePhase;
+}
+
+export interface PropertyChangeData extends ChangeData {
+ propertyName: string;
+ oldValue: any;
+ newValue: any;
+ cancel?: boolean;
+}
+
+export class Observable {
+ public static propertyChangeEvent = "propertyChange";
+ private _observers = {};
+
+ // true to track the Changing phase, false otherwise
+ private _trackChanging = false;
+
+ public bind(eventName: string, callback: (data: ChangeData) => void) {
+ this.verifyCallback(callback);
+ var list = this.getEventList(eventName, true);
+ list.push(callback);
+ }
+
+ public setProperty(name: string, value: any) {
+ // TODO: Parameter validation
+
+ if (!(name in this._observers)) {
+ // no observers to notify for the PropertyChange event
+ return;
+ }
+
+ // create data for the change
+ var data: PropertyChangeData = {
+ eventName: Observable.propertyChangeEvent,
+ propertyName: name,
+ sender: this,
+ oldValue: this[name],
+ newValue: value,
+ cancel: false
+ };
+
+ if (this._trackChanging) {
+ data.phase = ChangePhase.Changing;
+ this.notifyObservers(data);
+ if (data.cancel) {
+ // change is canceled by an observer
+ // TODO: define some priority, e.g. if someone cancels the change should others be able to override this cancelation?
+ return;
+ }
+ }
+
+ data.phase = ChangePhase.Changed;
+ this.notifyObservers(data);
+
+ this.setPropertyCore(data);
+ }
+
+ public getProperty(name: string): any {
+ return this[name];
+ }
+
+ /**
+ * This method is intended to be overriden by inheritors to specify additional
+ */
+ public setPropertyCore(data: PropertyChangeData) {
+ // get the new value from the data since some observer may have it modified - e.g. validation scenario
+ this[data.eventName] = data.newValue;
+ }
+
+ private getEventList(eventName: string, createIfNeeded?: boolean): Array<(data: ChangeData) => void> {
+ if (!eventName) {
+ throw new TypeError("EventName must be valid string.");
+ }
+
+ var list = void>>this._observers[eventName];
+ if (!list && createIfNeeded) {
+ list = new Array<(data: ChangeData) => void>();
+ this._observers[eventName] = list;
+ }
+
+ return list;
+ }
+
+ private verifyCallback(callback: any) {
+ if (!callback || typeof callback !== "function") {
+ throw new TypeError("Callback must be a valid function.");
+ }
+ }
+
+ // The method will return true if the change is accepted, false otherwise
+ private notifyObservers(data: ChangeData) {
+ var observers = this.getEventList(data.eventName);
+ if (!observers) {
+ return;
+ }
+
+ var i,
+ callback;
+ for (i = 0; i < observers.length; i++) {
+ callback = observers[i];
+ callback(data);
+ }
+ }
+}
\ No newline at end of file
diff --git a/ui/core/proxy.ts b/ui/core/proxy.ts
new file mode 100644
index 000000000..b5f88f92b
--- /dev/null
+++ b/ui/core/proxy.ts
@@ -0,0 +1,12 @@
+import observable = require("ui/core/observable");
+
+export class ProxyObject extends observable.Observable {
+ public setPropertyCore(data: observable.PropertyChangeData) {
+ super.setPropertyCore(data);
+ this.setNativeProperty(data);
+ }
+
+ public setNativeProperty(data: observable.PropertyChangeData) {
+ // TODO:
+ }
+}
\ No newline at end of file
diff --git a/ui/core/view.ts b/ui/core/view.ts
index 19a76f130..0c1db8d9a 100644
--- a/ui/core/view.ts
+++ b/ui/core/view.ts
@@ -1 +1,5 @@
-
\ No newline at end of file
+import proxy = require("ui/core/proxy");
+
+export class View extends proxy.ProxyObject {
+
+}
\ No newline at end of file
diff --git a/ui/text-view/text-view.android.ts b/ui/text-view/text-view.android.ts
new file mode 100644
index 000000000..9a401df34
--- /dev/null
+++ b/ui/text-view/text-view.android.ts
@@ -0,0 +1,21 @@
+import observable = require("ui/core/observable");
+import view = require("ui/core/view");
+
+export class TextView extends view.View {
+ public android: android.widget.TextView;
+
+ get text(): string {
+ if (this.android) {
+ return this.android.getText().toString();
+ }
+
+ return undefined;
+ }
+ set text(value: string) {
+
+ }
+
+ public setNativeProperty(data: observable.PropertyChangeData) {
+ // TODO:
+ }
+}
\ No newline at end of file
diff --git a/ui/text-view/text-view.common.ts b/ui/text-view/text-view.common.ts
new file mode 100644
index 000000000..1f46d6a8e
--- /dev/null
+++ b/ui/text-view/text-view.common.ts
@@ -0,0 +1,14 @@
+import observable = require("ui/core/observable");
+import view = require("ui/core/view");
+
+export class TextView extends view.View {
+ public static textProperty = "text";
+
+ get text(): string {
+ return this.getProperty(TextView.textProperty);
+ }
+
+ public setNativeProperty(data: observable.PropertyChangeData) {
+ // TODO:
+ }
+}
\ No newline at end of file
diff --git a/ui/text-view/text-view.d.ts b/ui/text-view/text-view.d.ts
new file mode 100644
index 000000000..5f282702b
--- /dev/null
+++ b/ui/text-view/text-view.d.ts
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/ui/text-view/text-view.ios.ts b/ui/text-view/text-view.ios.ts
new file mode 100644
index 000000000..fbada2d49
--- /dev/null
+++ b/ui/text-view/text-view.ios.ts
@@ -0,0 +1,5 @@
+import view = require("ui/core/view");
+
+export class TextView extends view.View {
+
+}
\ No newline at end of file