Add options for specifying layout of button text/image content
authorE.Z. Hart <hartez@gmail.com>
Tue, 22 Mar 2016 23:16:53 +0000 (17:16 -0600)
committerE.Z. Hart <hartez@gmail.com>
Wed, 30 Mar 2016 22:22:35 +0000 (16:22 -0600)
Also make the layout and layout defaults consistent across platforms

24 files changed:
Xamarin.Forms.ControlGallery.WP8/Xamarin.Forms.ControlGallery.WP8.csproj
Xamarin.Forms.ControlGallery.WP8/coffee.png [new file with mode: 0644]
Xamarin.Forms.ControlGallery.Windows/Xamarin.Forms.ControlGallery.Windows.csproj
Xamarin.Forms.ControlGallery.Windows/coffee.png [new file with mode: 0644]
Xamarin.Forms.ControlGallery.WindowsPhone/Xamarin.Forms.ControlGallery.WindowsPhone.csproj
Xamarin.Forms.ControlGallery.WindowsPhone/coffee.png [new file with mode: 0644]
Xamarin.Forms.ControlGallery.WindowsUniversal/Xamarin.Forms.ControlGallery.WindowsUniversal.csproj
Xamarin.Forms.ControlGallery.WindowsUniversal/coffee.png [new file with mode: 0644]
Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Bugzilla27417.cs [new file with mode: 0644]
Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Bugzilla27417Xaml.xaml [new file with mode: 0644]
Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Bugzilla27417Xaml.xaml.cs [new file with mode: 0644]
Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Xamarin.Forms.Controls.Issues.Shared.projitems
Xamarin.Forms.Controls/App.cs
Xamarin.Forms.Core.UnitTests/ButtonUnitTest.cs
Xamarin.Forms.Core/Button.cs
Xamarin.Forms.Platform.Android/AppCompat/ButtonRenderer.cs
Xamarin.Forms.Platform.Android/Renderers/ButtonRenderer.cs
Xamarin.Forms.Platform.WP8/ButtonRenderer.cs
Xamarin.Forms.Platform.WinRT/ButtonRenderer.cs
Xamarin.Forms.Platform.iOS/Renderers/ButtonRenderer.cs
docs/Xamarin.Forms.Core/Xamarin.Forms/Button+ButtonContentLayout+ImagePosition.xml [new file with mode: 0644]
docs/Xamarin.Forms.Core/Xamarin.Forms/Button+ButtonContentLayout.xml [new file with mode: 0644]
docs/Xamarin.Forms.Core/Xamarin.Forms/Button+ButtonContentTypeConverter.xml [new file with mode: 0644]
docs/Xamarin.Forms.Core/Xamarin.Forms/Button.xml

index f6728fa..99ca9e5 100644 (file)
     <Content Include="bank.png">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
+    <Content Include="coffee.png" />
     <Content Include="cover1.jpg">
       <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
     </Content>
diff --git a/Xamarin.Forms.ControlGallery.WP8/coffee.png b/Xamarin.Forms.ControlGallery.WP8/coffee.png
new file mode 100644 (file)
index 0000000..350257c
Binary files /dev/null and b/Xamarin.Forms.ControlGallery.WP8/coffee.png differ
index c5f558b..c977cec 100644 (file)
     <Content Include="Assets\SmallLogo.scale-100.png" />
     <Content Include="Assets\SplashScreen.scale-100.png" />
     <Content Include="Assets\StoreLogo.scale-100.png" />
+    <Content Include="coffee.png" />
     <Content Include="toolbar_close.png" />
   </ItemGroup>
   <ItemGroup>
diff --git a/Xamarin.Forms.ControlGallery.Windows/coffee.png b/Xamarin.Forms.ControlGallery.Windows/coffee.png
new file mode 100644 (file)
index 0000000..350257c
Binary files /dev/null and b/Xamarin.Forms.ControlGallery.Windows/coffee.png differ
index 50c990c..d97a36d 100644 (file)
     <Content Include="Assets\Square71x71Logo.scale-240.png" />
     <Content Include="Assets\StoreLogo.scale-240.png" />
     <Content Include="Assets\WideLogo.scale-240.png" />
+    <Content Include="coffee.png" />
     <Content Include="toolbar_close.png" />
   </ItemGroup>
   <ItemGroup>
diff --git a/Xamarin.Forms.ControlGallery.WindowsPhone/coffee.png b/Xamarin.Forms.ControlGallery.WindowsPhone/coffee.png
new file mode 100644 (file)
index 0000000..350257c
Binary files /dev/null and b/Xamarin.Forms.ControlGallery.WindowsPhone/coffee.png differ
index 0061689..d0c196e 100644 (file)
     </ProjectReference>
   </ItemGroup>
   <ItemGroup>
+    <Content Include="coffee.png" />
     <Content Include="toolbar_close.png" />
     <None Include="project.json" />
     <Content Include="..\Xamarin.Forms.ControlGallery.WP8\bank.png">
