diff --git a/CrossPlatformModules.csproj b/CrossPlatformModules.csproj
index 8bafda30a..b8b21c6f6 100644
--- a/CrossPlatformModules.csproj
+++ b/CrossPlatformModules.csproj
@@ -347,6 +347,10 @@
trace.d.ts
+
+ repeater.d.ts
+
+
list-picker.d.ts
@@ -1528,6 +1532,9 @@
PreserveNewest
+
+ PreserveNewest
+
diff --git a/ui/repeater/package.json b/ui/repeater/package.json
new file mode 100644
index 000000000..219eeec41
--- /dev/null
+++ b/ui/repeater/package.json
@@ -0,0 +1,2 @@
+{ "name" : "repeater",
+ "main" : "repeater.js" }
\ No newline at end of file
diff --git a/ui/repeater/repeater.d.ts b/ui/repeater/repeater.d.ts
new file mode 100644
index 000000000..e4885cadc
--- /dev/null
+++ b/ui/repeater/repeater.d.ts
@@ -0,0 +1,81 @@
+/**
+ * Contains the Repeater class, which represents a UI Repeater component.
+ */
+declare module "ui/repeater" {
+ import view = require("ui/core/view");
+ import dependencyObservable = require("ui/core/dependency-observable");
+
+ /**
+ * Represents a UI Repeater component.
+ */
+ export class Repeater extends view.View {
+ /**
+ * Represents the observable property backing the orientation property of each Repeater instance.
+ */
+ public static orientationProperty: dependencyObservable.Property;
+
+ /**
+ * Dependency property used to support binding operations for the items wrapping of the current Repeater instance.
+ */
+ public static wrapProperty: dependencyObservable.Property;
+
+ /**
+ * Represents the observable property backing the itemWidth property of each Repeater instance.
+ */
+ public static itemWidthProperty: dependencyObservable.Property;
+
+ /**
+ * Represents the observable property backing the itemHeight property of each Repeater instance.
+ */
+ public static itemHeightProperty: dependencyObservable.Property;
+
+ /**
+ * Represents the observable property backing the items property of each Repeater instance.
+ */
+ public static itemsProperty: dependencyObservable.Property;
+
+ /**
+ * Represents the item template property of each Repeater instance.
+ */
+ public static itemTemplateProperty: dependencyObservable.Property;
+
+ /**
+ * Gets or sets if layout should be horizontal or vertical.
+ * The default value is vertical.
+ */
+ orientation: string;
+
+ /**
+ * Gets or sets whether the Repeater wraps items or not.
+ */
+ wrap: boolean;
+
+ /**
+ * Gets or sets the width used to measure and layout each child.
+ * Default value is Number.NaN which does not restrict children.
+ */
+ itemWidth: number;
+
+ /**
+ * Gets or sets the height used to measure and layout each child.
+ * Default value is Number.NaN which does not restrict children.
+ */
+ itemHeight: number;
+
+ /**
+ * Gets or set the items collection of the Repeater.
+ * The items property can be set to an array or an object defining length and getItem(index) method.
+ */
+ items: any;
+
+ /**
+ * Gets or set the item template of the Repeater.
+ */
+ itemTemplate: string;
+
+ /**
+ * Forces the Repeater to reload all its items.
+ */
+ refresh();
+ }
+}
\ No newline at end of file
diff --git a/ui/repeater/repeater.ts b/ui/repeater/repeater.ts
new file mode 100644
index 000000000..6069dbc38
--- /dev/null
+++ b/ui/repeater/repeater.ts
@@ -0,0 +1,156 @@
+import definition = require("ui/repeater");
+import proxy = require("ui/core/proxy");
+import dependencyObservable = require("ui/core/dependency-observable");
+import viewModule = require("ui/core/view");
+import observable = require("data/observable");
+import observableArray = require("data/observable-array");
+import weakEvents = require("ui/core/weak-event-listener");
+import enums = require("ui/enums");
+
+var ITEMS = "items";
+var WRAP = "wrap";
+var ORIENTATION = "orientation";
+var ITEMTEMPLATE = "itemTemplate";
+var ITEMWIDTH = "itemWidth";
+var ITEMHEIGHT = "itemHeight";
+var REPEATER = "Repeater";
+
+export module knownTemplates {
+ export var itemTemplate = "itemTemplate";
+}
+
+function onItemsPropertyChanged(data: dependencyObservable.PropertyChangeData) {
+ var repeater = data.object;
+ repeater._onItemsPropertyChanged(data);
+}
+
+function onItemTemplatePropertyChanged(data: dependencyObservable.PropertyChangeData) {
+ var repeater = data.object;
+ repeater.refresh();
+}
+
+function validateOrientation(value: any): boolean {
+ return value === enums.Orientation.vertical || value === enums.Orientation.horizontal;
+}
+
+function isWidthHeightValid(value: any): boolean {
+ return isNaN(value) || (value >= 0.0 && value !== Number.POSITIVE_INFINITY);
+}
+
+export class Repeater extends viewModule.View implements definition.Repeater {
+
+ public static itemsProperty = new dependencyObservable.Property(
+ ITEMS,
+ REPEATER,
+ new proxy.PropertyMetadata(
+ undefined,
+ dependencyObservable.PropertyMetadataSettings.AffectsLayout,
+ onItemsPropertyChanged
+ )
+ );
+
+ public static itemTemplateProperty = new dependencyObservable.Property(
+ ITEMTEMPLATE,
+ REPEATER,
+ new proxy.PropertyMetadata(
+ undefined,
+ dependencyObservable.PropertyMetadataSettings.AffectsLayout,
+ onItemTemplatePropertyChanged
+ )
+ );
+
+ public static orientationProperty = new dependencyObservable.Property(
+ ORIENTATION,
+ REPEATER,
+ new proxy.PropertyMetadata(enums.Orientation.vertical,
+ dependencyObservable.PropertyMetadataSettings.AffectsLayout,
+ undefined,
+ validateOrientation)
+ );
+
+ public static wrapProperty = new dependencyObservable.Property(
+ WRAP,
+ REPEATER,
+ new proxy.PropertyMetadata(false, dependencyObservable.PropertyMetadataSettings.AffectsLayout)
+ );
+
+ public static itemWidthProperty = new dependencyObservable.Property(
+ ITEMWIDTH,
+ REPEATER,
+ new proxy.PropertyMetadata(Number.NaN,
+ dependencyObservable.PropertyMetadataSettings.AffectsLayout,
+ undefined,
+ isWidthHeightValid)
+ );
+
+ public static itemHeightProperty = new dependencyObservable.Property(
+ ITEMHEIGHT,
+ REPEATER,
+ new proxy.PropertyMetadata(Number.NaN,
+ dependencyObservable.PropertyMetadataSettings.AffectsLayout,
+ undefined,
+ isWidthHeightValid)
+ );
+
+ get items(): any {
+ return this._getValue(Repeater.itemsProperty);
+ }
+ set items(value: any) {
+ this._setValue(Repeater.itemsProperty, value);
+ }
+
+ get itemTemplate(): string {
+ return this._getValue(Repeater.itemTemplateProperty);
+ }
+ set itemTemplate(value: string) {
+ this._setValue(Repeater.itemTemplateProperty, value);
+ }
+
+ public refresh() {
+ //
+ }
+
+ public _onItemsPropertyChanged(data: dependencyObservable.PropertyChangeData) {
+ if (data.oldValue instanceof observable.Observable) {
+ weakEvents.removeWeakEventListener(data.oldValue, observableArray.ObservableArray.changeEvent, this._onItemsChanged, this);
+ }
+
+ if (data.newValue instanceof observable.Observable) {
+ weakEvents.addWeakEventListener(data.newValue, observableArray.ObservableArray.changeEvent, this._onItemsChanged, this);
+ }
+
+ this.refresh();
+ }
+
+ private _onItemsChanged(args: observable.EventData) {
+ this.refresh();
+ }
+
+ get wrap(): boolean {
+ return this._getValue(Repeater.wrapProperty);
+ }
+ set wrap(value: boolean) {
+ this._setValue(Repeater.wrapProperty, value);
+ }
+
+ get orientation(): string {
+ return this._getValue(Repeater.orientationProperty);
+ }
+ set orientation(value: string) {
+ this._setValue(Repeater.orientationProperty, value);
+ }
+
+ get itemWidth(): number {
+ return this._getValue(Repeater.itemWidthProperty);
+ }
+ set itemWidth(value: number) {
+ this._setValue(Repeater.itemWidthProperty, value);
+ }
+
+ get itemHeight(): number {
+ return this._getValue(Repeater.itemHeightProperty);
+ }
+ set itemHeight(value: number) {
+ this._setValue(Repeater.itemHeightProperty, value);
+ }
+}
\ No newline at end of file