diff --git a/Xamarin.Forms.ControlGallery.Android/Properties/AndroidManifest.xml b/Xamarin.Forms.ControlGallery.Android/Properties/AndroidManifest.xml
index 9bbcafdfce4..6b7581d5369 100644
--- a/Xamarin.Forms.ControlGallery.Android/Properties/AndroidManifest.xml
+++ b/Xamarin.Forms.ControlGallery.Android/Properties/AndroidManifest.xml
@@ -16,7 +16,7 @@
-
+
\ No newline at end of file
diff --git a/Xamarin.Forms.ControlGallery.WP8/App.xaml.cs b/Xamarin.Forms.ControlGallery.WP8/App.xaml.cs
index 5b83678624f..ea0eed04bb1 100644
--- a/Xamarin.Forms.ControlGallery.WP8/App.xaml.cs
+++ b/Xamarin.Forms.ControlGallery.WP8/App.xaml.cs
@@ -209,7 +209,7 @@ void InitializeLanguage()
//
// If a compiler error is hit then ResourceFlowDirection is missing from
// the resource file.
- FlowDirection flow = (FlowDirection)Enum.Parse(typeof(FlowDirection), AppResources.ResourceFlowDirection);
+ System.Windows.FlowDirection flow = (System.Windows.FlowDirection)Enum.Parse(typeof(System.Windows.FlowDirection), AppResources.ResourceFlowDirection);
RootFrame.FlowDirection = flow;
}
catch
diff --git a/Xamarin.Forms.ControlGallery.WindowsUniversal/Package.appxmanifest b/Xamarin.Forms.ControlGallery.WindowsUniversal/Package.appxmanifest
index 6430b2f6c95..8685c121880 100644
--- a/Xamarin.Forms.ControlGallery.WindowsUniversal/Package.appxmanifest
+++ b/Xamarin.Forms.ControlGallery.WindowsUniversal/Package.appxmanifest
@@ -12,6 +12,8 @@
+
+
diff --git a/Xamarin.Forms.ControlGallery.iOS/Info.plist b/Xamarin.Forms.ControlGallery.iOS/Info.plist
index 2b8924ceedc..7734872cb3a 100644
--- a/Xamarin.Forms.ControlGallery.iOS/Info.plist
+++ b/Xamarin.Forms.ControlGallery.iOS/Info.plist
@@ -96,6 +96,13 @@
{320, 480}
+ CFBundleDevelopmentRegion
+ en
+ CFBundleLocalizations
+
+ en
+ ar
+
NSAppTransportSecurity
NSAllowsArbitraryLoads
diff --git a/Xamarin.Forms.ControlGallery.iOS/Xamarin.Forms.ControlGallery.iOS.csproj b/Xamarin.Forms.ControlGallery.iOS/Xamarin.Forms.ControlGallery.iOS.csproj
index b43776fc58a..f8c97b61dff 100644
--- a/Xamarin.Forms.ControlGallery.iOS/Xamarin.Forms.ControlGallery.iOS.csproj
+++ b/Xamarin.Forms.ControlGallery.iOS/Xamarin.Forms.ControlGallery.iOS.csproj
@@ -78,7 +78,7 @@
False
False
True
-
+ mideast
True
@@ -132,6 +132,9 @@
true
+
+
+
diff --git a/Xamarin.Forms.Controls/ControlGalleryPages/FlowDirectionGallery.cs b/Xamarin.Forms.Controls/ControlGalleryPages/FlowDirectionGallery.cs
new file mode 100644
index 00000000000..eb2e0f79172
--- /dev/null
+++ b/Xamarin.Forms.Controls/ControlGalleryPages/FlowDirectionGallery.cs
@@ -0,0 +1,429 @@
+using System;
+using System.Linq;
+
+namespace Xamarin.Forms.Controls
+{
+
+ public class FlowDirectionGalleryLandingPage : ContentPage
+ {
+ FlowDirection DeviceDirection => Device.FlowDirection;
+
+ public FlowDirectionGalleryLandingPage()
+ {
+
+ var np = new Button { Text = "Try NavigationPage", Command = new Command(() => { PushNavigationPage(DeviceDirection); }) };
+ var mdp = new Button { Text = "Try MasterDetailPage", Command = new Command(() => { PushMasterDetailPage(DeviceDirection); }) };
+ var crp = new Button { Text = "Try CarouselPage", Command = new Command(() => { PushCarouselPage(DeviceDirection); }) };
+ var tp = new Button { Text = "Try TabbedPage", Command = new Command(() => { PushTabbedPage(DeviceDirection); }) };
+ var cp = new Button { Text = "Try ContentPage", Command = new Command(() => { PushContentPage(DeviceDirection); }) };
+
+ Content = new StackLayout
+ {
+ Children = {
+ new Label { Text = "Click a button below to swap the MainPage of the app." },
+ np,
+ mdp,
+ crp,
+ tp,
+ cp
+ }
+ };
+ }
+
+ public static void PushNavigationPage(FlowDirection direction)
+ {
+ ((App)Application.Current).SetMainPage(new FlowDirectionGalleryNP(direction));
+ }
+
+ public static void PushMasterDetailPage(FlowDirection direction)
+ {
+ ((App)Application.Current).SetMainPage(new FlowDirectionGalleryMDP(direction));
+ }
+
+ public static void PushCarouselPage(FlowDirection direction)
+ {
+ ((App)Application.Current).SetMainPage(new FlowDirectionGalleryCarP(direction));
+ }
+
+ public static void PushTabbedPage(FlowDirection direction)
+ {
+ ((App)Application.Current).SetMainPage(new FlowDirectionGalleryTP(direction));
+ }
+
+ public static void PushContentPage(FlowDirection direction)
+ {
+ ((App)Application.Current).SetMainPage(new FlowDirectionGalleryCP(direction)
+ {
+ FlowDirection = direction
+ });
+ }
+ }
+
+ public class FlowDirectionGalleryNP : NavigationPage
+ {
+ public FlowDirectionGalleryNP(FlowDirection direction)
+ {
+ FlowDirection = direction;
+ Navigation.PushAsync(new FlowDirectionGalleryCP(direction));
+ Navigation.PushAsync(new FlowDirectionGalleryCP(direction));
+ }
+ }
+
+ public class FlowDirectionGalleryMDP : MasterDetailPage
+ {
+ public FlowDirectionGalleryMDP(FlowDirection direction)
+ {
+ FlowDirection = direction;
+ Master = new FlowDirectionGalleryCP(direction) { Title = "Master", BackgroundColor = Color.Red };
+ Detail = new FlowDirectionGalleryCP(direction) { Title = "Detail" };
+ IsPresented = true;
+ }
+ }
+
+ public class FlowDirectionGalleryCarP : CarouselPage
+ {
+ public FlowDirectionGalleryCarP(FlowDirection direction)
+ {
+ FlowDirection = direction;
+ Children.Add(new FlowDirectionGalleryCP(direction) { Title = "1" });
+ Children.Add(new FlowDirectionGalleryCP(direction) { Title = "2" });
+ Children.Add(new FlowDirectionGalleryCP(direction) { Title = "3" });
+ }
+ }
+
+ public class FlowDirectionGalleryTP : TabbedPage
+ {
+ public FlowDirectionGalleryTP(FlowDirection direction)
+ {
+ FlowDirection = direction;
+ Children.Add(new FlowDirectionGalleryCP(direction) { Title = "1", BackgroundColor = Color.Red });
+ Children.Add(new FlowDirectionGalleryCP(direction) { Title = "2", BackgroundColor = Color.Orange });
+ Children.Add(new FlowDirectionGalleryCP(direction) { Title = "3", BackgroundColor = Color.Yellow });
+ }
+ }
+
+ public class FlowDirectionGalleryCP : ContentPage
+ {
+ FlowDirection DeviceDirection => Device.FlowDirection;
+
+ Page ParentPage => (Parent as Page) ?? this;
+
+ public FlowDirectionGalleryCP(FlowDirection direction)
+ {
+ var item = new ToolbarItem
+ {
+ Icon = "coffee.png",
+ Text = "Item 1",
+ };
+
+ var item2 = new ToolbarItem
+ {
+ Icon = "bank.png",
+ Text = "Item 2",
+ };
+
+ ToolbarItems.Add(item);
+ ToolbarItems.Add(item2);
+
+ Title = "Flow Direction Gallery";
+ NavigationPage.SetHasBackButton(this, true);
+ NavigationPage.SetBackButtonTitle(this, "Back");
+ SetContent(direction);
+ }
+
+ void SetContent(FlowDirection direction)
+ {
+ var hOptions = LayoutOptions.Start;
+
+ var imageCell = new DataTemplate(typeof(ImageCell));
+ imageCell.SetBinding(ImageCell.ImageSourceProperty, ".");
+ imageCell.SetBinding(ImageCell.TextProperty, ".");
+
+ var textCell = new DataTemplate(typeof(TextCell));
+ textCell.SetBinding(TextCell.DetailProperty, ".");
+
+ var entryCell = new DataTemplate(typeof(EntryCell));
+ entryCell.SetBinding(EntryCell.TextProperty, ".");
+
+ var switchCell = new DataTemplate(typeof(SwitchCell));
+ switchCell.SetBinding(SwitchCell.OnProperty, ".");
+ switchCell.SetValue(SwitchCell.TextProperty, "Switch Cell!");
+
+ var vc = new ViewCell
+ {
+ View = new StackLayout
+ {
+ Children = { new Label { HorizontalOptions = hOptions, Text = "View Cell! I have context actions." } }
+ }
+ };
+
+ var a1 = new MenuItem { Text = "First" };
+ vc.ContextActions.Add(a1);
+ var a2 = new MenuItem { Text = "Second" };
+ vc.ContextActions.Add(a2);
+
+ var viewCell = new DataTemplate(() => vc);
+
+ var relayout = new Switch
+ {
+ IsToggled = true,
+ HorizontalOptions = LayoutOptions.End,
+ VerticalOptions = LayoutOptions.Center
+ };
+
+ var flipButton = new Button
+ {
+ Text = direction == FlowDirection.RightToLeft ? "Switch to Left To Right" : "Switch to Right To Left",
+ HorizontalOptions = LayoutOptions.StartAndExpand,
+ VerticalOptions = LayoutOptions.Center
+ };
+
+ flipButton.Clicked += (s, e) =>
+ {
+ FlowDirection newDirection;
+ if (direction == FlowDirection.LeftToRight || direction == FlowDirection.MatchParent)
+ newDirection = FlowDirection.RightToLeft;
+ else
+ newDirection = FlowDirection.LeftToRight;
+
+ if (relayout.IsToggled)
+ {
+ ParentPage.FlowDirection = newDirection;
+
+ direction = newDirection;
+
+ flipButton.Text = direction == FlowDirection.RightToLeft ? "Switch to Left To Right" : "Switch to Right To Left";
+
+ return;
+ }
+
+ if (ParentPage == this)
+ {
+ FlowDirectionGalleryLandingPage.PushContentPage(newDirection);
+ return;
+ }
+ string parentType = ParentPage.GetType().ToString();
+ switch (parentType)
+ {
+ case "Xamarin.Forms.Controls.FlowDirectionGalleryMDP":
+ FlowDirectionGalleryLandingPage.PushMasterDetailPage(newDirection);
+ break;
+ case "Xamarin.Forms.Controls.FlowDirectionGalleryCarP":
+ FlowDirectionGalleryLandingPage.PushCarouselPage(newDirection);
+ break;
+ case "Xamarin.Forms.Controls.FlowDirectionGalleryNP":
+ FlowDirectionGalleryLandingPage.PushNavigationPage(newDirection);
+ break;
+ case "Xamarin.Forms.Controls.FlowDirectionGalleryTP":
+ FlowDirectionGalleryLandingPage.PushTabbedPage(newDirection);
+ break;
+ }
+ };
+
+ var horStack = new StackLayout
+ {
+ Orientation = StackOrientation.Horizontal,
+ Children = { flipButton, new Label { Text = "Relayout", HorizontalOptions = LayoutOptions.End, VerticalOptions = LayoutOptions.Center }, relayout }
+ };
+
+ var grid = new Grid
+ {
+ ColumnDefinitions = {
+ new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) },
+ new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) },
+ },
+ RowDefinitions = {
+ new RowDefinition { Height = new GridLength(100, GridUnitType.Absolute) },
+ new RowDefinition { Height = new GridLength(100, GridUnitType.Absolute) },
+ new RowDefinition { Height = new GridLength(100, GridUnitType.Absolute) },
+ new RowDefinition { Height = new GridLength(100, GridUnitType.Absolute) },
+ new RowDefinition { Height = new GridLength(100, GridUnitType.Absolute) },
+ new RowDefinition { Height = new GridLength(100, GridUnitType.Absolute) },
+ new RowDefinition { Height = new GridLength(100, GridUnitType.Absolute) },
+ }
+ };
+
+ int col = 0;
+ int row = 0;
+
+ var ai = AddView(grid, ref col, ref row);
+ ai.IsRunning = true;
+
+ var box = AddView(grid, ref col, ref row);
+ box.WidthRequest = box.HeightRequest = 20;
+ box.BackgroundColor = Color.Purple;
+
+ var btn = AddView
-
+
\ No newline at end of file
diff --git a/Xamarin.Forms.Core/BindableObject.cs b/Xamarin.Forms.Core/BindableObject.cs
index 1df88b7d80d..9a774110aca 100644
--- a/Xamarin.Forms.Core/BindableObject.cs
+++ b/Xamarin.Forms.Core/BindableObject.cs
@@ -593,8 +593,7 @@ void SetValueActual(BindableProperty property, BindablePropertyContext context,
OnPropertyChanged(property.PropertyName);
- if (property.PropertyChanged != null)
- property.PropertyChanged(this, original, value);
+ property.PropertyChanged?.Invoke(this, original, value);
}
}
@@ -661,4 +660,4 @@ public enum SetValueFlags
RaiseOnEqual = 1 << 3
}
}
-}
\ No newline at end of file
+}
diff --git a/Xamarin.Forms.Core/Cells/Cell.cs b/Xamarin.Forms.Core/Cells/Cell.cs
index 6e088219d50..59d7e157846 100644
--- a/Xamarin.Forms.Core/Cells/Cell.cs
+++ b/Xamarin.Forms.Core/Cells/Cell.cs
@@ -4,10 +4,11 @@
using System.Collections.Specialized;
using System.ComponentModel;
using System.Threading.Tasks;
+using Xamarin.Forms.Internals;
namespace Xamarin.Forms
{
- public abstract class Cell : Element, ICellController
+ public abstract class Cell : Element, ICellController, IFlowDirectionController
{
public const int DefaultCellHeight = 40;
public static readonly BindableProperty IsEnabledProperty = BindableProperty.Create("IsEnabled", typeof(bool), typeof(Cell), true, propertyChanged: OnIsEnabledPropertyChanged);
@@ -18,6 +19,25 @@ public abstract class Cell : Element, ICellController
bool _nextCallToForceUpdateSizeQueued;
+ EffectiveFlowDirection _effectiveFlowDirection = default(EffectiveFlowDirection);
+ EffectiveFlowDirection IFlowDirectionController.EffectiveFlowDirection
+ {
+ get { return _effectiveFlowDirection; }
+ set
+ {
+ if (value == _effectiveFlowDirection)
+ return;
+
+ _effectiveFlowDirection = value;
+
+ var ve = (Parent as VisualElement);
+ ve?.InvalidateMeasureInternal(InvalidationTrigger.Undefined);
+ OnPropertyChanged(VisualElement.FlowDirectionProperty.PropertyName);
+ }
+ }
+
+ IFlowDirectionController FlowController => this;
+
public IList