diff --git a/Xamarin.Forms.ControlGallery.WindowsUniversal/coffee.png b/Xamarin.Forms.ControlGallery.WindowsUniversal/coffee.png
new file mode 100644 (file)
index 0000000..350257c
Binary files /dev/null and b/Xamarin.Forms.ControlGallery.WindowsUniversal/coffee.png differ
diff --git a/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Bugzilla27417.cs b/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Bugzilla27417.cs
new file mode 100644 (file)
index 0000000..4f01a63
--- /dev/null
@@ -0,0 +1,59 @@
+using Xamarin.Forms.CustomAttributes;
+
+namespace Xamarin.Forms.Controls.Issues
+{
+       [Preserve(AllMembers = true)]
+       [Issue(IssueTracker.Bugzilla, 27417,
+               "Button.Image behaviors differently on each platform and has extra padding even with no Text", PlatformAffected.All)]
+       public class Bugzilla27417 : TestContentPage
+       {
+               protected override void Init()
+               {
+                       var instructions = new Label { Text = @"There should be 6 buttons below. 
+The first button should have the text 'Click Me' in the center.
+The second button should have an image in the center and no text.
+The third button should have the image on the left and the text on the right.
+The fourth button should have the image on the top and the text on the bottom.
+The fifth button should have the image on the right and the text on the left.
+The sixth button should have the image on the bottom and the text on the top." };
+
+                       Content = new StackLayout
+                       {
+                               Spacing = 10,
+                               Children =
+                               {
+                                       instructions,
+                                       new ScrollView
+                                       {
+                                               Content = new StackLayout
+                                               {
+                                                       Spacing = 10,
+                                                       VerticalOptions = LayoutOptions.Center,
+                                                       HorizontalOptions = LayoutOptions.Center,
+                                                       Children =
+                                                       {
+                                                               new Button { Text = "Click Me", BackgroundColor = Color.Gray },
+                                                               new Button { Image = "coffee.png", BackgroundColor = Color.Gray },
+                                                               CreateButton(new Button.ButtonContentLayout(Button.ButtonContentLayout.ImagePosition.Left, 10)),
+                                                               CreateButton(new Button.ButtonContentLayout(Button.ButtonContentLayout.ImagePosition.Top, 10)),
+                                                               CreateButton(new Button.ButtonContentLayout(Button.ButtonContentLayout.ImagePosition.Bottom, 10)),
+                                                               CreateButton(new Button.ButtonContentLayout(Button.ButtonContentLayout.ImagePosition.Right, 10))
+                                                       }
+                                               }
+                                       }
+                               }
+                       };
+               }
+
+               static Button CreateButton(Button.ButtonContentLayout layout)
+               {
+                       return new Button
+                       {
+                               Text = "Click Me",
+                               Image = "coffee.png",
+                               ContentLayout = layout,
+                               BackgroundColor = Color.Gray
+                       };
+               }
+       }
+}
\ No newline at end of file
diff --git a/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Bugzilla27417Xaml.xaml b/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Bugzilla27417Xaml.xaml
new file mode 100644 (file)
index 0000000..ab652b3
--- /dev/null
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
+             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
+             x:Class="Xamarin.Forms.Controls.Issues.Bugzilla27417Xaml">
+  <StackLayout Spacing="10">
+
+    <Button BackgroundColor="Color.Gray" Text="Click Me"></Button>
+    <Button BackgroundColor="Color.Gray" Image="coffee.png"></Button>
+    <Button BackgroundColor="Color.Gray" Image="coffee.png" Text="Click Me"></Button>
+    <Button BackgroundColor="Color.Gray" Image="coffee.png" Text="Click Me" ContentLayout="Top,10"></Button>
+    <Button BackgroundColor="Color.Gray" Image="coffee.png" Text="Click Me" ContentLayout="Bottom,10"></Button>
+    <Button BackgroundColor="Color.Gray" Image="coffee.png" Text="Click Me" ContentLayout="Right"></Button>
+    
+  </StackLayout>
+</ContentPage>
\ No newline at end of file
diff --git a/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Bugzilla27417Xaml.xaml.cs b/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Bugzilla27417Xaml.xaml.cs
new file mode 100644 (file)
index 0000000..96d2ac4
--- /dev/null
@@ -0,0 +1,20 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+using Xamarin.Forms;
+
+namespace Xamarin.Forms.Controls.Issues
+{
+       public partial class Bugzilla27417Xaml : ContentPage
+       {
+               public Bugzilla27417Xaml ()
+               {
+#if APP
+                       InitializeComponent ();
+#endif
+               }
+       }
+}
index 0a2d251..6ae60c7 100644 (file)
     <Compile Include="$(MSBuildThisFileDirectory)Bugzilla26501.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)Bugzilla26868.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)Bugzilla27378.cs" />
+    <Compile Include="$(MSBuildThisFileDirectory)Bugzilla27417.cs" />
+    <Compile Include="$(MSBuildThisFileDirectory)Bugzilla27417Xaml.xaml.cs">
+      <DependentUpon>Bugzilla27417Xaml.xaml</DependentUpon>
+      <SubType>Code</SubType>
+    </Compile>
     <Compile Include="$(MSBuildThisFileDirectory)Bugzilla27581.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)Bugzilla28570.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)Bugzilla28796.cs" />
       <Generator>MSBuild:UpdateDesignTimeXaml</Generator>
     </EmbeddedResource>
   </ItemGroup>
+  <ItemGroup>
+    <EmbeddedResource Include="$(MSBuildThisFileDirectory)Bugzilla27417Xaml.xaml">
+      <SubType>Designer</SubType>
+      <Generator>MSBuild:UpdateDesignTimeXaml</Generator>
+    </EmbeddedResource>
+  </ItemGroup>
 </Project>
\ No newline at end of file
index 2556bc8..d75b35a 100644 (file)
@@ -10,7 +10,7 @@ namespace Xamarin.Forms.Controls
        {
                public const string AppName = "XamarinFormsControls";
                static string s_insightsKey;
-               
+
                // ReSharper disable once InconsistentNaming
                public static int IOSVersion = -1;
 
@@ -24,8 +24,7 @@ namespace Xamarin.Forms.Controls
                        _testCloudService = DependencyService.Get<ITestCloudService>();
                        InitInsights();
                        // MainPage = new MainPageLifeCycleTests ();
-                       MainPage = new MasterDetailPage
-                       {
+                       MainPage = new MasterDetailPage {
                                Master = new ContentPage { Title = "Master", BackgroundColor = Color.Red },
                                Detail = CoreGallery.GetMainPage()
                        };
@@ -65,7 +64,7 @@ namespace Xamarin.Forms.Controls
 
                static Assembly GetAssembly(out string assemblystring)
                {
-                       assemblystring = typeof (App).AssemblyQualifiedName.Split(',')[1].Trim();
+                       assemblystring = typeof(App).AssemblyQualifiedName.Split(',')[1].Trim();
                        var assemblyname = new AssemblyName(assemblystring);
                        return Assembly.Load(assemblyname);
                }
index 29ad2d0..78d97a8 100644 (file)
@@ -1,4 +1,5 @@
 using System;
+using System.Diagnostics;
 using NUnit.Framework;
 
 namespace Xamarin.Forms.Core.UnitTests
@@ -177,5 +178,28 @@ namespace Xamarin.Forms.Core.UnitTests
 
                        Assert.True (button.IsEnabled);
                }
+
+               [Test]
+               public void ButtonContentLayoutTypeConverterTest()
+               {
+                       var converter = new Button.ButtonContentTypeConverter();
+                       Assert.True(converter.CanConvertFrom(typeof(string)));
+
+                       AssertButtonContentLayoutsEqual(new Button.ButtonContentLayout(Button.ButtonContentLayout.ImagePosition.Left, 10), converter.ConvertFromInvariantString("left,10"));
+                       AssertButtonContentLayoutsEqual(new Button.ButtonContentLayout(Button.ButtonContentLayout.ImagePosition.Right, 10), converter.ConvertFromInvariantString("right"));
+                       AssertButtonContentLayoutsEqual(new Button.ButtonContentLayout(Button.ButtonContentLayout.ImagePosition.Top, 20), converter.ConvertFromInvariantString("top,20"));
+                       AssertButtonContentLayoutsEqual(new Button.ButtonContentLayout(Button.ButtonContentLayout.ImagePosition.Left, 15), converter.ConvertFromInvariantString("15"));
+                       AssertButtonContentLayoutsEqual(new Button.ButtonContentLayout(Button.ButtonContentLayout.ImagePosition.Bottom, 0), converter.ConvertFromInvariantString("Bottom, 0"));
+
+                       Assert.Throws<InvalidOperationException>(() => converter.ConvertFromInvariantString(""));
+               }
+
+               private void AssertButtonContentLayoutsEqual(Button.ButtonContentLayout layout1, object layout2)
+               {
+                       var bcl = (Button.ButtonContentLayout)layout2;
+
+                       Assert.AreEqual(layout1.Position, bcl.Position);
+                       Assert.AreEqual(layout1.Spacing, bcl.Spacing);
+               }
        }       
 }
index 4662105..9c746c9 100644 (file)
@@ -1,4 +1,6 @@
 using System;
+using System.Diagnostics;
+using System.Globalization;
 using System.Windows.Input;
 using Xamarin.Forms.Platform;
 
@@ -12,6 +14,9 @@ namespace Xamarin.Forms
                public static readonly BindableProperty CommandParameterProperty = BindableProperty.Create("CommandParameter", typeof(object), typeof(Button), null,
                        propertyChanged: (bindable, oldvalue, newvalue) => ((Button)bindable).CommandCanExecuteChanged(bindable, EventArgs.Empty));
 
+               public static readonly BindableProperty ContentLayoutProperty =
+                       BindableProperty.Create("ContentLayout", typeof(ButtonContentLayout), typeof(Button), new ButtonContentLayout(ButtonContentLayout.ImagePosition.Left, DefaultSpacing));
+
                public static readonly BindableProperty TextProperty = BindableProperty.Create("Text", typeof(string), typeof(Button), null,
                        propertyChanged: (bindable, oldVal, newVal) => ((Button)bindable).InvalidateMeasure(InvalidationTrigger.MeasureChanged));
 
@@ -39,6 +44,8 @@ namespace Xamarin.Forms
 
                bool _cancelEvents;
 
+               const double DefaultSpacing = 10;
+
                public Color BorderColor
                {
                        get { return (Color)GetValue(BorderColorProperty); }
@@ -57,6 +64,12 @@ namespace Xamarin.Forms
                        set { SetValue(BorderWidthProperty, value); }
                }
 
+               public ButtonContentLayout ContentLayout
+               {
+                       get { return (ButtonContentLayout)GetValue(ContentLayoutProperty); }
+                       set { SetValue(ContentLayoutProperty, value); }
+               }
+
                public ICommand Command
                {
                        get { return (ICommand)GetValue(CommandProperty); }
@@ -247,5 +260,72 @@ namespace Xamarin.Forms
 
                        button._cancelEvents = false;
                }
+
+               [DebuggerDisplay("Image Position = {Position}, Spacing = {Spacing}")]
+               [TypeConverter(typeof(ButtonContentTypeConverter))]
+               public sealed class ButtonContentLayout
+               {
+                       public enum ImagePosition
+                       {
+                               Left,
+                               Top,
+                               Right,
+                               Bottom
+                       }
+
+                       public ButtonContentLayout(ImagePosition position, double spacing)
+                       {
+                               Position = position;
+                               Spacing = spacing;
+                       }
+
+                       public ImagePosition Position { get; }
+
+                       public double Spacing { get; }
+
+                       public override string ToString()
+                       {
+                               return $"Image Position = {Position}, Spacing = {Spacing}";
+                       }
+               }
+
+               public sealed class ButtonContentTypeConverter : TypeConverter
+               {
+                       public override object ConvertFromInvariantString(string value)
+                       {
+                               if (value == null)
+                               {
+                                       throw new InvalidOperationException($"Cannot convert null into {typeof(ButtonContentLayout)}");
+                               }
+
+                               string[] parts = value.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
+
+                               if (parts.Length != 1 && parts.Length != 2)
+                               {
+                                       throw new InvalidOperationException($"Cannot convert \"{value}\" into {typeof(ButtonContentLayout)}");
+                               }
+
+                               double spacing = DefaultSpacing;
+                               var position = ButtonContentLayout.ImagePosition.Left;
+
+                               var spacingFirst = char.IsDigit(parts[0][0]);
+
+                               int positionIndex = spacingFirst ? (parts.Length == 2 ? 1 : -1) : 0;
+                               int spacingIndex = spacingFirst ? 0 : (parts.Length == 2 ? 1 : -1);
+
+                               if (spacingIndex > -1)
+                               {
+                                       spacing = double.Parse(parts[spacingIndex]);
+                               }
+
+                               if (positionIndex > -1)
+                               {
+                                       position =
+                                               (ButtonContentLayout.ImagePosition)Enum.Parse(typeof(ButtonContentLayout.ImagePosition), parts[positionIndex], true);
+                               }
+
+                               return new ButtonContentLayout(position, spacing);
+                       }
+               }
        }
 }
\ No newline at end of file
index c7df08e..7b7503e 100644 (file)
@@ -158,16 +158,51 @@ namespace Xamarin.Forms.Platform.Android.AppCompat
 
                void UpdateBitmap()
                {
-                       FileImageSource elementImage = Element.Image;
-                       string imageFile = elementImage?.File;
-                       if (elementImage != null && !string.IsNullOrEmpty(imageFile))
+                       var elementImage = Element.Image;
+                       var imageFile = elementImage?.File;
+
+                       if (elementImage == null || string.IsNullOrEmpty(imageFile))
+                       {
+                               Control.SetCompoundDrawablesWithIntrinsicBounds(null, null, null, null);
+                               return;
+                       }
+
+                       var image = Context.Resources.GetDrawable(imageFile);
+
+                       if (string.IsNullOrEmpty(Element.Text))
                        {
-                               Drawable image = Context.Resources.GetDrawable(imageFile);
-                               Control.SetCompoundDrawablesWithIntrinsicBounds(image, null, null, null);
+                               // No text, so no need for relative position; just center the image
+                               // There's no option for just plain-old centering, so we'll use Top 
+                               // (which handles the horizontal centering) and some tricksy padding 
+                               // to handle the vertical centering
+                               Control.SetCompoundDrawablesWithIntrinsicBounds(null, image, null, null);
+                               Control.SetPadding(0, Control.PaddingTop, 0, -Control.PaddingTop);
                                image?.Dispose();
+                               return;
                        }
-                       else
-                               Control.SetCompoundDrawablesWithIntrinsicBounds(null, null, null, null);
+
+                       var layout = Element.ContentLayout;
+
+                       Control.CompoundDrawablePadding = (int)layout.Spacing;
+
+                       switch (layout.Position)
+                       {
+                               case Button.ButtonContentLayout.ImagePosition.Top:
+                                       Control.SetCompoundDrawablesWithIntrinsicBounds(null, image, null, null);
+                                       break;
+                               case Button.ButtonContentLayout.ImagePosition.Bottom:
+                                       Control.SetCompoundDrawablesWithIntrinsicBounds(null, null, null, image);
+                                       break;
+                               case Button.ButtonContentLayout.ImagePosition.Right:
+                                       Control.SetCompoundDrawablesWithIntrinsicBounds(null, null, image, null);
+                                       break;
+                               default:
+                                       // Defaults to image on the left
+                                       Control.SetCompoundDrawablesWithIntrinsicBounds(image, null, null, null);
+                                       break;
+                       }
+
+                       image?.Dispose();
                }
 
                void UpdateEnabled()
index eb9b884..0d93207 100644 (file)
@@ -138,17 +138,53 @@ namespace Xamarin.Forms.Platform.Android
                        UpdateDrawable();
                }
 
-               async void UpdateBitmap()
+               void UpdateBitmap()
                {
-                       if (Element.Image != null && !string.IsNullOrEmpty(Element.Image.File))
+                       var elementImage = Element.Image;
+                       var imageFile = elementImage?.File;
+
+                       if (elementImage == null || string.IsNullOrEmpty(imageFile))
                        {
-                               Drawable image = Context.Resources.GetDrawable(Element.Image.File);
-                               Control.SetCompoundDrawablesWithIntrinsicBounds(image, null, null, null);
-                               if (image != null)
-                                       image.Dispose();
-                       }
-                       else
                                Control.SetCompoundDrawablesWithIntrinsicBounds(null, null, null, null);
+                               return;
+                       }
+
+                       var image = Context.Resources.GetDrawable(imageFile);
+
+                       if (string.IsNullOrEmpty(Element.Text))
+                       {
+                               // No text, so no need for relative position; just center the image
+                               // There's no option for just plain-old centering, so we'll use Top 
+                               // (which handles the horizontal centering) and some tricksy padding 
+                               // to handle the vertical centering
+                               Control.SetCompoundDrawablesWithIntrinsicBounds(null, image, null, null);
+                               Control.SetPadding(0, Control.PaddingTop, 0, -Control.PaddingTop);
+                               image?.Dispose();
+                               return;
+                       }
+
+                       var layout = Element.ContentLayout;
+
+                       Control.CompoundDrawablePadding = (int)layout.Spacing;
+
+                       switch (layout.Position)
+                       {
+                               case Button.ButtonContentLayout.ImagePosition.Top:
+                                       Control.SetCompoundDrawablesWithIntrinsicBounds(null, image, null, null);
+                                       break;
+                               case Button.ButtonContentLayout.ImagePosition.Bottom:
+                                       Control.SetCompoundDrawablesWithIntrinsicBounds(null, null, null, image);
+                                       break;
+                               case Button.ButtonContentLayout.ImagePosition.Right:
+                                       Control.SetCompoundDrawablesWithIntrinsicBounds(null, null, image, null);
+                                       break;
+                               default:
+                                       // Defaults to image on the left
+                                       Control.SetCompoundDrawablesWithIntrinsicBounds(image, null, null, null);
+                                       break;
+                       }
+
+                       image?.Dispose();
                }
 
                void UpdateDrawable()
index 886a776..a75173b 100644 (file)
@@ -81,20 +81,72 @@ namespace Xamarin.Forms.Platform.WinPhone
 
                void UpdateContent()
                {
-                       if (Element.Image != null)
+                       var text = Element.Text;
+                       var elementImage = Element.Image;
+
+                       // No image, just the text
+                       if (elementImage == null)
+                       {
+                               Control.Content = text;
+                               return;
+                       }
+
+                       var image = new WImage
+                       {
+                               Source = new BitmapImage(new Uri("/" + elementImage.File, UriKind.Relative)),
+                               Width = 30,
+                               Height = 30,
+                               VerticalAlignment = VerticalAlignment.Center,
+                               HorizontalAlignment = HorizontalAlignment.Center
+                       };
+
+                       // No text, just the image
+                       if (string.IsNullOrEmpty(text))
+                       {
+                               Control.Content = image;
+                               return;
+                       }
+
+                       // Both image and text, so we need to build a container for them
+                       var layout = Element.ContentLayout;
+                       var container = new StackPanel();
+                       var textBlock = new TextBlock
+                       {
+                               Text = text,
+                               VerticalAlignment = VerticalAlignment.Center,
+                               HorizontalAlignment = HorizontalAlignment.Center
+                       };
+
+                       var spacing = layout.Spacing;
+
+                       container.HorizontalAlignment = HorizontalAlignment.Center;
+                       container.VerticalAlignment = VerticalAlignment.Center;
+
+                       switch (layout.Position)
                        {
-                               Control.Content = new StackPanel
-                               {
-                                       Orientation = Orientation.Horizontal,
-                                       Children =
-                                       {
-                                               new WImage { Source = new BitmapImage(new Uri("/" + Element.Image.File, UriKind.Relative)), Width = 30, Height = 30, Margin = new WThickness(0, 0, 20, 0) },
-                                               new TextBlock { Text = Element.Text }
-                                       }
-                               };
+                               case Button.ButtonContentLayout.ImagePosition.Top:
+                                       container.Orientation = Orientation.Vertical;
+                                       image.Margin = new WThickness(0, 0, 0, spacing);
+                                       break;
+                               case Button.ButtonContentLayout.ImagePosition.Bottom:
+                                       container.Orientation = Orientation.Vertical;
+                                       image.Margin = new WThickness(0, spacing, 0, 0);
+                                       break;
+                               case Button.ButtonContentLayout.ImagePosition.Right:
+                                       container.Orientation = Orientation.Horizontal;
+                                       image.Margin = new WThickness(spacing, 0, 0, 0);
+                                       break;
+                               default:
+                                       // Defaults to image on the left
+                                       container.Orientation = Orientation.Horizontal;
+                                       image.Margin = new WThickness(0, 0, spacing, 0);
+                                       break;
                        }
-                       else
-                               Control.Content = Element.Text;
+
+                       container.Children.Add(image);
+                       container.Children.Add(textBlock);
+
+                       Control.Content = container;
                }
 
                void UpdateFont()
index 60ee641..bcba31c 100644 (file)
@@ -117,25 +117,78 @@ namespace Xamarin.Forms.Platform.WinRT
 
                void UpdateContent()
                {
-                       if (Element.Image != null)
+                       var text = Element.Text;
+                       var elementImage = Element.Image;
+
+                       // No image, just the text
+                       if (elementImage == null)
                        {
-                               var panel = new StackPanel { Orientation = Orientation.Horizontal };
+                               Control.Content = text;
+                               return;
+                       }
 
-                               var image = new WImage { Source = new BitmapImage(new Uri("ms-appx:///" + Element.Image.File)), Width = 30, Height = 30, Margin = new WThickness(0, 0, 20, 0) };
-                               panel.Children.Add(image);
-                               image.ImageOpened += (sender, args) => { ((IButtonController)Element).NativeSizeChanged(); };
+                       var image = new WImage
+                       {
+                               Source = new BitmapImage(new Uri("ms-appx:///" + elementImage.File)),
+                               Width = 30,
+                               Height = 30,
+                               VerticalAlignment = VerticalAlignment.Center,
+                               HorizontalAlignment = HorizontalAlignment.Center
+                       };
+
+                       // No text, just the image
+                       if (string.IsNullOrEmpty(text))
+                       {
+                               Control.Content = image;
+                               return;
+                       }
 
-                               if (Element.Text != null)
-                               {
-                                       panel.Children.Add(new TextBlock { Text = Element.Text });
-                               }
+                       // Both image and text, so we need to build a container for them
+                       var layout = Element.ContentLayout;
+                       var container = new StackPanel();
+                       var textBlock = new TextBlock
+                       {
+                               Text = text,
+                               VerticalAlignment = VerticalAlignment.Center,
+                               HorizontalAlignment = HorizontalAlignment.Center
+                       };
 
-                               Control.Content = panel;
-                       }
-                       else
+                       var spacing = layout.Spacing;
+
+                       container.HorizontalAlignment = HorizontalAlignment.Center;
+                       container.VerticalAlignment = VerticalAlignment.Center;
+
+                       switch (layout.Position)
                        {
-                               Control.Content = Element.Text;
+                               case Button.ButtonContentLayout.ImagePosition.Top:
+                                       container.Orientation = Orientation.Vertical;
+                                       image.Margin = new WThickness(0, 0, 0, spacing);
+                                       container.Children.Add(image);
+                                       container.Children.Add(textBlock);
+                                       break;
+                               case Button.ButtonContentLayout.ImagePosition.Bottom:
+                                       container.Orientation = Orientation.Vertical;
+                                       image.Margin = new WThickness(0, spacing, 0, 0);
+                                       container.Children.Add(textBlock);
+                                       container.Children.Add(image);
+                                       break;
+                               case Button.ButtonContentLayout.ImagePosition.Right:
+                                       container.Orientation = Orientation.Horizontal;
+                                       image.Margin = new WThickness(spacing, 0, 0, 0);
+                                       container.Children.Add(textBlock);
+                                       container.Children.Add(image);
+                                       break;
+                               default:
+                                       // Defaults to image on the left
+                                       container.Orientation = Orientation.Horizontal;
+                                       image.Margin = new WThickness(0, 0, spacing, 0);
+                                       container.Children.Add(image);
+                                       container.Children.Add(textBlock);
+                                       break;
                        }
+
+                       Control.Content = container;
+
                }
 
                void UpdateFont()
index 3fa84d1..34609b4 100644 (file)
@@ -1,20 +1,18 @@
 using System;
-using System.Drawing;
 using System.Linq;
 using System.ComponentModel;
+using System.Diagnostics;
+
 #if __UNIFIED__
+using Foundation;
 using UIKit;
-using CoreGraphics;
-#else
-using MonoTouch.UIKit;
-using MonoTouch.CoreGraphics;
-#endif
-#if __UNIFIED__
 using RectangleF = CoreGraphics.CGRect;
 using SizeF = CoreGraphics.CGSize;
 using PointF = CoreGraphics.CGPoint;
-
 #else
+using System.Drawing;
+using MonoTouch.UIKit;
+using MonoTouch.Foundation;
 using nfloat=System.Single;
 using nint=System.Int32;
 using nuint=System.UInt32;
@@ -27,14 +25,25 @@ namespace Xamarin.Forms.Platform.iOS
                UIColor _buttonTextColorDefaultDisabled;
                UIColor _buttonTextColorDefaultHighlighted;
                UIColor _buttonTextColorDefaultNormal;
+               bool _titleChanged;
+               SizeF _titleSize;
+
+               // This looks like it should be a const under iOS Classic,
+               // but that doesn't work under iOS 
+               // ReSharper disable once BuiltInTypeReferenceStyle
+               // Under iOS Classic Resharper wants to suggest this use the built-in type ref
+               // but under iOS that suggestion won't work
+               readonly nfloat _minimumButtonHeight = 44; // Apple docs
 
                public override SizeF SizeThatFits(SizeF size)
                {
                        var result = base.SizeThatFits(size);
-                       result.Height = 44; // Apple docs
-                       //Compensate for the insets
-                       if (!Control.ImageView.Hidden)
-                               result.Width += 10;
+
+                       if (result.Height < _minimumButtonHeight)
+                       {
+                               result.Height = _minimumButtonHeight; 
+                       }
+
                        return result;
                }
 
@@ -56,6 +65,8 @@ namespace Xamarin.Forms.Platform.iOS
                                {
                                        SetNativeControl(new UIButton(UIButtonType.RoundedRect));
 
+                                       Debug.Assert(Control != null, "Control != null");
+
                                        _buttonTextColorDefaultNormal = Control.TitleColor(UIControlState.Normal);
                                        _buttonTextColorDefaultHighlighted = Control.TitleColor(UIControlState.Highlighted);
                                        _buttonTextColorDefaultDisabled = Control.TitleColor(UIControlState.Disabled);
@@ -91,8 +102,7 @@ namespace Xamarin.Forms.Platform.iOS
 
                void OnButtonTouchUpInside(object sender, EventArgs eventArgs)
                {
-                       if (Element != null)
-                               ((IButtonController)Element).SendClicked();
+                       ((IButtonController)Element)?.SendClicked();
                }
 
                void UpdateBackgroundVisibility()
@@ -129,7 +139,7 @@ namespace Xamarin.Forms.Platform.iOS
                async void UpdateImage()
                {
                        IImageSourceHandler handler;
-                       var source = Element.Image;
+                       FileImageSource source = Element.Image;
                        if (source != null && (handler = Registrar.Registered.GetHandler<IImageSourceHandler>(source.GetType())) != null)
                        {
                                UIImage uiimage;
@@ -141,31 +151,36 @@ namespace Xamarin.Forms.Platform.iOS
                                {
                                        uiimage = null;
                                }
-                               var button = Control;
+                               UIButton button = Control;
                                if (button != null && uiimage != null)
                                {
                                        if (Forms.IsiOS7OrNewer)
                                                button.SetImage(uiimage.ImageWithRenderingMode(UIImageRenderingMode.AlwaysOriginal), UIControlState.Normal);
                                        else
                                                button.SetImage(uiimage, UIControlState.Normal);
+
                                        button.ImageView.ContentMode = UIViewContentMode.ScaleAspectFit;
 
-                                       Control.ImageEdgeInsets = new UIEdgeInsets(0, 0, 0, 10);
-                                       Control.TitleEdgeInsets = new UIEdgeInsets(0, 10, 0, 0);
+                                       ComputeEdgeInsets(Control, Element.ContentLayout);
                                }
                        }
                        else
                        {
                                Control.SetImage(null, UIControlState.Normal);
-                               Control.ImageEdgeInsets = new UIEdgeInsets(0, 0, 0, 0);
-                               Control.TitleEdgeInsets = new UIEdgeInsets(0, 0, 0, 0);
+                               ClearEdgeInsets(Control);
                        }
                        ((IVisualElementController)Element).NativeSizeChanged();
                }
 
                void UpdateText()
                {
-                       Control.SetTitle(Element.Text, UIControlState.Normal);
+                       var newText = Element.Text;
+
+                       if (Control.Title(UIControlState.Normal) != newText)
+                       {
+                               Control.SetTitle(Element.Text, UIControlState.Normal);
+                               _titleChanged = true;
+                       }
                }
 
                void UpdateTextColor()
@@ -186,5 +201,74 @@ namespace Xamarin.Forms.Platform.iOS
                                        Control.TintColor = Element.TextColor.ToUIColor();
                        }
                }
+
+               void ClearEdgeInsets(UIButton button)
+               {
+                       if (button == null)
+                       {
+                               return;
+                       }
+
+                       Control.ImageEdgeInsets = new UIEdgeInsets(0, 0, 0, 0);
+                       Control.TitleEdgeInsets = new UIEdgeInsets(0, 0, 0, 0);
+                       Control.ContentEdgeInsets = new UIEdgeInsets(0, 0, 0, 0);
+               }
+
+               void ComputeEdgeInsets(UIButton button, Button.ButtonContentLayout layout)
+               {
+                       if (button?.ImageView?.Image == null || string.IsNullOrEmpty(button.TitleLabel?.Text))
+                       {
+                               return;
+                       }
+
+                       var position = layout.Position;
+                       var spacing = (nfloat)(layout.Spacing / 2);
+
+                       if (position == Button.ButtonContentLayout.ImagePosition.Left)
+                       {
+                               button.ImageEdgeInsets = new UIEdgeInsets(0, -spacing, 0, spacing);
+                               button.TitleEdgeInsets = new UIEdgeInsets(0, spacing, 0, -spacing);
+                               button.ContentEdgeInsets = new UIEdgeInsets(0, 2 * spacing, 0, 2 * spacing);
+                               return;
+                       }
+
+                       if (_titleChanged)
+                       {
+                               var stringToMeasure = new NSString(button.TitleLabel.Text);
+                               UIStringAttributes attribs = new UIStringAttributes { Font = button.TitleLabel.Font };
+                               _titleSize = stringToMeasure.GetSizeUsingAttributes(attribs);
+                               _titleChanged = false;
+                       }
+
+                       var labelWidth = _titleSize.Width;
+                       var imageWidth = button.ImageView.Image.Size.Width;
+
+                       if (position == Button.ButtonContentLayout.ImagePosition.Right)
+                       {
+                               button.ImageEdgeInsets = new UIEdgeInsets(0, labelWidth + spacing, 0, -labelWidth - spacing);
+                               button.TitleEdgeInsets = new UIEdgeInsets(0, -imageWidth - spacing, 0, imageWidth + spacing);
+                               button.ContentEdgeInsets = new UIEdgeInsets(0, 2 * spacing, 0, 2 * spacing);
+                               return;
+                       }
+
+                       var imageVertOffset = (_titleSize.Height / 2);
+                       var titleVertOffset = (button.ImageView.Image.Size.Height / 2);
+
+                       var edgeOffset = (float)Math.Min(imageVertOffset, titleVertOffset);
+
+                       button.ContentEdgeInsets = new UIEdgeInsets(edgeOffset, 0, edgeOffset, 0);
+
+                       var horizontalImageOffset = labelWidth / 2;
+                       var horizontalTitleOffset = imageWidth / 2;
+
+                       if (position == Button.ButtonContentLayout.ImagePosition.Bottom)
+                       {
+                               imageVertOffset = -imageVertOffset;
+                               titleVertOffset = -titleVertOffset;
+                       }
+
+                       button.ImageEdgeInsets = new UIEdgeInsets(-imageVertOffset, horizontalImageOffset, imageVertOffset, -horizontalImageOffset);
+                       button.TitleEdgeInsets = new UIEdgeInsets(titleVertOffset, -horizontalTitleOffset, -titleVertOffset, horizontalTitleOffset);
+               }
        }
 }
\ No newline at end of file
diff --git a/docs/Xamarin.Forms.Core/Xamarin.Forms/Button+ButtonContentLayout+ImagePosition.xml b/docs/Xamarin.Forms.Core/Xamarin.Forms/Button+ButtonContentLayout+ImagePosition.xml
new file mode 100644 (file)
index 0000000..fd06aed
--- /dev/null
@@ -0,0 +1,73 @@
+<Type Name="Button+ButtonContentLayout+ImagePosition" FullName="Xamarin.Forms.Button+ButtonContentLayout+ImagePosition">
+  <TypeSignature Language="C#" Value="public enum Button.ButtonContentLayout.ImagePosition" />
+  <TypeSignature Language="ILAsm" Value=".class nested public auto ansi sealed Button/ButtonContentLayout/ImagePosition extends System.Enum" />
+  <AssemblyInfo>
+    <AssemblyName>Xamarin.Forms.Core</AssemblyName>
+    <AssemblyVersion>2.0.0.0</AssemblyVersion>
+  </AssemblyInfo>
+  <Base>
+    <BaseTypeName>System.Enum</BaseTypeName>
+  </Base>
+  <Docs>
+    <summary>To be added.</summary>
+    <remarks>To be added.</remarks>
+  </Docs>
+  <Members>
+    <Member MemberName="Bottom">
+      <MemberSignature Language="C#" Value="Bottom" />
+      <MemberSignature Language="ILAsm" Value=".field public static literal valuetype Xamarin.Forms.Button/ButtonContentLayout/ImagePosition Bottom = int32(3)" />
+      <MemberType>Field</MemberType>
+      <AssemblyInfo>
+        <AssemblyVersion>2.0.0.0</AssemblyVersion>
+      </AssemblyInfo>
+      <ReturnValue>
+        <ReturnType>Xamarin.Forms.Button+ButtonContentLayout+ImagePosition</ReturnType>
+      </ReturnValue>
+      <Docs>
+        <summary>To be added.</summary>
+      </Docs>
+    </Member>
+    <Member MemberName="Left">
+      <MemberSignature Language="C#" Value="Left" />
+      <MemberSignature Language="ILAsm" Value=".field public static literal valuetype Xamarin.Forms.Button/ButtonContentLayout/ImagePosition Left = int32(0)" />
+      <MemberType>Field</MemberType>
+      <AssemblyInfo>
+        <AssemblyVersion>2.0.0.0</AssemblyVersion>
+      </AssemblyInfo>
+      <ReturnValue>
+        <ReturnType>Xamarin.Forms.Button+ButtonContentLayout+ImagePosition</ReturnType>
+      </ReturnValue>
+      <Docs>
+        <summary>To be added.</summary>
+      </Docs>
+    </Member>
+    <Member MemberName="Right">
+      <MemberSignature Language="C#" Value="Right" />
+      <MemberSignature Language="ILAsm" Value=".field public static literal valuetype Xamarin.Forms.Button/ButtonContentLayout/ImagePosition Right = int32(2)" />
+      <MemberType>Field</MemberType>
+      <AssemblyInfo>
+        <AssemblyVersion>2.0.0.0</AssemblyVersion>
+      </AssemblyInfo>
+      <ReturnValue>
+        <ReturnType>Xamarin.Forms.Button+ButtonContentLayout+ImagePosition</ReturnType>
+      </ReturnValue>
+      <Docs>
+        <summary>To be added.</summary>
+      </Docs>
+    </Member>
+    <Member MemberName="Top">
+      <MemberSignature Language="C#" Value="Top" />
+      <MemberSignature Language="ILAsm" Value=".field public static literal valuetype Xamarin.Forms.Button/ButtonContentLayout/ImagePosition Top = int32(1)" />
+      <MemberType>Field</MemberType>
+      <AssemblyInfo>
+        <AssemblyVersion>2.0.0.0</AssemblyVersion>
+      </AssemblyInfo>
+      <ReturnValue>
+        <ReturnType>Xamarin.Forms.Button+ButtonContentLayout+ImagePosition</ReturnType>
+      </ReturnValue>
+      <Docs>
+        <summary>To be added.</summary>
+      </Docs>
+    </Member>
+  </Members>
+</Type>
diff --git a/docs/Xamarin.Forms.Core/Xamarin.Forms/Button+ButtonContentLayout.xml b/docs/Xamarin.Forms.Core/Xamarin.Forms/Button+ButtonContentLayout.xml
new file mode 100644 (file)
index 0000000..63f2039
--- /dev/null
@@ -0,0 +1,93 @@
+<Type Name="Button+ButtonContentLayout" FullName="Xamarin.Forms.Button+ButtonContentLayout">
+  <TypeSignature Language="C#" Value="public sealed class Button.ButtonContentLayout" />
+  <TypeSignature Language="ILAsm" Value=".class nested public auto ansi sealed beforefieldinit Button/ButtonContentLayout extends System.Object" />
+  <AssemblyInfo>
+    <AssemblyName>Xamarin.Forms.Core</AssemblyName>
+    <AssemblyVersion>2.0.0.0</AssemblyVersion>
+  </AssemblyInfo>
+  <Base>
+    <BaseTypeName>System.Object</BaseTypeName>
+  </Base>
+  <Interfaces />
+  <Attributes>
+    <Attribute>
+      <AttributeName>System.Diagnostics.DebuggerDisplay("Image Position = {Position}, Spacing = {Spacing}")</AttributeName>
+    </Attribute>
+    <Attribute>
+      <AttributeName>Xamarin.Forms.TypeConverter(typeof(Xamarin.Forms.Button/ButtonContentTypeConverter))</AttributeName>
+    </Attribute>
+  </Attributes>
+  <Docs>
+    <summary>To be added.</summary>
+    <remarks>To be added.</remarks>
+  </Docs>
+  <Members>
+    <Member MemberName=".ctor">
+      <MemberSignature Language="C#" Value="public ButtonContentLayout (Xamarin.Forms.Button.ButtonContentLayout.ImagePosition position, double spacing);" />
+      <MemberSignature Language="ILAsm" Value=".method public hidebysig specialname rtspecialname instance void .ctor(valuetype Xamarin.Forms.Button/ButtonContentLayout/ImagePosition position, float64 spacing) cil managed" />
+      <MemberType>Constructor</MemberType>
+      <AssemblyInfo>
+        <AssemblyVersion>2.0.0.0</AssemblyVersion>
+      </AssemblyInfo>
+      <Parameters>
+        <Parameter Name="position" Type="Xamarin.Forms.Button+ButtonContentLayout+ImagePosition" />
+        <Parameter Name="spacing" Type="System.Double" />
+      </Parameters>
+      <Docs>
+        <param name="position">To be added.</param>
+        <param name="spacing">To be added.</param>
+        <summary>To be added.</summary>
+        <remarks>To be added.</remarks>
+      </Docs>
+    </Member>
+    <Member MemberName="Position">
+      <MemberSignature Language="C#" Value="public Xamarin.Forms.Button.ButtonContentLayout.ImagePosition Position { get; }" />
+      <MemberSignature Language="ILAsm" Value=".property instance valuetype Xamarin.Forms.Button/ButtonContentLayout/ImagePosition Position" />
+      <MemberType>Property</MemberType>
+      <AssemblyInfo>
+        <AssemblyVersion>2.0.0.0</AssemblyVersion>
+      </AssemblyInfo>
+      <ReturnValue>
+        <ReturnType>Xamarin.Forms.Button+ButtonContentLayout+ImagePosition</ReturnType>
+      </ReturnValue>
+      <Docs>
+        <summary>To be added.</summary>
+        <value>To be added.</value>
+        <remarks>To be added.</remarks>
+      </Docs>
+    </Member>
+    <Member MemberName="Spacing">
+      <MemberSignature Language="C#" Value="public double Spacing { get; }" />
+      <MemberSignature Language="ILAsm" Value=".property instance float64 Spacing" />
+      <MemberType>Property</MemberType>
+      <AssemblyInfo>
+        <AssemblyVersion>2.0.0.0</AssemblyVersion>
+      </AssemblyInfo>
+      <ReturnValue>
+        <ReturnType>System.Double</ReturnType>
+      </ReturnValue>
+      <Docs>
+        <summary>To be added.</summary>
+        <value>To be added.</value>
+        <remarks>To be added.</remarks>
+      </Docs>
+    </Member>
+    <Member MemberName="ToString">
+      <MemberSignature Language="C#" Value="public override string ToString ();" />
+      <MemberSignature Language="ILAsm" Value=".method public hidebysig virtual instance string ToString() cil managed" />
+      <MemberType>Method</MemberType>
+      <AssemblyInfo>
+        <AssemblyVersion>2.0.0.0</AssemblyVersion>
+      </AssemblyInfo>
+      <ReturnValue>
+        <ReturnType>System.String</ReturnType>
+      </ReturnValue>
+      <Parameters />
+      <Docs>
+        <summary>To be added.</summary>
+        <returns>To be added.</returns>
+        <remarks>To be added.</remarks>
+      </Docs>
+    </Member>
+  </Members>
+</Type>
diff --git a/docs/Xamarin.Forms.Core/Xamarin.Forms/Button+ButtonContentTypeConverter.xml b/docs/Xamarin.Forms.Core/Xamarin.Forms/Button+ButtonContentTypeConverter.xml
new file mode 100644 (file)
index 0000000..aba7930
--- /dev/null
@@ -0,0 +1,51 @@
+<Type Name="Button+ButtonContentTypeConverter" FullName="Xamarin.Forms.Button+ButtonContentTypeConverter">
+  <TypeSignature Language="C#" Value="public sealed class Button.ButtonContentTypeConverter : Xamarin.Forms.TypeConverter" />
+  <TypeSignature Language="ILAsm" Value=".class nested public auto ansi sealed beforefieldinit Button/ButtonContentTypeConverter extends Xamarin.Forms.TypeConverter" />
+  <AssemblyInfo>
+    <AssemblyName>Xamarin.Forms.Core</AssemblyName>
+    <AssemblyVersion>2.0.0.0</AssemblyVersion>
+  </AssemblyInfo>
+  <Base>
+    <BaseTypeName>Xamarin.Forms.TypeConverter</BaseTypeName>
+  </Base>
+  <Interfaces />
+  <Docs>
+    <summary>To be added.</summary>
+    <remarks>To be added.</remarks>
+  </Docs>
+  <Members>
+    <Member MemberName=".ctor">
+      <MemberSignature Language="C#" Value="public ButtonContentTypeConverter ();" />
+      <MemberSignature Language="ILAsm" Value=".method public hidebysig specialname rtspecialname instance void .ctor() cil managed" />
+      <MemberType>Constructor</MemberType>
+      <AssemblyInfo>
+        <AssemblyVersion>2.0.0.0</AssemblyVersion>
+      </AssemblyInfo>
+      <Parameters />
+      <Docs>
+        <summary>To be added.</summary>
+        <remarks>To be added.</remarks>
+      </Docs>
+    </Member>
+    <Member MemberName="ConvertFromInvariantString">
+      <MemberSignature Language="C#" Value="public override object ConvertFromInvariantString (string value);" />
+      <MemberSignature Language="ILAsm" Value=".method public hidebysig virtual instance object ConvertFromInvariantString(string value) cil managed" />
+      <MemberType>Method</MemberType>
+      <AssemblyInfo>
+        <AssemblyVersion>2.0.0.0</AssemblyVersion>
+      </AssemblyInfo>
+      <ReturnValue>
+        <ReturnType>System.Object</ReturnType>
+      </ReturnValue>
+      <Parameters>
+        <Parameter Name="value" Type="System.String" />
+      </Parameters>
+      <Docs>
+        <param name="value">To be added.</param>
+        <summary>To be added.</summary>
+        <returns>To be added.</returns>
+        <remarks>To be added.</remarks>
+      </Docs>
+    </Member>
+  </Members>
+</Type>
index b5614e1..09f5276 100644 (file)
@@ -358,6 +358,37 @@ namespace FormsGallery
         </remarks>
       </Docs>
     </Member>
+    <Member MemberName="ContentLayout">
+      <MemberSignature Language="C#" Value="public Xamarin.Forms.Button.ButtonContentLayout ContentLayout { get; set; }" />
+      <MemberSignature Language="ILAsm" Value=".property instance class Xamarin.Forms.Button/ButtonContentLayout ContentLayout" />
+      <MemberType>Property</MemberType>
+      <AssemblyInfo>
+        <AssemblyVersion>2.0.0.0</AssemblyVersion>
+      </AssemblyInfo>
+      <ReturnValue>
+        <ReturnType>Xamarin.Forms.Button+ButtonContentLayout</ReturnType>
+      </ReturnValue>
+      <Docs>
+        <summary>To be added.</summary>
+        <value>To be added.</value>
+        <remarks>To be added.</remarks>
+      </Docs>
+    </Member>
+    <Member MemberName="ContentLayoutProperty">
+      <MemberSignature Language="C#" Value="public static readonly Xamarin.Forms.BindableProperty ContentLayoutProperty;" />
+      <MemberSignature Language="ILAsm" Value=".field public static initonly class Xamarin.Forms.BindableProperty ContentLayoutProperty" />
+      <MemberType>Field</MemberType>
+      <AssemblyInfo>
+        <AssemblyVersion>2.0.0.0</AssemblyVersion>
+      </AssemblyInfo>
+      <ReturnValue>
+        <ReturnType>Xamarin.Forms.BindableProperty</ReturnType>
+      </ReturnValue>
+      <Docs>
+        <summary>To be added.</summary>
+        <remarks>To be added.</remarks>
+      </Docs>
+    </Member>
     <Member MemberName="Font">
       <MemberSignature Language="C#" Value="public Xamarin.Forms.Font Font { get; set; }" />
       <MemberSignature Language="ILAsm" Value=".property instance valuetype Xamarin.Forms.Font Font" />