[WIP] Unify the image handling (#4915)
authorMatthew Leibowitz <mattleibow@live.com>
Fri, 26 Apr 2019 20:46:13 +0000 (00:46 +0400)
committerSamantha Houts <samhouts@users.noreply.github.com>
Fri, 26 Apr 2019 20:46:13 +0000 (13:46 -0700)
* Initial code to get unifiied image handling
 - not yet tested
 - still using FileImageSource in some areas

* Updated the button renderers and added tests for Android

* Updated a few more of the Android renderers
 - also added an `IsEmpty` property to the ImageSource to indicate if this source actually contains data that can be used to try and load an image
 - added a few more "tests"
 - includes the changes for #4916

* A few more changes

* Keep the default page for the sample app

* Changing everything to ImageSource and going from there
 - Android, iOS, UWP and WPF are compiling
 - GTK, Mac and Tizen are not yet finished
 - Added a new interface for UWP to return an IconElement in addition to ImageSource (for app bar buttons)
 - not tested yet, nor are there any tests

* Renamed the property to be more useful

* All of Android is now async
 - still only minimal tests
 - also removed the bits that are in https://github.com/xamarin/Xamarin.Forms/pull/4948

* Update Xamarin.Forms.Platform.cs

* A few fixes to whitespace and nameof()

* Updated iOS and UWP wirth async image sources

* A few fixes and WPF support

* A few fixes for Android after the big merge

* Updated a few more loaders:
 - ios
 - macos
 - tizen
 - gtk

* Fix a few things after the merge

* - cast type to FileImageSource

* fix setting of title content if icon doesn't load

* fix IButtonLayoutManager to return correct control

* remove cast and add pack api

* - fix timing issues with layout/invalidation

* - remove aggresive element invalidations for now

* first set of api changes

* obsolete old apis and create new ones for ImageSource

* obsolete messages and static ordering fix

* add tests

* switch default on windows to show images on tabs

* - XStatic obsolete fix

* fix NPC test and bring back alert check on uwp

Fixes #3207
Fixes #4689

167 files changed:
Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/AppBarIconColors.cs
Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/BottomTabbedPageTests.cs
Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Bugzilla22401.cs
Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Bugzilla27417.cs
Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Bugzilla30835.cs
Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Bugzilla31255.cs
Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Bugzilla31602.cs
Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Bugzilla32801.cs
Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Bugzilla32865.cs
Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Bugzilla40073.cs
Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Bugzilla40824.cs
Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Bugzilla42364.cs
Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Bugzilla53909.cs
Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/DesktopSupportTestPage.cs
Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/GitHub1702.cs
Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue1305.cs
Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue1323.cs
Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue1342.cs
Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue1461.cs
Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue1705_2.cs
Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue1898.cs
Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue198.cs
Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue2222.cs
Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue2628.cs
Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue2818.cs
Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue2948.cs
Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue2976.cs
Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue2993.cs
Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue3089.cs
Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue4484.cs
Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue4597.cs
Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue4915.xaml [new file with mode: 0644]
Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue4915.xaml.cs [new file with mode: 0644]
Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue5057.xaml.cs
Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue889.cs
Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Xamarin.Forms.Controls.Issues.Shared.projitems
Xamarin.Forms.Controls/App.cs
Xamarin.Forms.Controls/ControlGalleryPages/AutomationPropertiesGallery.cs
Xamarin.Forms.Controls/ControlGalleryPages/FlowDirectionGallery.cs
Xamarin.Forms.Controls/ControlGalleryPages/ToolbarItems.cs
Xamarin.Forms.Controls/CoreGallery.cs
Xamarin.Forms.Controls/CoreGalleryPages/ButtonCoreGalleryPage.cs
Xamarin.Forms.Controls/CoreGalleryPages/SliderCoreGalleryPage.cs
Xamarin.Forms.Controls/GalleryPages/BackgroundImageGallery.cs
Xamarin.Forms.Controls/GalleryPages/ButtonGallery.cs
Xamarin.Forms.Controls/GalleryPages/EditableList.cs
Xamarin.Forms.Controls/GalleryPages/ImageSourcesGallery.cs [new file with mode: 0644]
Xamarin.Forms.Controls/GalleryPages/MacOSTestGallery.cs
Xamarin.Forms.Controls/GalleryPages/TemplatedTabbedGallery.cs
Xamarin.Forms.Controls/GalleryPages/TitleView.xaml.cs
Xamarin.Forms.Controls/HanselForms/BaseView.cs
Xamarin.Forms.Controls/HanselForms/BlogPage.xaml.cs
Xamarin.Forms.Controls/Xamarin.Forms.Controls.csproj
Xamarin.Forms.Core.UITests.Shared/PlatformQueries.cs
Xamarin.Forms.Core.UnitTests/ButtonUnitTest.cs
Xamarin.Forms.Core.UnitTests/NotifiedPropertiesTests.cs
Xamarin.Forms.Core/Button.cs
Xamarin.Forms.Core/FileImageSource.cs
Xamarin.Forms.Core/FontImageSource.cs
Xamarin.Forms.Core/ImageElement.cs
Xamarin.Forms.Core/ImageSource.cs
Xamarin.Forms.Core/Internals/AsyncValue.cs [moved from Xamarin.Forms.Platform.UAP/AsyncValue.cs with 64% similarity]
Xamarin.Forms.Core/MenuItem.cs
Xamarin.Forms.Core/NavigationPage.cs
Xamarin.Forms.Core/Page.cs
Xamarin.Forms.Core/PlatformConfiguration/WindowsSpecific/TabbedPage.cs
Xamarin.Forms.Core/Properties/AssemblyInfo.cs
Xamarin.Forms.Core/Slider.cs
Xamarin.Forms.Core/StackLayout.cs
Xamarin.Forms.Core/StreamImageSource.cs
Xamarin.Forms.Core/ToolbarItem.cs
Xamarin.Forms.Core/UriImageSource.cs
Xamarin.Forms.Material.Android/MaterialButtonRenderer.cs
Xamarin.Forms.Platform.Android/AppCompat/ButtonRenderer.cs
Xamarin.Forms.Platform.Android/AppCompat/MasterDetailPageRenderer.cs
Xamarin.Forms.Platform.Android/AppCompat/NavigationPageRenderer.cs
Xamarin.Forms.Platform.Android/AppCompat/TabbedPageRenderer.cs
Xamarin.Forms.Platform.Android/ButtonLayoutManager.cs
Xamarin.Forms.Platform.Android/CellAdapter.cs
Xamarin.Forms.Platform.Android/Extensions/ImageViewExtensions.cs
Xamarin.Forms.Platform.Android/FastRenderers/AutomationPropertiesProvider.cs
Xamarin.Forms.Platform.Android/FastRenderers/ButtonRenderer.cs
Xamarin.Forms.Platform.Android/FastRenderers/ImageElementManager.cs
Xamarin.Forms.Platform.Android/IButtonLayoutRenderer.cs
Xamarin.Forms.Platform.Android/Platform.cs
Xamarin.Forms.Platform.Android/Renderers/ButtonRenderer.cs
Xamarin.Forms.Platform.Android/Renderers/MasterDetailRenderer.cs
Xamarin.Forms.Platform.Android/Renderers/PageRenderer.cs
Xamarin.Forms.Platform.Android/Renderers/ShellFlyoutContentRenderer.cs
Xamarin.Forms.Platform.Android/Renderers/ShellItemRenderer.cs
Xamarin.Forms.Platform.Android/Renderers/ShellSearchView.cs
Xamarin.Forms.Platform.Android/Renderers/ShellToolbarTracker.cs
Xamarin.Forms.Platform.Android/Renderers/SliderRenderer.cs
Xamarin.Forms.Platform.Android/ResourceManager.cs
Xamarin.Forms.Platform.GTK/Cells/CellBase.cs
Xamarin.Forms.Platform.GTK/Cells/ImageCellRenderer.cs
Xamarin.Forms.Platform.GTK/Controls/Carousel.cs
Xamarin.Forms.Platform.GTK/Controls/ImageButton.cs
Xamarin.Forms.Platform.GTK/Controls/NotebookWrapper.cs
Xamarin.Forms.Platform.GTK/Controls/Page.cs
Xamarin.Forms.Platform.GTK/Extensions/ImageExtensions.cs
Xamarin.Forms.Platform.GTK/Extensions/PageExtensions.cs
Xamarin.Forms.Platform.GTK/GtkToolbarTracker.cs
Xamarin.Forms.Platform.GTK/IVisualNativeElementRenderer.cs [new file with mode: 0644]
Xamarin.Forms.Platform.GTK/Renderers/AbstractPageRenderer.cs
Xamarin.Forms.Platform.GTK/Renderers/ButtonRenderer.cs
Xamarin.Forms.Platform.GTK/Renderers/CarouselPageRenderer.cs
Xamarin.Forms.Platform.GTK/Renderers/ImageRenderer.cs
Xamarin.Forms.Platform.GTK/Renderers/MasterDetailPageRenderer.cs
Xamarin.Forms.Platform.GTK/Renderers/NavigationPageRenderer.cs
Xamarin.Forms.Platform.GTK/Renderers/TabbedPageRenderer.cs
Xamarin.Forms.Platform.GTK/VisualElementRenderer.cs
Xamarin.Forms.Platform.GTK/Xamarin.Forms.Platform.GTK.csproj
Xamarin.Forms.Platform.MacOS/Cells/ImageCellRenderer.cs
Xamarin.Forms.Platform.MacOS/Extensions/NSImageExtensions.cs
Xamarin.Forms.Platform.MacOS/Extensions/NSMenuExtensions.cs
Xamarin.Forms.Platform.MacOS/NativeToolbarTracker.cs
Xamarin.Forms.Platform.MacOS/Renderers/ButtonRenderer.cs
Xamarin.Forms.Platform.MacOS/Renderers/CarouselPageRenderer.cs
Xamarin.Forms.Platform.MacOS/Renderers/ImageRenderer.cs
Xamarin.Forms.Platform.MacOS/Renderers/PageRenderer.cs
Xamarin.Forms.Platform.MacOS/Renderers/TabbedPageRenderer.cs
Xamarin.Forms.Platform.Tizen/Extensions/ImageExtensions.cs [new file with mode: 0644]
Xamarin.Forms.Platform.Tizen/Native/ToolbarItemButton.cs
Xamarin.Forms.Platform.Tizen/Renderers/ButtonRenderer.cs
Xamarin.Forms.Platform.Tizen/Renderers/PageRenderer.cs
Xamarin.Forms.Platform.Tizen/Renderers/TabbedPageRenderer.cs
Xamarin.Forms.Platform.Tizen/ResourcePath.cs
Xamarin.Forms.Platform.UAP/BackgroundTracker.cs
Xamarin.Forms.Platform.UAP/ButtonRenderer.cs
Xamarin.Forms.Platform.UAP/Extensions.cs
Xamarin.Forms.Platform.UAP/Extensions/ImageExtensions.cs
Xamarin.Forms.Platform.UAP/FileImageSourceHandler.cs
Xamarin.Forms.Platform.UAP/FontImageSourceHandler.cs
Xamarin.Forms.Platform.UAP/FormsSlider.cs
Xamarin.Forms.Platform.UAP/IIconElementHandler.cs [new file with mode: 0644]
Xamarin.Forms.Platform.UAP/ImageButtonRenderer.cs
Xamarin.Forms.Platform.UAP/ImageConverter.cs
Xamarin.Forms.Platform.UAP/ImageElementManager.cs
Xamarin.Forms.Platform.UAP/ImageRenderer.cs
Xamarin.Forms.Platform.UAP/ImageSourceIconElementConverter.cs [moved from Xamarin.Forms.Platform.UAP/FileImageSourcePathConverter.cs with 56% similarity]
Xamarin.Forms.Platform.UAP/MasterDetailPageRenderer.cs
Xamarin.Forms.Platform.UAP/NavigationPageRenderer.cs
Xamarin.Forms.Platform.UAP/Platform.cs
Xamarin.Forms.Platform.UAP/Resources.xaml
Xamarin.Forms.Platform.UAP/SliderRenderer.cs
Xamarin.Forms.Platform.UAP/TabbedPageRenderer.cs
Xamarin.Forms.Platform.UAP/Xamarin.Forms.Platform.UAP.csproj
Xamarin.Forms.Platform.WPF/Converters/ImageConverter.cs
Xamarin.Forms.Platform.WPF/Extensions/ImageExtensions.cs
Xamarin.Forms.Platform.WPF/Renderers/ButtonRenderer.cs
Xamarin.Forms.Platform.WPF/Renderers/ImageRenderer.cs
Xamarin.Forms.Platform.WPF/Renderers/VisualPageRenderer.cs
Xamarin.Forms.Platform.WPF/WPFResources.xaml
Xamarin.Forms.Platform.iOS/Extensions/ColorExtensions.cs
Xamarin.Forms.Platform.iOS/Extensions/ToolbarItemExtensions.cs
Xamarin.Forms.Platform.iOS/Renderers/ButtonLayoutManager.cs
Xamarin.Forms.Platform.iOS/Renderers/CarouselPageRenderer.cs
Xamarin.Forms.Platform.iOS/Renderers/ImageElementManager.cs
Xamarin.Forms.Platform.iOS/Renderers/NavigationRenderer.cs
Xamarin.Forms.Platform.iOS/Renderers/PageRenderer.cs
Xamarin.Forms.Platform.iOS/Renderers/PhoneMasterDetailRenderer.cs
Xamarin.Forms.Platform.iOS/Renderers/ShellSectionRenderer.cs
Xamarin.Forms.Platform.iOS/Renderers/SliderRenderer.cs
Xamarin.Forms.Platform.iOS/Renderers/TabbedRenderer.cs
Xamarin.Forms.Platform.iOS/Renderers/TabletMasterDetailRenderer.cs
Xamarin.Forms.Xaml.UnitTests/XStatic.xaml.cs

index 98c0205..9a9d2b1 100644 (file)
@@ -47,7 +47,7 @@ namespace Xamarin.Forms.Controls.Issues
                        BarBackgroundColor = Color.Purple;
                        BarTextColor = Color.White;
                        Title = root.Title;
-                       Icon = root.Icon;
+                       IconImageSource = root.IconImageSource;
                }
        }
 }
index a7bfc54..03593e3 100644 (file)
@@ -40,8 +40,8 @@ namespace Xamarin.Forms.Controls.Issues
 
                        var longerTest = new Button() { Text = "Manual Color Tests", BackgroundColor = Color.Blue };
 
-                       Children.Add(new ContentPage() { Title = "Page 1", Content = popButton1, Icon = "coffee.png" });
-                       Children.Add(new ContentPage() { Title = "Page 2", Content = popButton2, Icon = "bank.png" });
+                       Children.Add(new ContentPage() { Title = "Page 1", Content = popButton1, IconImageSource = "coffee.png" });
+                       Children.Add(new ContentPage() { Title = "Page 2", Content = popButton2, IconImageSource = "bank.png" });
                        Button btnChangeBarText = null;
                        Button btnChangeBarItemColorText = null;
                        Button btnChangeBarSelectedItemColorText = null;
@@ -128,7 +128,7 @@ namespace Xamarin.Forms.Controls.Issues
                                        {
                                                Content = new Label() { Text = (Children.Count + 1).ToString() },
                                                Title = (Children.Count + 1).ToString(),
-                                               Icon = "calculator.png"
+                                               IconImageSource = "calculator.png"
                                        });
                                        btnRemovePage.IsEnabled = true;
                                }),
@@ -178,8 +178,8 @@ namespace Xamarin.Forms.Controls.Issues
                                                                        Children.Remove(Children.Last());
                                                                }
 
-                                                               Children.Insert(1, new ContentPage(){ Icon = "bank.png" });
-                                                               Children.Insert(1, new ContentPage(){ Icon = "bank.png" });
+                                                               Children.Insert(1, new ContentPage(){ IconImageSource = "bank.png" });
+                                                               Children.Insert(1, new ContentPage(){ IconImageSource = "bank.png" });
                                                                int i = 0;
                                                                Device.StartTimer(TimeSpan.FromSeconds(3), () =>
                                                                {
@@ -199,7 +199,7 @@ namespace Xamarin.Forms.Controls.Issues
                                                                                {
                                                                                        throw new Exception("Removing page caused Current Page to Change");
                                                                                }
-                                                                               Children.Insert(1, new ContentPage(){ Icon = "bank.png" });
+                                                                               Children.Insert(1, new ContentPage(){ IconImageSource = "bank.png" });
                                                                                CurrentPage = Children[1];
                                                                        }
                                                                        else if(i == 2)
@@ -246,7 +246,7 @@ namespace Xamarin.Forms.Controls.Issues
                        {
                                Title = "Test",
                                Content = layout,
-                               Icon = "calculator.png"
+                               IconImageSource = "calculator.png"
                        });
                }
 
index b066214..eda51ff 100644 (file)
@@ -46,7 +46,7 @@ namespace Xamarin.Forms.Controls.Issues
                                })
                        };
 
-                       Master = new ContentPage { Title = "master", Icon = "menuIcon.png", Content = listView };
+                       Master = new ContentPage { Title = "master", IconImageSource = "menuIcon.png", Content = listView };
 
                        listView.ItemSelected += (sender, e) => {
                                Detail = CreateDetailPage (string.Format("Page {0}", (e.SelectedItem as Person).Name));
@@ -103,8 +103,8 @@ namespace Xamarin.Forms.Controls.Issues
                                }
                        };
 
-                       var tbiBank = new ToolbarItem { Command = new Command (() => { }), Icon = "bank.png" };
-                       var tbiCalc = new ToolbarItem { Command = new Command (() => { }), Icon = "calculator.png" };
+                       var tbiBank = new ToolbarItem { Command = new Command (() => { }), IconImageSource = "bank.png" };
+                       var tbiCalc = new ToolbarItem { Command = new Command (() => { }), IconImageSource = "calculator.png" };
 
                        page.ToolbarItems.Add (tbiBank);
                        page.ToolbarItems.Add (tbiCalc);
index 5ae2970..0d55631 100644 (file)
@@ -31,7 +31,7 @@ Button 8 have the image on the right and the text on the left." };
                                        new Button
                                        {
                                                HeightRequest = 500, // Making sure that the image still gets centered vertically even if the HeightRequest won't be honored
-                                               Image = "coffee.png"
+                                               ImageSource = "coffee.png"
                                        }
                                }
                        };
@@ -53,9 +53,9 @@ Button 8 have the image on the right and the text on the left." };
                                                        HorizontalOptions = LayoutOptions.Center,
                                                        Children =
                                                        {
-                                                               new Button { WidthRequest = 200, HeightRequest = 300, Image = "coffee.png" },
+                                                               new Button { WidthRequest = 200, HeightRequest = 300, ImageSource = "coffee.png" },
                                                                new Button { Text = "Click Me", BackgroundColor = Color.Gray },
-                                                               new Button { Image = "coffee.png", BackgroundColor = Color.Gray },
+                                                               new Button { ImageSource = "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)),
@@ -72,7 +72,7 @@ Button 8 have the image on the right and the text on the left." };
                        return new Button
                        {
                                Text = "Click Me",
-                               Image = "coffee.png",
+                               ImageSource = "coffee.png",
                                ContentLayout = layout,
                                BackgroundColor = Color.Gray
                        };
index 7e57d22..033d2f8 100644 (file)
@@ -99,7 +99,7 @@ namespace Xamarin.Forms.Controls.Issues
 
                        public MenuPage ()
                        {
-                               Icon = "bank.png";
+                               IconImageSource = "bank.png";
                                Title = "Carsousel Memory Bug";
                                BackgroundColor = Color.FromHex ("#000000");
 
index 896039c..a58f05f 100644 (file)
@@ -63,7 +63,7 @@ namespace Xamarin.Forms.Controls.Issues
                        public Page2 ()
                        {
                                Master = new Page () { Title = "Master", 
-                                       Icon = "Icon.png" 
+                                       IconImageSource = "Icon.png" 
                                };
                                Detail = new Page () { Title = "Detail" };
                        }
index 702e1d9..65f7c1e 100644 (file)
@@ -35,7 +35,7 @@ namespace Xamarin.Forms.Controls.Issues
                        public SidemenuPage ()
                        {
                                Title = "Side";
-                               Icon = "menuIcon.png";
+                               IconImageSource = "menuIcon.png";
                                var lbl = new Label { Text = "SideMenu" };
                                var btn = new Button { Text = "Menu Opener"  };
 
@@ -49,7 +49,7 @@ namespace Xamarin.Forms.Controls.Issues
                        }
 
                        public void ChangeIcon() {
-                               Icon = "bank.png";
+                               IconImageSource = "bank.png";
                        }
                }
 
index 8002867..5554d8d 100644 (file)
@@ -17,8 +17,8 @@ namespace Xamarin.Forms.Controls.Issues
        {
                protected override void Init ()
                {
-                       Children.Add (new NavigationPage (new TestDemoPage (1)) { Title = "Tab", Icon = "bank.png" });
-                       Children.Add (new NavigationPage (new TestDemoPage (1)) { Title = "Tab 1", Icon = "bank.png" });
+                       Children.Add (new NavigationPage (new TestDemoPage (1)) { Title = "Tab", IconImageSource = "bank.png" });
+                       Children.Add (new NavigationPage (new TestDemoPage (1)) { Title = "Tab 1", IconImageSource = "bank.png" });
 
                }
 
index 2cf416e..473125e 100644 (file)
@@ -25,11 +25,11 @@ namespace Xamarin.Forms.Controls.Issues
 
                public void ChangeIcon()
                {
-                       Master.Icon = "settings";
+                       Master.IconImageSource = "settings";
                }
                public void ChangeIcon2()
                {
-                       Master.Icon = "menuIcon";
+                       Master.IconImageSource = "menuIcon";
                }
        }
 
index 6c4a328..a370c70 100644 (file)
@@ -27,7 +27,7 @@ namespace Xamarin.Forms.Controls.Issues
 
                        var thePage = new TabbedPage();
                        thePage.Children.Add(_theContent);
-                       thePage.ToolbarItems.Add(new ToolbarItem() { Text = "Refresh", Icon = "coffee.png" });
+                       thePage.ToolbarItems.Add(new ToolbarItem() { Text = "Refresh", IconImageSource = "coffee.png" });
 
                        PushAsync(thePage);
                }
index 09b853e..d612d57 100644 (file)
@@ -32,7 +32,7 @@ namespace Xamarin.Forms.Controls.Issues
                                        cell.ContextActions.Add(new MenuItem
                                        {
                                                Text = "Action",
-                                               Icon = "icon",
+                                               IconImageSource = "icon",
                                                IsDestructive = true,
                                                Command = new Command(() => DisplayAlert("TITLE", "Context action invoked", "Ok")),
                                        });
index 6a540db..37aace8 100644 (file)
@@ -36,7 +36,7 @@ namespace Xamarin.Forms.Controls.Issues
                     cell.ContextActions.Add(new MenuItem
                     {
                         Text = "Action",
-                        Icon = "icon",
+                        IconImageSource = "icon",
                         IsDestructive = true,
                         Command = new Command(() => DisplayAlert("TITLE", "Context action invoked", "Ok")),
                     });
index 854aeb7..c1697b0 100644 (file)
@@ -16,7 +16,7 @@ namespace Xamarin.Forms.Controls.Issues
                {
 
             var tbi = new ToolbarItem();
-            tbi.Icon = "synchronize.png";
+            tbi.IconImageSource = "synchronize.png";
             tbi.Order = ToolbarItemOrder.Primary;
             tbi.Priority = 0;
 
index 15cabca..174b80e 100644 (file)
@@ -173,7 +173,7 @@ namespace Xamarin.Forms.Controls.Issues
                                                var item = new MenuItem { Text = $"hello menu item {i}.{j}" };
                                                if (withImage)
                                                {
-                                                       item.Icon = Icon = "bank.png";
+                                                       item.IconImageSource = IconImageSource = "bank.png";
                                                }
                                                if (addShortcut)
                                                {
index a3d8491..992996f 100644 (file)
@@ -21,35 +21,35 @@ namespace Xamarin.Forms.Controls.Issues
                                {
                                        new Button()
                                        {
-                                               Image = "coffee.png",
+                                               ImageSource = "coffee.png",
                                                BackgroundColor = Color.GreenYellow,
                                                Text = "No padding? Height 100",
                                                HeightRequest = 100,
                                        },
                                        new Button()
                                        {
-                                               Image = "coffee.png",
+                                               ImageSource = "coffee.png",
                                                BackgroundColor = Color.Green,
                                                Padding = new Thickness(100, 0, 0, 0),
                                                Text = "Do I have left padding? I should have left padding.",
                                        },
                                        new Button()
                                        {
-                                               Image = "coffee.png",
+                                               ImageSource = "coffee.png",
                                                BackgroundColor = Color.LawnGreen,
                                                Padding = new Thickness(0, 30, 0, 0),
                                                Text = "Do I have top padding? I should have top padding."
                                        },
                                        new Button()
                                        {
-                                               Image = "coffee.png",
+                                               ImageSource = "coffee.png",
                                                BackgroundColor = Color.LightGreen,
                                                Padding = new Thickness(0, 0, 100, 0),
                                                Text = "Do I have right padding? I should have right padding."
                                        },
                                        new Button()
                                        {
-                                               Image = "coffee.png",
+                                               ImageSource = "coffee.png",
                                                BackgroundColor = Color.ForestGreen,
                                                Padding = new Thickness(0, 0, 0, 30),
                                                Text = "Do I have bottom padding? I should have bottom padding."
index 520970c..e86c09f 100644 (file)
@@ -13,7 +13,7 @@ namespace Xamarin.Forms.Controls.Issues
                {
                        var settings = new ToolbarItem
                        {
-                               Icon = "bank.png",
+                               IconImageSource = "bank.png",
                                Text = "Settings",
                                Command = new Command(ShowSettingsPage),
                        };
@@ -24,7 +24,7 @@ namespace Xamarin.Forms.Controls.Issues
 
                        Title = "Test Page";
 
-                       Icon = "Icon.png";
+                       IconImageSource = "Icon.png";
 
                }
 
@@ -44,7 +44,7 @@ namespace Xamarin.Forms.Controls.Issues
 
                        Title = "Settings";
 
-                       Icon = "bank.png";
+                       IconImageSource = "bank.png";
                }
        }
 }
index cb914fc..2d20252 100644 (file)
@@ -34,10 +34,10 @@ namespace Xamarin.Forms.Controls.Issues
                        base.OnAppearing();
                        BarTextColor = Color.White;
                        Children.RemoveAt(1);
-                       Children.Insert(1, new ContentPage { Title = "Page5", Icon = "Loyalty.png" });
+                       Children.Insert(1, new ContentPage { Title = "Page5", IconImageSource = "Loyalty.png" });
 
                        Children.RemoveAt(3);
-                       Children.Insert(2, new ContentPage { Title = "Page6", Icon = "Gift.png" });
+                       Children.Insert(2, new ContentPage { Title = "Page6", IconImageSource = "Gift.png" });
                        BarTextColor = Color.White;
                }
 
index 0affb7c..056f39d 100644 (file)
@@ -149,7 +149,7 @@ namespace Xamarin.Forms.Controls.Issues
                {
                        public ListPageCode()
                        {
-                               Icon = "coffee.png";
+                               IconImageSource = "coffee.png";
                                ListView view = new ListView(ListViewCachingStrategy.RecycleElement);
                                Content = view;
 
index f4fa871..38b60e6 100644 (file)
@@ -218,7 +218,7 @@ namespace Xamarin.Forms.Controls.Issues
                        btn.Clicked += bnToggle_Clicked;
                        Master = new ContentPage {
                                Title = string.Format ("Master sample for {0}", state),
-                               Icon = "bank.png",
+                               IconImageSource = "bank.png",
                                Padding = Device.RuntimePlatform == Device.iOS ? new Thickness(5, 60, 5, 5) : new Thickness(5),
                                Content = 
                                        new StackLayout { Children = {
index b8e7257..6407ce2 100644 (file)
@@ -27,9 +27,9 @@ namespace Xamarin.Forms.Controls.Issues
 
                public Issue1705_2()
                {
-                       _page1 = new ContentPage { Title = "TabPage1", Icon = "bank.png" };
+                       _page1 = new ContentPage { Title = "TabPage1", IconImageSource = "bank.png" };
                        _page1.Content = new StackLayout { Padding = new Thickness(0, 16), Children = { new Label { Text = "This is TabPage1 using bank.png icon.", FontAttributes = FontAttributes.Bold } } };
-                       _page2 = new ContentPage { Title = "TabPage2", Icon = "coffee.png" };
+                       _page2 = new ContentPage { Title = "TabPage2", IconImageSource = "coffee.png" };
                        _page2.Content = new StackLayout { Padding = new Thickness(0, 16), Children = { new Label { Text = "This is TabPage2 using coffee.png icon.", FontAttributes = FontAttributes.Bold } } };
                        _page3 = new ContentPage { Title = "TabPage3" };
                        _page3.Content = new StackLayout { Padding = new Thickness(0, 16), Children = { new Label { Text = "This is TabPage3 without icon.", FontAttributes = FontAttributes.Bold } } };
index 6bc3604..8296756 100644 (file)
@@ -79,8 +79,8 @@ namespace Xamarin.Forms.Controls.Issues
 
                internal static void SetupTabbedPage(TabbedPage tabbedPage, AToolbarPlacement placement)
                {
-                       ContentPage Issue1898PageOne = new ContentPage() { Title = Title1, Icon = "bank.png" };
-                       ContentPage Issue1898PageTwo = new ContentPage() { Title = Title2, Icon = "bank.png" };
+                       ContentPage Issue1898PageOne = new ContentPage() { Title = Title1, IconImageSource = "bank.png" };
+                       ContentPage Issue1898PageTwo = new ContentPage() { Title = Title2, IconImageSource = "bank.png" };
 
                        Issue1898PageOne.Content =
                                new StackLayout
@@ -90,9 +90,9 @@ namespace Xamarin.Forms.Controls.Issues
                                        {
                                                new Label(){ Text = "Click through each button on each tab to make sure they do what they say they do" },
                                                new Button(){ Text = ChangeTitle1, Command = new Command(() => Issue1898PageOne.Title = ChangeTitle1) },
-                                               new Button(){ Text = ChangeIcon1, Command = new Command(() => Issue1898PageOne.Icon = "coffee.png")},
-                                               new Button(){ Text = ChangeIconPage2, Command = new Command(() => Issue1898PageTwo.Icon = "coffee.png")},
-                                               new Button(){ Text = ChangeIcon1Null, Command = new Command(() => Issue1898PageOne.Icon = null)},
+                                               new Button(){ Text = ChangeIcon1, Command = new Command(() => Issue1898PageOne.IconImageSource = "coffee.png")},
+                                               new Button(){ Text = ChangeIconPage2, Command = new Command(() => Issue1898PageTwo.IconImageSource = "coffee.png")},
+                                               new Button(){ Text = ChangeIcon1Null, Command = new Command(() => Issue1898PageOne.IconImageSource = null)},
                                        }
                                };
 
@@ -103,9 +103,9 @@ namespace Xamarin.Forms.Controls.Issues
                                        Children =
                                        {
                                                new Button(){ Text = ChangeTitle2, Command = new Command(() => Issue1898PageTwo.Title = ChangeTitle2) },
-                                               new Button(){ Text = ChangeIcon2, Command = new Command(() => Issue1898PageTwo.Icon = "bank.png")},
-                                               new Button(){ Text = ChangeIconPage1, Command = new Command(() => Issue1898PageOne.Icon = "calculator.png")},
-                                               new Button(){ Text = ChangeIcon2Null, Command = new Command(() => Issue1898PageTwo.Icon = null)},
+                                               new Button(){ Text = ChangeIcon2, Command = new Command(() => Issue1898PageTwo.IconImageSource = "bank.png")},
+                                               new Button(){ Text = ChangeIconPage1, Command = new Command(() => Issue1898PageOne.IconImageSource = "calculator.png")},
+                                               new Button(){ Text = ChangeIcon2Null, Command = new Command(() => Issue1898PageTwo.IconImageSource = null)},
                                        }
                                };
 
index 211a255..dada9f5 100644 (file)
@@ -27,13 +27,13 @@ namespace Xamarin.Forms.Controls.Issues
                        leavePageBtn.Clicked += (s, e) => Navigation.PopModalAsync ();
 
                        var navigationPageOne = new NavigationPage (new ContentPage {
-                               Icon = "calculator.png",
+                               IconImageSource = "calculator.png",
                                Content = leavePageBtn
                        }) {
                                Title = "Page One",
                        };
                        var navigationPageTwo = new NavigationPage (new ContentPage {
-                               Icon = "calculator.png",
+                               IconImageSource = "calculator.png",
                        }) {
                                Title = "Page Two",
                        };
@@ -41,11 +41,11 @@ namespace Xamarin.Forms.Controls.Issues
                                Title = "No Crash",
                        }) {
                                Title = "Page Three",
-                               Icon = "calculator.png"
+                               IconImageSource = "calculator.png"
                        };
                        var navigationPageFour = new NavigationPage (new ContentPage ()) {
                                Title = "Page Four",
-                               Icon = "calculator.png"
+                               IconImageSource = "calculator.png"
                        };
 
                        Children.Add (navigationPageOne);
index 60e635a..0cca415 100644 (file)
@@ -16,7 +16,7 @@ namespace Xamarin.Forms.Controls.Issues
        {
                protected override void Init ()
                {
-                       var tbItem = new ToolbarItem { Text = "hello", Icon="wrongName" };
+                       var tbItem = new ToolbarItem { Text = "hello", IconImageSource="wrongName" };
                        ToolbarItems.Add(tbItem);
 
                        PushAsync (new Issue22221 ());
index ffdeaaa..fa5fd0d 100644 (file)
@@ -11,7 +11,7 @@ namespace Xamarin.Forms.Controls.Issues
                public Issue2628 ()
                {
                        var button1 = new Button { Text = "Click !!!!!!!!!!"};
-                       BackgroundImage="bank.png";
+                       BackgroundImageSource="bank.png";
                        button1.Clicked += ButtonAction;
 
                        Content = new StackLayout {
@@ -25,7 +25,7 @@ namespace Xamarin.Forms.Controls.Issues
 
                public  void ButtonAction(object sender, EventArgs args)
                {
-                       BackgroundImage="calculator.png";
+                       BackgroundImageSource="calculator.png";
                }
        }
 }
index 2b6ca3f..6934d2a 100644 (file)
@@ -15,7 +15,7 @@ namespace Xamarin.Forms.Controls.Issues
                        {
                                Title = "Master",
                                BackgroundColor = Color.SkyBlue,
-                               Icon = "menuIcon"
+                               IconImageSource = "menuIcon"
                        };
 
                        Detail = new NavigationPage(new ContentPage
index 20cdd96..c6856f1 100644 (file)
@@ -68,7 +68,7 @@ namespace Xamarin.Forms.Controls.Issues
                        public ContractsPage ()
                        {
                                Title = "Contracts";
-                               Icon = "bank.png";
+                               IconImageSource = "bank.png";
 
                                var grid = new Grid();
                                grid.ColumnDefinitions.Add(new ColumnDefinition());
index 929e3c1..09b1836 100644 (file)
@@ -19,16 +19,16 @@ namespace Xamarin.Forms.Controls.Issues
                {
 
                        // built-in Xamarin.Forms controls
-                       Children.Add (new XamarinFormsPage {Title = "DEMOA", Icon = "bank.png"});
+                       Children.Add (new XamarinFormsPage {Title = "DEMOA", IconImageSource = "bank.png"});
 
                        // custom renderer for the list, using a native built-in cell type
-                       Children.Add (new NativeListPage {Title = "DEMOB", Icon = "bank.png"});
+                       Children.Add (new NativeListPage {Title = "DEMOB", IconImageSource = "bank.png"});
 
                        // built in Xamarin.Forms list, but with a native cell custom-renderer
-                       Children.Add (new XamarinFormsNativeCellPage {Title = "DEMOC", Icon = "bank.png"});
+                       Children.Add (new XamarinFormsNativeCellPage {Title = "DEMOC", IconImageSource = "bank.png"});
 
                        // custom renderer for the list, using a native cell that has been custom-defined in native code
-                       Children.Add (new NativeListViewPage2 {Title = "DEMOD", Icon = "bank.png"});
+                       Children.Add (new NativeListViewPage2 {Title = "DEMOD", IconImageSource = "bank.png"});
                }
 
 #if UITEST
index 027b20b..148aa83 100644 (file)
@@ -38,7 +38,7 @@ namespace Xamarin.Forms.Controls.Issues
                                var contentPage = new ContentPage()
                                {
                                        Content = grid,
-                                       Icon = "coffee.png"
+                                       IconImageSource = "coffee.png"
                                };
 
                                return contentPage;
@@ -48,7 +48,7 @@ namespace Xamarin.Forms.Controls.Issues
                        Children.Add((createPage()));
                        Children.Add(new ContentPage()
                        {
-                               Icon = "calculator.png",
+                               IconImageSource = "calculator.png",
                                Content = new Button()
                                {
                                        Text = "Click Me",
index 563a09e..599ca66 100644 (file)
@@ -110,7 +110,7 @@ namespace Xamarin.Forms.Controls.Issues
                {
                        public ListPageCode()
                        {
-                               Icon = "coffee.png";
+                               IconImageSource = "coffee.png";
                                ListView view = new ListView(ListViewCachingStrategy.RecycleElement);
                                Content = view;
 
index a99ff4f..e2be114 100644 (file)
@@ -32,7 +32,7 @@ namespace Xamarin.Forms.Controls.Issues
                                        Orientation = StackOrientation.Horizontal,
                                        Children =
                                        {
-                                               new Button(){ Image = "bank.png", AutomationId="bank"},
+                                               new Button(){ ImageSource = "bank.png", AutomationId="bank"},
                                                new Image(){Source = "bank.png"},
                                                new ImageButton{Source = "bank.png"}
                                        }
index 6b07327..af0558b 100644 (file)
@@ -37,7 +37,7 @@ namespace Xamarin.Forms.Controls.Issues
                protected override void Init()
                {
                        _image = new Image() { Source = _fileName, AutomationId = _fileName, ClassId = "Something" };
-                       _button = new Button() { Image = _fileName, AutomationId = _fileName };
+                       _button = new Button() { ImageSource = _fileName, AutomationId = _fileName };
                        _imageButton = new ImageButton() { Source = _fileName, AutomationId = _fileName };
                        _listView = new ListView()
                        {
@@ -63,7 +63,7 @@ namespace Xamarin.Forms.Controls.Issues
                                        if (button.Text == _disappearText)
                                        {
                                                _image.Source = null;
-                                               _button.Image = null;
+                                               _button.ImageSource = null;
                                                _imageButton.Source = null;
                                                _listView.ItemsSource = new string[] { null };
                                                Device.BeginInvokeOnMainThread(() => button.Text = _appearText);
@@ -71,7 +71,7 @@ namespace Xamarin.Forms.Controls.Issues
                                        else
                                        {
                                                _image.Source = _fileName;
-                                               _button.Image = _fileName;
+                                               _button.ImageSource = _fileName;
                                                _imageButton.Source = _fileName;
                                                _listView.ItemsSource = new string[] { _fileName };
                                                Device.BeginInvokeOnMainThread(() => button.Text = _disappearText);
diff --git a/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue4915.xaml b/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue4915.xaml
new file mode 100644 (file)
index 0000000..8c48f5d
--- /dev/null
@@ -0,0 +1,19 @@
+<?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.Issue4915ContentPage"
+             xmlns:local="clr-namespace:Xamarin.Forms.Controls"
+            BackgroundImage="{Binding Image}"
+            Icon="{Binding Image}">
+    <ContentPage.ToolbarItems>
+        <ToolbarItem Name="MenuItem1" Order="Primary" Icon="{Binding Image}" Text="Item 1" Priority="0" />
+    </ContentPage.ToolbarItems>
+    <ContentPage.Content>
+        <StackLayout>
+            <Button Image="{Binding Image}"></Button>
+            <Slider ThumbImage="{Binding Image}"></Slider>
+            <Label Text="Verify that Button.Image, MenuItem.Icon, Page.BackgroundImage, Page.Icon, Slider.ThumbImage all have coffee cups"></Label>
+            <Label Text="Nothing Crashed"></Label>
+        </StackLayout>
+    </ContentPage.Content>
+</ContentPage>
\ No newline at end of file
diff --git a/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue4915.xaml.cs b/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue4915.xaml.cs
new file mode 100644 (file)
index 0000000..69d9099
--- /dev/null
@@ -0,0 +1,62 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+using Xamarin.Forms;
+using Xamarin.Forms.CustomAttributes;
+using Xamarin.Forms.Internals;
+using Xamarin.Forms.Xaml;
+#if UITEST
+using Xamarin.UITest;
+using NUnit.Framework;
+#endif
+
+namespace Xamarin.Forms.Controls.Issues
+{
+       [Preserve(AllMembers = true)]
+       [Issue(IssueTracker.Github, 4915, "Unify the image handling")]
+       public class Issue4915 : TestTabbedPage
+       {
+               protected override void Init()
+               {
+                       var navPage = new NavigationPage(new Issue4915ContentPage()) { Title = "nav page 1" };
+#pragma warning disable CS0618 // Type or member is obsolete
+                       navPage.SetBinding(Page.IconProperty, "Image");
+#pragma warning restore CS0618 // Type or member is obsolete
+                       navPage.BindingContext = new Issue4915ContentPage.ViewModel();
+
+                       Children.Add(navPage);
+                       Children.Add(new Issue4915ContentPage() { Title = "page 2" });
+               }
+
+#if UITEST
+               [Test]
+               public void LegacyImageSourceProperties()
+               {
+                       RunningApp.WaitForElement("Nothing Crashed");
+               }
+#endif
+
+       }
+
+       [Preserve(AllMembers = true)]
+       public partial class Issue4915ContentPage : ContentPage
+       {
+               public Issue4915ContentPage()
+               {
+#if APP
+                       InitializeComponent();
+#endif
+                       BindingContext = new ViewModel();
+
+               }
+
+               [Preserve(AllMembers = true)]
+               public class ViewModel
+               {
+                       public string Image { get; set; } = "coffee.png";
+               }
+       }
+}
\ No newline at end of file
index 357bf97..f7f035e 100644 (file)
@@ -25,7 +25,7 @@ namespace Xamarin.Forms.Controls.Issues
 
                void BtnSetBkgndImg_Clicked(object sender, System.EventArgs e)
                {
-                       BackgroundImage = "test.jpg";
+                       BackgroundImageSource = "test.jpg";
                }
 
                void BtnSetBkgndColorDefault_Clicked(object sender, System.EventArgs e)
@@ -35,7 +35,7 @@ namespace Xamarin.Forms.Controls.Issues
 
                void BtnSetBkgndImgNull_Clicked(object sender, System.EventArgs e)
                {
-                       BackgroundImage = null;
+                       BackgroundImageSource = null;
                }
        }
 #endif
index 75b08a1..a2a8ea4 100644 (file)
@@ -43,7 +43,7 @@ namespace Xamarin.Forms.Controls.Issues
 
                        var master = new ContentPage {
                                Title = "Master",
-                               Icon = "bank.png",
+                               IconImageSource = "bank.png",
                                Content = listView
                        };
 
@@ -114,8 +114,8 @@ namespace Xamarin.Forms.Controls.Issues
                                }
                        };
 
-                       tabOne.SetValue (IconProperty, "bank.png");
-                       tabTwo.SetValue (IconProperty, "coffee.png");
+                       tabOne.SetValue (IconImageSourceProperty, "bank.png");
+                       tabTwo.SetValue (IconImageSourceProperty, "coffee.png");
                        Children.Add (tabOne);
                        Children.Add (tabTwo);
                }
index 2c6d298..062a886 100644 (file)
@@ -11,6 +11,9 @@
   <ItemGroup>
     <Compile Include="$(MSBuildThisFileDirectory)Bugzilla59172.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)Issue4684.xaml.cs" />
+    <Compile Include="$(MSBuildThisFileDirectory)Issue4915.xaml.cs">
+      <SubType>Code</SubType>
+    </Compile>
     <Compile Include="$(MSBuildThisFileDirectory)Issue5131.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)Issue5376.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)Bugzilla60787.xaml.cs">
       <Generator>MSBuild:UpdateDesignTimeXaml</Generator>
     </EmbeddedResource>
   </ItemGroup>
+  <ItemGroup>
+    <EmbeddedResource Include="$(MSBuildThisFileDirectory)Issue4915.xaml">
+      <SubType>Designer</SubType>
+      <Generator>MSBuild:UpdateDesignTimeXaml</Generator>
+    </EmbeddedResource>
+  </ItemGroup>
 </Project>
\ No newline at end of file
index aa1af7f..38bc8e2 100644 (file)
@@ -37,6 +37,8 @@ namespace Xamarin.Forms.Controls
                        SetMainPage(CreateDefaultMainPage());
 
                        //TestMainPageSwitches();
+
+                       //SetMainPage(new ImageSourcesGallery());
                }
 
                protected override void OnStart()
@@ -109,7 +111,7 @@ namespace Xamarin.Forms.Controls
                {
                        var layout = new StackLayout { BackgroundColor = Color.Red };
                        layout.Children.Add(new Label { Text = "This is master Page" });
-                       var master = new ContentPage { Title = "Master", Content = layout, BackgroundColor = Color.SkyBlue, Icon ="menuIcon" };
+                       var master = new ContentPage { Title = "Master", Content = layout, BackgroundColor = Color.SkyBlue, IconImageSource ="menuIcon" };
                        master.On<iOS>().SetUseSafeArea(true);
                        var mdp = new MasterDetailPage
                        {
@@ -117,11 +119,11 @@ namespace Xamarin.Forms.Controls
                                Master = master,
                                Detail = CoreGallery.GetMainPage()
                        };
-                       master.Icon.AutomationId = "btnMDPAutomationID";
+                       master.IconImageSource.AutomationId = "btnMDPAutomationID";
                        mdp.SetAutomationPropertiesName("Main page");
                        mdp.SetAutomationPropertiesHelpText("Main page help text");
-                       mdp.Master.Icon.SetAutomationPropertiesHelpText("This as MDP icon");
-                       mdp.Master.Icon.SetAutomationPropertiesName("MDPICON");
+                       mdp.Master.IconImageSource.SetAutomationPropertiesHelpText("This as MDP icon");
+                       mdp.Master.IconImageSource.SetAutomationPropertiesName("MDPICON");
                        return mdp;
 
             //return new XamStore.StoreShell();
index d446947..a92de15 100644 (file)
@@ -69,7 +69,7 @@ namespace Xamarin.Forms.Controls
                        this.SetAutomationPropertiesName("Accessibility Gallery Page");
                        this.SetAutomationPropertiesHelpText("Demonstrates accessibility settings");
 
-                       var toolbarItem = new ToolbarItem { Icon = "coffee.png" };
+                       var toolbarItem = new ToolbarItem { IconImageSource = "coffee.png" };
                        toolbarItem.SetAutomationPropertiesName(toolbarItemName);
                        ToolbarItems.Add(toolbarItem);
                        toolbarItem.Command = new Command(() => { Navigation.PushAsync(new ContentPage()); });
index 85f9274..17fa8e0 100644 (file)
@@ -112,13 +112,13 @@ namespace Xamarin.Forms.Controls
                {
                        var item = new ToolbarItem
                        {
-                               Icon = "coffee.png",
+                               IconImageSource = "coffee.png",
                                Text = "Item 1",
                        };
 
                        var item2 = new ToolbarItem
                        {
-                               Icon = "bank.png",
+                               IconImageSource = "bank.png",
                                Text = "Item 2",
                        };
 
index cf76f17..97f54a2 100644 (file)
@@ -41,12 +41,12 @@ namespace Xamarin.Forms.Controls
                        tb4.Text = "tb4";
                        tb4.Order = ToolbarItemOrder.Secondary;
                        tb4.Command = command;
-                       tb4.Icon = "coffee";
+                       tb4.IconImageSource = "coffee";
                        tb4.AutomationId = "toolbaritem_secondary2";
 
                        var tb5 = new ToolbarItem();
                        tb5.Text = "tb5";
-                       tb5.Icon = "bank.png";
+                       tb5.IconImageSource = "bank.png";
                        tb5.Order = ToolbarItemOrder.Secondary;
                        tb5.Command = new Command(async () => {
                                await Navigation.PushAsync(new ToolbarItems());
index 493e837..d855433 100644 (file)
@@ -46,7 +46,7 @@ namespace Xamarin.Forms.Controls
 
                        var toCrashButton = new Button { Text = "Crash Me" };
 
-                       var masterPage = new ContentPage { Title = "Menu", Icon = "bank.png", Content = toCrashButton };
+                       var masterPage = new ContentPage { Title = "Menu", IconImageSource = "bank.png", Content = toCrashButton };
                        var detailPage = new CoreRootPage(this, NavigationBehavior.PushModalAsync) { Title = "DetailPage" };
 
                        bool toggle = false;
@@ -136,7 +136,7 @@ namespace Xamarin.Forms.Controls
                        Children.Add(new NavigationPage(new Page())
                        {
                                Title = "Rubriques",
-                               Icon = "coffee.png",
+                               IconImageSource = "coffee.png",
                                BarBackgroundColor = Color.Blue,
                                BarTextColor = Color.Aqua
                        });
index 3a285a3..2a1844a 100644 (file)
@@ -84,8 +84,8 @@ namespace Xamarin.Forms.Controls
 
                        var imageContainer = new ViewContainer<Button> (Test.Button.Image, 
                                new Button {
-                                       Text = "Image", 
-                                       Image = new FileImageSource { File = "bank.png" }
+                                       Text = "Image",
+                                       ImageSource = new FileImageSource { File = "bank.png" }
                                }
                        )
                        ;
index 5ee9ebe..146ec1d 100644 (file)
@@ -24,7 +24,7 @@ namespace Xamarin.Forms.Controls
                        var minTrackColorContainer = new ValueViewContainer<Slider> (Test.Slider.MinimumTrackColor, new Slider { MinimumTrackColor = Color.Red, Value = 0.5 }, "Value", value => value.ToString ());
                        var maxTrackColorContainer = new ValueViewContainer<Slider> (Test.Slider.MaximumTrackColor, new Slider { MaximumTrackColor = Color.Red, Value = 0.5 }, "Value", value => value.ToString ());
                        var thumbColorContainer = new ValueViewContainer<Slider> (Test.Slider.ThumbColor, new Slider { ThumbColor = Color.Red, Value = 0.5 }, "Value", value => value.ToString ());
-                       var thumbImageContainer = new ValueViewContainer<Slider> (Test.Slider.ThumbImage, new Slider { ThumbImage = "coffee.png", Value = 0.5 }, "Value", value => value.ToString ());
+                       var thumbImageContainer = new ValueViewContainer<Slider> (Test.Slider.ThumbImage, new Slider { ThumbImageSource = "coffee.png", Value = 0.5 }, "Value", value => value.ToString ());
 
                        var dragStartedContainer = new EventViewContainer<Slider>(Test.Slider.DragStarted, new Slider { Value = 0.5 });
                        dragStartedContainer.View.DragStarted += (sender, args) => dragStartedContainer.EventFired();
index e105928..70dad34 100644 (file)
@@ -16,7 +16,7 @@ namespace Xamarin.Forms.Controls
                                await Navigation.PushModalAsync (new TabbedPage {
                                        ItemTemplate = new DataTemplate (() => {
                                                var page = new ContentPage();
-                                               page.SetBinding (BackgroundImageProperty, ".");
+                                               page.SetBinding (BackgroundImageSourceProperty, ".");
                                                return page;
                                        }),
 
@@ -32,7 +32,7 @@ namespace Xamarin.Forms.Controls
                                await Navigation.PushModalAsync (new CarouselPage {
                                        ItemTemplate = new DataTemplate (() => {
                                                var page = new ContentPage();
-                                               page.SetBinding (BackgroundImageProperty, ".");
+                                               page.SetBinding (BackgroundImageSourceProperty, ".");
                                                return page;
                                        }),
 
@@ -51,7 +51,7 @@ namespace Xamarin.Forms.Controls
                                                        FontSize = 42
                                                }})
                                        {
-                                               BackgroundImage = "oasis.jpg"
+                                               BackgroundImageSource = "oasis.jpg"
                                        }
                                );
                        };
@@ -59,7 +59,7 @@ namespace Xamarin.Forms.Controls
                        var carousel = new Button { Text = "CarouselPage" };
                        carousel.Clicked += async (sender, args) => {
                                await Navigation.PushAsync (new CarouselPage {
-                                       BackgroundImage = "crimson.jpg",
+                                       BackgroundImageSource = "crimson.jpg",
                                        ItemsSource = new[] { "test1", "test2" }
                                });
                        };
@@ -67,7 +67,7 @@ namespace Xamarin.Forms.Controls
                        var tabbed = new Button { Text = "TabbedPage" };
                        tabbed.Clicked += async (sender, args) => {
                                await Navigation.PushAsync (new TabbedPage {
-                                       BackgroundImage = "crimson.jpg",
+                                       BackgroundImageSource = "crimson.jpg",
                                        ItemsSource = new[] { "test1", "test2" }
                                });
                        };
@@ -77,7 +77,7 @@ namespace Xamarin.Forms.Controls
                                await Navigation.PushModalAsync (new MasterDetailPage {
                                        Master = new ContentPage { Title = "Master" },
                                        Detail = new ContentPage(),
-                                       BackgroundImage = "crimson.jpg",
+                                       BackgroundImageSource = "crimson.jpg",
                                });
                        };
 
index f568d99..e260243 100644 (file)
@@ -69,7 +69,7 @@ namespace Xamarin.Forms.Controls
                        var busy = new Button { Text = "Toggle Busy" };
                        var alert = new Button { Text = "Alert" };
                        var alertSingle = new Button {Text = "Alert Single"};
-                       var image = new Button { Text = "Image Button", Image = new FileImageSource {File = "bank.png"}, BackgroundColor = Color.Blue.WithLuminosity (.8) };
+                       var image = new Button { Text = "Image Button", ImageSource = new FileImageSource {File = "bank.png"}, BackgroundColor = Color.Blue.WithLuminosity (.8) };
 
                        themedButton.Clicked += (sender, args) => themedButton.Font = Font.Default;
 
index 3f98473..82e177b 100644 (file)
@@ -71,7 +71,7 @@ namespace Xamarin.Forms.Controls
                                var delete = new MenuItem { Text = "Delete", IsDestructive = true };
                                delete.SetBinding (MenuItem.CommandProperty, "Delete");
 
-                               var mark = new MenuItem { Text = "Mark",  Icon = "calculator.png" };
+                               var mark = new MenuItem { Text = "Mark",  IconImageSource = "calculator.png" };
                                var move = new MenuItem { Text = "Move" };
 
                                //move.Clicked += async (sender, e) => await Navigation.PopAsync();
diff --git a/Xamarin.Forms.Controls/GalleryPages/ImageSourcesGallery.cs b/Xamarin.Forms.Controls/GalleryPages/ImageSourcesGallery.cs
new file mode 100644 (file)
index 0000000..dd010a9
--- /dev/null
@@ -0,0 +1,413 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Xamarin.Forms.Controls
+{
+       public class ImageSourcesGallery : NavigationPage
+       {
+               public ImageSourcesGallery()
+                       : base(new RootPage())
+               {
+               }
+
+               static Picker CreateImageSourcePicker(string title, Action<Func<ImageSource>> onSelected)
+               {
+                       var items = new[]
+                       {
+                               new ImageSourcePickerItem
+                               {
+                                       Text = "<none>",
+                                       Getter = () => null
+                               },
+                               new ImageSourcePickerItem
+                               {
+                                       Text = "App Resource",
+                                       Getter = () => ImageSource.FromFile("bank.png")
+                               },
+                               new ImageSourcePickerItem
+                               {
+                                       Text = "Embedded",
+                                       Getter = () => ImageSource.FromResource("Xamarin.Forms.Controls.GalleryPages.crimson.jpg", typeof(App))
+                               },
+                               new ImageSourcePickerItem
+                               {
+                                       Text = "Stream",
+                                       Getter = () => ImageSource.FromStream(() => typeof(App).Assembly.GetManifestResourceStream("Xamarin.Forms.Controls.coffee.png"))
+                               },
+                               new ImageSourcePickerItem
+                               {
+                                       Text = "URI",
+                                       Getter = () => new UriImageSource
+                                       {
+                                               Uri = new Uri("https://beehive.blob.core.windows.net/staticimages/FeatureImages/MutantLizard01.png"),
+                                               CachingEnabled = false
+                                       }
+                               },
+                               new ImageSourcePickerItem
+                               {
+                                       Text = "Font Glyph",
+                                       Getter = () =>
+                                       {
+                                               var fontFamily = "";
+                                               switch (Device.RuntimePlatform)
+                                               {
+                                                       case Device.iOS:
+                                                               fontFamily = "Ionicons";
+                                                               break;
+                                                       case Device.UWP:
+                                                               fontFamily = "Assets/Fonts/ionicons.ttf#ionicons";
+                                                               break;
+                                                       case Device.Android:
+                                                       default:
+                                                               fontFamily = "fonts/ionicons.ttf#";
+                                                               break;
+                                               }
+                                               return new FontImageSource
+                                               {
+                                                       Color = Color.Black,
+                                                       FontFamily = fontFamily,
+                                                       Glyph = "\uf233",
+                                                       Size = 24,
+                                               };
+                                       }
+                               },
+                       };
+
+                       var picker = new Picker
+                       {
+                               Title = title,
+                               ItemsSource = items,
+                               ItemDisplayBinding = new Binding("Text"),
+                       };
+
+                       picker.SelectedIndexChanged += (sender, e) =>
+                       {
+                               var item = (ImageSourcePickerItem)picker.SelectedItem;
+                               var text = item.Text;
+                               onSelected?.Invoke(item.Getter);
+                       };
+
+                       return picker;
+               }
+
+               class ImageSourcePickerItem
+               {
+                       public string Text { get; set; }
+
+                       public Func<ImageSource> Getter { get; set; }
+               }
+
+               class RootPage : ContentPage
+               {
+                       public RootPage()
+                       {
+                               Title = "Image Source Tests";
+
+                               Content = new ScrollView
+                               {
+                                       Content = new StackLayout
+                                       {
+                                               Padding = 20,
+                                               Spacing = 10,
+                                               Children =
+                                               {
+                                                       CreateImageSourcePicker("Change Title Icon", getter => NavigationPage.SetTitleIcon(this, getter())),
+                                                       new Button
+                                                       {
+                                                               Text = "Page & Toolbar",
+                                                               Command = new Command(() => Navigation.PushAsync(new PagePropertiesPage()))
+                                                       },
+                                                       new Button
+                                                       {
+                                                               Text = "ListView & Context Actions",
+                                                               Command = new Command(() => Navigation.PushAsync(new ListViewContextActionsPage()))
+                                                       },
+                                                       new Button
+                                                       {
+                                                               Text = "Image View",
+                                                               Command = new Command(() => Navigation.PushAsync(new ImageViewPage()))
+                                                       },
+                                                       new Button
+                                                       {
+                                                               Text = "Buttons",
+                                                               Command = new Command(() => Navigation.PushAsync(new ButtonsPage()))
+                                                       },
+                                                       new Button
+                                                       {
+                                                               Text = "Slider",
+                                                               Command = new Command(() => Navigation.PushAsync(new SliderPage()))
+                                                       },
+                                               }
+                                       }
+                               };
+                       }
+               }
+
+               class PagePropertiesPage : TabbedPage
+               {
+                       public PagePropertiesPage()
+                       {
+                               Title = "Page & Toolbar";
+
+                               Children.Add(new TabPage { Title = "Tab 1" });
+                               Children.Add(new TabPage { Title = "Tab 2" });
+                               Children.Add(new TabPage { Title = "Tab 3" });
+                       }
+
+                       class TabPage : ContentPage
+                       {
+                               ToolbarItem _toolbarItem;
+
+                               public TabPage()
+                               {
+                                       ToolbarItems.Add(_toolbarItem = new ToolbarItem("MENU", null, delegate
+                                       {
+                                       }));
+
+                                       Content = new ScrollView
+                                       {
+                                               Content = new StackLayout
+                                               {
+                                                       Padding = 20,
+                                                       Spacing = 10,
+                                                       Children =
+                                                       {
+                                                               CreateImageSourcePicker("Change Tab Icon", getter => IconImageSource = getter()),
+                                                               CreateImageSourcePicker("Change Toolbar Icon", getter => _toolbarItem.IconImageSource = getter()),
+                                                               CreateImageSourcePicker("Change Background", getter => BackgroundImageSource = getter()),
+                                                       }
+                                               }
+                                       };
+                               }
+                       }
+               }
+
+               class ListViewContextActionsPage : ContentPage
+               {
+                       ListView _listView;
+                       string[] _items = new[] { "one", "two", "three", "four", "five" };
+
+                       public ListViewContextActionsPage()
+                       {
+                               Title = "ListView & Context Actions";
+
+                               Content = new ScrollView
+                               {
+                                       Content = new StackLayout
+                                       {
+                                               Padding = 20,
+                                               Spacing = 10,
+                                               Children =
+                                               {
+                                                       new Label
+                                                       {
+                                                               Text = "Select the item source from the picker and then view the context menu of each item.",
+                                                               LineBreakMode = LineBreakMode.WordWrap,
+                                                       },
+                                                       CreateImageSourcePicker("Select Icon Source", getter =>
+                                                       {
+                                                               _listView.ItemsSource = null;
+                                                               _listView.ItemsSource = CreateDataItems(getter);
+                                                       }),
+                                                       (_listView = new ListView
+                                                       {
+                                                               Margin = new Thickness(-20, 0, -20, -20),
+                                                               ItemsSource = CreateDataItems(),
+                                                               ItemTemplate = new DataTemplate(() =>
+                                                               {
+                                                                       var menuItem = new MenuItem();
+                                                                       menuItem.SetBinding(MenuItem.TextProperty, new Binding(nameof(ListItem.Text)));
+                                                                       menuItem.SetBinding(MenuItem.IconImageSourceProperty, new Binding(nameof(ListItem.ContextImage)));
+
+                                                                       var cell = new ImageCell();
+                                                                       cell.ContextActions.Add(menuItem);
+                                                                       cell.SetBinding(ImageCell.TextProperty, new Binding(nameof(ListItem.Text)));
+                                                                       cell.SetBinding(ImageCell.ImageSourceProperty, new Binding(nameof(ListItem.Image)));
+
+                                                                       return cell;
+                                                               }),
+                                                       })
+                                               }
+                                       }
+                               };
+                       }
+
+                       IEnumerable<ListItem> CreateDataItems(Func<ImageSource> getter = null)
+                       {
+                               return _items.Select(i => new ListItem
+                               {
+                                       Text = i,
+                                       Image = getter?.Invoke(),
+                                       ContextImage = getter?.Invoke(),
+                               });
+                       }
+
+                       class ListItem
+                       {
+                               public string Text { get; set; }
+
+                               public ImageSource Image { get; set; }
+
+                               public ImageSource ContextImage { get; set; }
+                       }
+               }
+
+               class ImageViewPage : ContentPage
+               {
+                       Image _image = null;
+                       Image _imageAutosize = null;
+                       ActivityIndicator _loading = null;
+
+                       public ImageViewPage()
+                       {
+                               Title = "Image View";
+
+                               Content = new ScrollView
+                               {
+                                       Content = new StackLayout
+                                       {
+                                               Padding = 20,
+                                               Spacing = 10,
+                                               Children =
+                                               {
+                                                       CreateImageSourcePicker("Select Image Source", getter =>
+                                                       {
+                                                               _image.Source = getter();
+                                                               _imageAutosize.Source = getter();
+                                                       }),
+                                                       new StackLayout
+                                                       {
+                                                               Children =
+                                                               {
+                                                                       new Grid
+                                                                       {
+                                                                               Children =
+                                                                               {
+                                                                                       (_image = new Image
+                                                                                       {
+                                                                                               WidthRequest = 200,
+                                                                                               HeightRequest = 200,
+                                                                                               Source = "bank.png"
+                                                                                       }),
+                                                                                       (_loading = new ActivityIndicator
+                                                                                       {
+                                                                                               WidthRequest = 100,
+                                                                                               HeightRequest = 100
+                                                                                       }),
+                                                                               }
+                                                                       },
+                                                                       (_imageAutosize = new Image
+                                                                       {
+                                                                               Source = "bank.png"
+                                                                       }),
+                                                               }
+                                                       }
+                                               }
+                                       }
+                               };
+
+                               _loading.SetBinding(ActivityIndicator.IsRunningProperty, new Binding(Image.IsLoadingProperty.PropertyName));
+                               _loading.SetBinding(ActivityIndicator.IsVisibleProperty, new Binding(Image.IsLoadingProperty.PropertyName));
+                               _loading.BindingContext = _image;
+                       }
+               }
+
+               class ButtonsPage : ContentPage
+               {
+                       Button _buttonWithImageAndText;
+                       Button _buttonWithPositionedImageAndText;
+                       Button _buttonWithImage;
+                       ImageButton _imageButton;
+
+                       public ButtonsPage()
+                       {
+                               Title = "Buttons";
+
+                               Content = new ScrollView
+                               {
+                                       Content = new StackLayout
+                                       {
+                                               Padding = 20,
+                                               Spacing = 10,
+                                               Children =
+                                               {
+                                                       CreateImageSourcePicker("Select Image Source", getter =>
+                                                       {
+                                                               _buttonWithImageAndText.ImageSource = getter();
+                                                               _buttonWithPositionedImageAndText.ImageSource = getter();
+                                                               _buttonWithImage.ImageSource = getter();
+                                                               _imageButton.Source = getter();
+                                                       }),
+                                                       new Label
+                                                       {
+                                                               Text = "The default Button type.",
+                                                               LineBreakMode = LineBreakMode.WordWrap,
+                                                       },
+                                                       (_buttonWithImageAndText = new Button
+                                                       {
+                                                               Text = "Image & Text",
+                                                               ImageSource = "bank.png"
+                                                       }),
+                                                       (_buttonWithPositionedImageAndText = new Button
+                                                       {
+                                                               Text = "Image Above & Text",
+                                                               ContentLayout = new Button.ButtonContentLayout(Button.ButtonContentLayout.ImagePosition.Top, 5),
+                                                               ImageSource = "bank.png"
+                                                       }),
+                                                       (_buttonWithImage = new Button
+                                                       {
+                                                               ImageSource = "bank.png"
+                                                       }),
+                                                       new Button
+                                                       {
+                                                               Text = "Just Text",
+                                                               ImageSource = null
+                                                       },
+                                                       new Label
+                                                       {
+                                                               Text = "The ImageButton type.",
+                                                               LineBreakMode = LineBreakMode.WordWrap,
+                                                       },
+                                                       (_imageButton = new ImageButton
+                                                       {
+                                                               Padding = 10,
+                                                               Source = "bank.png",
+                                                       }),
+                                               }
+                                       }
+                               };
+                       }
+               }
+
+               class SliderPage : ContentPage
+               {
+                       Slider _slider = null;
+
+                       public SliderPage()
+                       {
+                               Title = "Slider";
+
+                               Content = new ScrollView
+                               {
+                                       Content = new StackLayout
+                                       {
+                                               Padding = 20,
+                                               Spacing = 10,
+                                               Children =
+                                               {
+                                                       CreateImageSourcePicker("Select Image Source", getter => _slider.ThumbImageSource = getter()),
+                                                       (_slider = new Slider
+                                                       {
+                                                               Minimum = 0,
+                                                               Maximum = 1,
+                                                               Value = 0.5,
+                                                               HeightRequest = 50
+                                                       }),
+                                               }
+                                       }
+                               };
+                       }
+               }
+       }
+}
index d81b6f3..3e520db 100644 (file)
@@ -22,7 +22,7 @@ namespace Xamarin.Forms.Controls
                        var lst2 = new ListView { ItemTemplate = new DataTemplate(typeof(DemoSwitchCell)), BackgroundColor = Color.Yellow, HeightRequest = 300, RowHeight = 50, ItemsSource = items, };
                        var lst3 = new ListView { ItemTemplate = new DataTemplate(typeof(DemoImageCell)), BackgroundColor = Color.Yellow, HeightRequest = 300, RowHeight = 50, ItemsSource = items, };
 
-                       var bigbUtton = new Button { WidthRequest = 200, HeightRequest = 300, Image = "bank.png" };
+                       var bigbUtton = new Button { WidthRequest = 200, HeightRequest = 300, ImageSource = "bank.png" };
 
                        var picker = new DatePicker();
 
@@ -118,7 +118,7 @@ namespace Xamarin.Forms.Controls
                                                                timePicker,
                                                                bigbUtton,
                                                                new Button { Text = "Click Me", BackgroundColor = Color.Gray },
-                                                               new Button { Image = "bank.png", BackgroundColor = Color.Gray },
+                                                               new Button { ImageSource = "bank.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)),
@@ -182,9 +182,9 @@ namespace Xamarin.Forms.Controls
 
                        var tp = new TabbedPage { BarTextColor = Color.Red, BarBackgroundColor = Color.Yellow };
 
-                       var master = new ContentPage { Icon = "bank.png", BackgroundColor = Color.Red, Title = "Master", Content = lyout };
+                       var master = new ContentPage { IconImageSource = "bank.png", BackgroundColor = Color.Red, Title = "Master", Content = lyout };
 
-                       var detail = new ContentPage { Icon = "bank.png", BackgroundColor = Color.Blue, Title = "Detail", Content = new Label { Text = "This is Detail Page" } };
+                       var detail = new ContentPage { IconImageSource = "bank.png", BackgroundColor = Color.Blue, Title = "Detail", Content = new Label { Text = "This is Detail Page" } };
 
                        tp.Children.Add(master);
                        tp.Children.Add(detail);
@@ -199,7 +199,7 @@ namespace Xamarin.Forms.Controls
                        btnGo.Clicked += (sender, e) =>
                        {
                                tp.CurrentPage.Title = "Tile changed";
-                               tp.CurrentPage.Icon = null;
+                               tp.CurrentPage.IconImageSource = null;
                        };
 
                        btnGo1.Clicked += (sender, e) =>
@@ -288,7 +288,7 @@ namespace Xamarin.Forms.Controls
 
                        };
 
-                       return new ContentPage { Icon = "bank.png", BackgroundColor = _pageID % 2 == 0 ? Color.Blue : Color.Green, Title = label.Text, Content = lyout };
+                       return new ContentPage { IconImageSource = "bank.png", BackgroundColor = _pageID % 2 == 0 ? Color.Blue : Color.Green, Title = label.Text, Content = lyout };
                }
 
                static StackLayout MakeNewStackLayout()
@@ -323,7 +323,7 @@ namespace Xamarin.Forms.Controls
                        return new Button
                        {
                                Text = "Click Me On Mac",
-                               Image = "bank.png",
+                               ImageSource = "bank.png",
                                Font = Font.OfSize("Helvetica", 14),
                                ContentLayout = layout,
                                BackgroundColor = Color.Black,
index a6333e3..381aff7 100644 (file)
@@ -76,7 +76,7 @@ namespace Xamarin.Forms.Controls
                        ItemTemplate = new DataTemplate (() => {
                                var page = new ContentPage();
                                page.SetBinding (TitleProperty, "Title");
-                               page.SetBinding (IconProperty, "Icon");
+                               page.SetBinding (IconImageSourceProperty, "Icon");
 
                                var layout = new StackLayout();
 
index 448d390..1b6dec4 100644 (file)
@@ -197,10 +197,10 @@ namespace Xamarin.Forms.Controls.GalleryPages
                {
                        if (App.Current.MainPage is MasterDetailPage mdp)
                        {
-                               if (String.IsNullOrWhiteSpace(mdp.Master.Icon))
-                                       mdp.Master.Icon = "menuIcon";
+                               if (mdp.Master.IconImageSource == null || mdp.Master.IconImageSource.IsEmpty)
+                                       mdp.Master.IconImageSource = "menuIcon";
                                else
-                                       mdp.Master.Icon = null;
+                                       mdp.Master.IconImageSource = null;
                        }
                }
 
index 926dbc9..3a5c38c 100644 (file)
@@ -5,7 +5,7 @@
                public BaseView()
                {
                        SetBinding(Page.TitleProperty, new Binding(HBaseViewModel.TitlePropertyName));
-                       SetBinding(Page.IconProperty, new Binding(HBaseViewModel.IconPropertyName));
+                       SetBinding(Page.IconImageSourceProperty, new Binding(HBaseViewModel.IconPropertyName));
                }
        }
 
index 53601f9..3f7c33f 100644 (file)
@@ -66,7 +66,7 @@ namespace Xamarin.Forms.Controls
                        };
                        var share = new ToolbarItem
                        {
-                               Icon = "ic_share.png",
+                               IconImageSource = "ic_share.png",
                                Text = "Share",
                                //Command = new Command(() => CrossShare.Current
                                //  .Share("Be sure to read @shanselman's " + item.Title + " " + item.Link))
index df98d49..17e3e06 100644 (file)
@@ -36,6 +36,7 @@
   <ItemGroup>
     <EmbeddedResource Include="BuildNumber.txt" />
     <EmbeddedResource Include="GalleryPages\crimson.jpg" />
+    <EmbeddedResource Include="coffee.png" />
     <PackageReference Include="Newtonsoft.Json" Version="10.0.3" />
     <PackageReference Include="Xam.Plugin.DeviceInfo" Version="3.0.2" />
     <Compile Update="GalleryPages\BindableLayoutGalleryPage.xaml.cs">
index 10eafb4..09b8a46 100644 (file)
@@ -37,7 +37,7 @@ namespace Xamarin.Forms.Core.UITests
                                { BorderElement.BorderColorProperty, Tuple.Create(new[] { "getBackground" }, false) },
                                { Button.CornerRadiusProperty, Tuple.Create(new[] { "getBackground" }, false) },
                                { Button.BorderWidthProperty, Tuple.Create(new[] { "getBackground" }, false) },
-                               { Button.ImageProperty, Tuple.Create(new[] { "getBackground" }, false) },
+                               { Button.ImageSourceProperty, Tuple.Create(new[] { "getBackground" }, false) },
                                { Button.FontProperty, Tuple.Create(new[] { "getTypeface", "isBold" }, false) },
                                { Button.TextProperty, Tuple.Create(new[] { "getText" }, false) },
                                { Button.TextColorProperty, Tuple.Create(new[] { "getCurrentTextColor" }, false) },
index 6536bb1..fa0b078 100644 (file)
@@ -121,12 +121,12 @@ namespace Xamarin.Forms.Core.UnitTests
                        var button = new Button ();
                        button.BindingContext = context;
                        var source = new FileImageSource ();
-                       button.Image = source;
+                       button.ImageSource = source;
                        Assert.AreSame (context, source.BindingContext);
 
                        button = new Button ();
                        source = new FileImageSource ();
-                       button.Image = source;
+                       button.ImageSource = source;
                        button.BindingContext = context;
                        Assert.AreSame (context, source.BindingContext);
                }
@@ -135,7 +135,7 @@ namespace Xamarin.Forms.Core.UnitTests
                public void TestImageSourcePropertiesChangedTriggerResize ()
                {
                        var source = new FileImageSource ();
-                       var button = new Button { Image = source };
+                       var button = new Button { ImageSource = source };
                        bool fired = false;
                        button.MeasureInvalidated += (sender, e) => fired = true;
                        Assert.Null (source.File);
index 5f4027c..f3c40e3 100644 (file)
@@ -115,7 +115,7 @@ namespace Xamarin.Forms.Core.UnitTests
                        new PropertyTestCase<Map, bool> ("HasScrollEnabled", v => v.HasScrollEnabled, (v, o) => v.HasScrollEnabled = o, () => true, false),
                        new PropertyTestCase<Map, bool> ("HasZoomEnabled", v => v.HasZoomEnabled, (v, o) => v.HasZoomEnabled = o, () => true, false),
                        new PropertyTestCase<OpenGLView, bool> ("HasRenderLoop", v => v.HasRenderLoop, (v, o) => v.HasRenderLoop = o, () => false, true),
-                       new PropertyTestCase<Page, string> ("BackgroundImage", v => v.BackgroundImage, (v, o) => v.BackgroundImage = o, () => null, "Foo"),
+                       new PropertyTestCase<Page, ImageSource> ("BackgroundImageSource", v => v.BackgroundImageSource, (v, o) => v.BackgroundImageSource = o, () => null, "Foo"),
                        new PropertyTestCase<Page, Color> ("BackgroundColor", v => v.BackgroundColor, (v, o) => v.BackgroundColor = o, () => default(Color), new Color (0, 1, 0)),
                        new PropertyTestCase<Page, string> ("Title", v => v.Title, (v, o) => v.Title = o, () => null, "Foo"),
                        new PropertyTestCase<Page, bool> ("IsBusy", v => v.IsBusy, (v, o) => v.IsBusy = o, () => false, true),
index 6c75250..3151e98 100644 (file)
@@ -47,8 +47,11 @@ namespace Xamarin.Forms
                public static readonly BindableProperty CornerRadiusProperty = BindableProperty.Create("CornerRadius", typeof(int), typeof(Button), defaultValue: BorderElement.DefaultCornerRadius,
                        propertyChanged: CornerRadiusPropertyChanged);
 
-               public static readonly BindableProperty ImageProperty = ImageElement.FileImageProperty;
+               public static readonly BindableProperty ImageSourceProperty = ImageElement.ImageProperty;
 
+               [Obsolete("ImageProperty is obsolete as of 4.0.0. Please use ImageSourceProperty instead.")]
+               [EditorBrowsable(EditorBrowsableState.Never)]
+               public static readonly BindableProperty ImageProperty = ImageElement.ImageProperty;
 
                public static readonly BindableProperty PaddingProperty = PaddingElement.PaddingProperty;
 
@@ -125,9 +128,17 @@ namespace Xamarin.Forms
                        set { SetValue(FontProperty, value); }
                }
 
-               public FileImageSource Image
+               public ImageSource ImageSource
+               {
+                       get { return (ImageSource)GetValue(ImageSourceProperty); }
+                       set { SetValue(ImageSourceProperty, value); }
+               }
+
+               [Obsolete("Image is obsolete as of 4.0.0. Please use ImageSource instead.")]
+               [EditorBrowsable(EditorBrowsableState.Never)]
+               public ImageSource Image
                {
-                       get { return (FileImageSource)GetValue(ImageProperty); }
+                       get { return GetValue(ImageProperty) as FileImageSource; }
                        set { SetValue(ImageProperty, value); }
                }
 
@@ -219,7 +230,7 @@ namespace Xamarin.Forms
 
                protected override void OnBindingContextChanged()
                {
-                       FileImageSource image = Image;
+                       ImageSource image = ImageSource;
                        if (image != null)
                                SetInheritedBindingContext(image, BindingContext);
 
@@ -242,11 +253,11 @@ namespace Xamarin.Forms
                        InvalidateMeasureInternal(InvalidationTrigger.MeasureChanged);
 
                Aspect IImageElement.Aspect => Aspect.AspectFit;
-               ImageSource IImageElement.Source => Image;
+               ImageSource IImageElement.Source => ImageSource;
                bool IImageElement.IsOpaque => false;
 
 
-               void IImageElement.RaiseImageSourcePropertyChanged() => OnPropertyChanged(ImageProperty.PropertyName);
+               void IImageElement.RaiseImageSourcePropertyChanged() => OnPropertyChanged(ImageSourceProperty.PropertyName);
 
                int IBorderElement.CornerRadiusDefaultValue => (int)CornerRadiusProperty.DefaultValue;
 
index f2f3471..bdf0bcc 100644 (file)
@@ -7,6 +7,8 @@ namespace Xamarin.Forms
        {
                public static readonly BindableProperty FileProperty = BindableProperty.Create("File", typeof(string), typeof(FileImageSource), default(string));
 
+               public override bool IsEmpty => string.IsNullOrEmpty(File);
+
                public string File
                {
                        get { return (string)GetValue(FileProperty); }
index efb4b59..ca19a75 100644 (file)
@@ -21,6 +21,8 @@ namespace Xamarin.Forms
                        );
                }
 
+               public override bool IsEmpty => string.IsNullOrEmpty(Glyph);
+
                public double Size { get => (double)GetValue(SizeProperty); set => SetValue(SizeProperty, value); }
                public static readonly BindableProperty SizeProperty = CreateBindableProperty(nameof(Size), 30d);
 
index 413d61b..d39e09a 100644 (file)
@@ -6,7 +6,7 @@ namespace Xamarin.Forms
        static class ImageElement
        {
 
-               public static readonly BindableProperty FileImageProperty = BindableProperty.Create("Image", typeof(FileImageSource), typeof(IImageElement), default(FileImageSource),
+               public static readonly BindableProperty ImageProperty = BindableProperty.Create("Image", typeof(ImageSource), typeof(IImageElement), default(ImageSource),
        propertyChanging: OnImageSourceChanging, propertyChanged: OnImageSourceChanged);
 
                public static readonly BindableProperty SourceProperty = BindableProperty.Create(nameof(IImageElement.Source), typeof(ImageSource), typeof(IImageElement), default(ImageSource),
index ecee837..bdd83c5 100644 (file)
@@ -20,6 +20,8 @@ namespace Xamarin.Forms
                {
                }
 
+               public virtual bool IsEmpty => false;
+
                protected CancellationTokenSource CancellationTokenSource
                {
                        get { return _cancellationTokenSource; }
similarity index 64%
rename from Xamarin.Forms.Platform.UAP/AsyncValue.cs
rename to Xamarin.Forms.Core/Internals/AsyncValue.cs
index 71037e8..2ef1aee 100644 (file)
@@ -30,27 +30,31 @@ using System.Runtime.CompilerServices;
 using System.Threading;
 using System.Threading.Tasks;
 
-namespace Xamarin.Forms.Platform.UWP
+namespace Xamarin.Forms.Internals
 {
-       internal sealed class AsyncValue<T> : INotifyPropertyChanged
+       [EditorBrowsable(EditorBrowsableState.Never)]
+       public sealed class AsyncValue<T> : INotifyPropertyChanged
        {
                readonly T _defaultValue;
                readonly Task<T> _valueTask;
                bool _isRunning = true;
 
-               public AsyncValue(Task<T> valueTask, T defaultValue)
+               public AsyncValue(Task<T> valueTask, T defaultValue = default(T))
                {
-                       if (valueTask == null)
-                               throw new ArgumentNullException("valueTask");
-
-                       _valueTask = valueTask;
+                       _valueTask = valueTask ?? throw new ArgumentNullException(nameof(valueTask));
                        _defaultValue = defaultValue;
 
                        TaskScheduler scheduler = TaskScheduler.FromCurrentSynchronizationContext();
 
-                       _valueTask.ContinueWith(t => { IsRunning = false; }, scheduler);
+                       if (_valueTask.IsCompleted)
+                               IsRunning = false;
+                       else
+                               _valueTask.ContinueWith(t => IsRunning = false, scheduler);
 
-                       _valueTask.ContinueWith(t => { OnPropertyChanged("Value"); }, CancellationToken.None, TaskContinuationOptions.OnlyOnRanToCompletion, scheduler);
+                       if (_valueTask.Status == TaskStatus.RanToCompletion)
+                               OnPropertyChanged(nameof(Value));
+                       else
+                               _valueTask.ContinueWith(t => OnPropertyChanged(nameof(Value)), CancellationToken.None, TaskContinuationOptions.OnlyOnRanToCompletion, scheduler);
                }
 
                public bool IsRunning
@@ -77,13 +81,18 @@ namespace Xamarin.Forms.Platform.UWP
                        }
                }
 
+               public static AsyncValue<T> Null => new AsyncValue<T>(Task.FromResult<T>(default(T)));
+
                public event PropertyChangedEventHandler PropertyChanged;
 
-               void OnPropertyChanged([CallerMemberName] string propertyName = null)
-               {
-                       PropertyChangedEventHandler handler = PropertyChanged;
-                       if (handler != null)
-                               handler(this, new PropertyChangedEventArgs(propertyName));
-               }
+               void OnPropertyChanged([CallerMemberName] string propertyName = null) =>
+                       PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
+       }
+
+       [EditorBrowsable(EditorBrowsableState.Never)]
+       public static class AsyncValueExtensions
+       {
+               public static AsyncValue<T> AsAsyncValue<T>(this Task<T> valueTask, T defaultValue = default(T)) =>
+                       new AsyncValue<T>(valueTask, defaultValue);
        }
 }
\ No newline at end of file
index aecf36a..73be93f 100644 (file)
@@ -17,7 +17,11 @@ namespace Xamarin.Forms
 
                public static readonly BindableProperty IsDestructiveProperty = BindableProperty.Create(nameof(IsDestructive), typeof(bool), typeof(MenuItem), false);
 
-               public static readonly BindableProperty IconProperty = BindableProperty.Create(nameof(Icon), typeof(FileImageSource), typeof(MenuItem), default(FileImageSource));
+               public static readonly BindableProperty IconImageSourceProperty = BindableProperty.Create(nameof(IconImageSource), typeof(ImageSource), typeof(MenuItem), default(ImageSource));
+
+               [Obsolete("IconProperty is obsolete as of 4.0.0. Please use IconImageSourceProperty instead.")]
+               [EditorBrowsable(EditorBrowsableState.Never)]
+               public static readonly BindableProperty IconProperty = IconImageSourceProperty;
 
                static readonly BindablePropertyKey IsEnabledPropertyKey = BindableProperty.CreateReadOnly(nameof(IsEnabled), typeof(bool), typeof(ToolbarItem), true);
                public static readonly BindableProperty IsEnabledProperty = IsEnabledPropertyKey.BindableProperty;
@@ -40,12 +44,20 @@ namespace Xamarin.Forms
                        set => SetValue(CommandParameterProperty, value);
                }
 
+               [Obsolete("Icon is obsolete as of 4.0.0. Please use IconImageSource instead.")]
+               [EditorBrowsable(EditorBrowsableState.Never)]
                public FileImageSource Icon
                {
-                       get => (FileImageSource)GetValue(IconProperty);
+                       get => GetValue(IconProperty) as FileImageSource ?? default(FileImageSource);
                        set => SetValue(IconProperty, value);
                }
 
+               public ImageSource IconImageSource
+               {
+                       get => (ImageSource)GetValue(IconImageSourceProperty);
+                       set => SetValue(IconImageSourceProperty, value);
+               }
+
                public bool IsDestructive
                {
                        get => (bool)GetValue(IsDestructiveProperty);
index bf53f8e..2f7a040 100644 (file)
@@ -26,7 +26,7 @@ namespace Xamarin.Forms
 
                public static readonly BindableProperty BarTextColorProperty = BarElement.BarTextColorProperty;
 
-               public static readonly BindableProperty TitleIconProperty = BindableProperty.CreateAttached("TitleIcon", typeof(FileImageSource), typeof(NavigationPage), default(FileImageSource));
+               public static readonly BindableProperty TitleIconProperty = BindableProperty.CreateAttached("TitleIcon", typeof(ImageSource), typeof(NavigationPage), default(ImageSource));
 
                public static readonly BindableProperty TitleViewProperty = BindableProperty.CreateAttached("TitleView", typeof(View), typeof(NavigationPage), null, propertyChanging: TitleViewPropertyChanging);
 
@@ -138,9 +138,9 @@ namespace Xamarin.Forms
                        return (bool)page.GetValue(HasNavigationBarProperty);
                }
 
-               public static FileImageSource GetTitleIcon(BindableObject bindable)
+               public static ImageSource GetTitleIcon(BindableObject bindable)
                {
-                       return (FileImageSource)bindable.GetValue(TitleIconProperty);
+                       return (ImageSource)bindable.GetValue(TitleIconProperty);
                }
 
                public static View GetTitleView(BindableObject bindable)
@@ -250,7 +250,7 @@ namespace Xamarin.Forms
                        page.SetValue(HasNavigationBarProperty, value);
                }
 
-               public static void SetTitleIcon(BindableObject bindable, FileImageSource value)
+               public static void SetTitleIcon(BindableObject bindable, ImageSource value)
                {
                        bindable.SetValue(TitleIconProperty, value);
                }
index f6f43dc..5e0b282 100644 (file)
@@ -21,8 +21,12 @@ namespace Xamarin.Forms
                public const string ActionSheetSignalName = "Xamarin.ShowActionSheet";
 
                internal static readonly BindableProperty IgnoresContainerAreaProperty = BindableProperty.Create("IgnoresContainerArea", typeof(bool), typeof(Page), false);
+               
+               public static readonly BindableProperty BackgroundImageSourceProperty = BindableProperty.Create(nameof(BackgroundImageSource), typeof(ImageSource), typeof(Page), default(ImageSource));
 
-               public static readonly BindableProperty BackgroundImageProperty = BindableProperty.Create("BackgroundImage", typeof(string), typeof(Page), default(string));
+               [Obsolete("BackgroundImageProperty is obsolete as of 4.0.0. Please use BackgroundImageSourceProperty instead.")]
+               [EditorBrowsable(EditorBrowsableState.Never)]
+               public static readonly BindableProperty BackgroundImageProperty = BackgroundImageSourceProperty;
 
                public static readonly BindableProperty IsBusyProperty = BindableProperty.Create("IsBusy", typeof(bool), typeof(Page), false, propertyChanged: (bo, o, n) => ((Page)bo).OnPageBusyChanged());
 
@@ -30,7 +34,11 @@ namespace Xamarin.Forms
 
                public static readonly BindableProperty TitleProperty = BindableProperty.Create("Title", typeof(string), typeof(Page), null);
 
-               public static readonly BindableProperty IconProperty = BindableProperty.Create("Icon", typeof(FileImageSource), typeof(Page), default(FileImageSource));
+               public static readonly BindableProperty IconImageSourceProperty = BindableProperty.Create(nameof(IconImageSource), typeof(ImageSource), typeof(Page), default(ImageSource));
+
+               [Obsolete("IconProperty is obsolete as of 4.0.0. Please use IconImageSourceProperty instead.")]
+               [EditorBrowsable(EditorBrowsableState.Never)]
+               public static readonly BindableProperty IconProperty = IconImageSourceProperty;
 
                readonly Lazy<PlatformConfigurationRegistry<Page>> _platformConfigurationRegistry;
 
@@ -54,18 +62,34 @@ namespace Xamarin.Forms
                        _platformConfigurationRegistry = new Lazy<PlatformConfigurationRegistry<Page>>(() => new PlatformConfigurationRegistry<Page>(this));
                }
 
-               public string BackgroundImage
+               [Obsolete("BackgroundImage is obsolete as of 4.0.0. Please use BackgroundImageSource instead.")]
+               [EditorBrowsable(EditorBrowsableState.Never)]
+               public FileImageSource BackgroundImage
                {
-                       get { return (string)GetValue(BackgroundImageProperty); }
+                       get { return GetValue(BackgroundImageProperty) as FileImageSource; }
                        set { SetValue(BackgroundImageProperty, value); }
                }
 
+               public ImageSource BackgroundImageSource
+               {
+                       get { return (ImageSource)GetValue(BackgroundImageSourceProperty); }
+                       set { SetValue(BackgroundImageSourceProperty, value); }
+               }
+
+               [Obsolete("Icon is obsolete as of 4.0.0. Please use IconImageSource instead.")]
+               [EditorBrowsable(EditorBrowsableState.Never)]
                public FileImageSource Icon
                {
-                       get { return (FileImageSource)GetValue(IconProperty); }
+                       get { return GetValue(IconProperty) as FileImageSource; }
                        set { SetValue(IconProperty, value); }
                }
 
+               public ImageSource IconImageSource
+               {
+                       get { return (ImageSource)GetValue(IconImageSourceProperty); }
+                       set { SetValue(IconImageSourceProperty, value); }
+               }
+
                public bool IsBusy
                {
                        get { return (bool)GetValue(IsBusyProperty); }
index 893eb97..a10b5da 100644 (file)
@@ -9,7 +9,7 @@ namespace Xamarin.Forms.PlatformConfiguration.WindowsSpecific
        public static class TabbedPage
        {
                public static readonly BindableProperty HeaderIconsEnabledProperty =
-                       BindableProperty.Create(nameof(HeaderIconsEnabledProperty), typeof(bool), typeof(TabbedPage), false);
+                       BindableProperty.Create(nameof(HeaderIconsEnabledProperty), typeof(bool), typeof(TabbedPage), true);
 
                public static readonly BindableProperty HeaderIconsSizeProperty =
                        BindableProperty.Create(nameof(HeaderIconsSizeProperty), typeof(Forms.Size), typeof(TabbedPage), new Forms.Size(16, 16));
index 4ce77aa..5119867 100644 (file)
@@ -44,7 +44,7 @@ using Xamarin.Forms.StyleSheets;
 [assembly: XmlnsPrefix("http://xamarin.com/schemas/2014/forms/design", "d")]
 
 [assembly: StyleProperty("background-color", typeof(VisualElement), nameof(VisualElement.BackgroundColorProperty))]
-[assembly: StyleProperty("background-image", typeof(Page), nameof(Page.BackgroundImageProperty))]
+[assembly: StyleProperty("background-image", typeof(Page), nameof(Page.BackgroundImageSourceProperty))]
 [assembly: StyleProperty("border-color", typeof(IBorderElement), nameof(BorderElement.BorderColorProperty))]
 [assembly: StyleProperty("border-radius", typeof(ICornerElement), nameof(CornerElement.CornerRadiusProperty))]
 [assembly: StyleProperty("border-radius", typeof(IBorderElement), nameof(BorderElement.CornerRadiusProperty))]
index fa700e9..0ef7ae2 100644 (file)
@@ -47,7 +47,11 @@ namespace Xamarin.Forms
 
                public static readonly BindableProperty ThumbColorProperty = BindableProperty.Create(nameof(ThumbColor), typeof(Color), typeof(Slider), Color.Default);
 
-               public static readonly BindableProperty ThumbImageProperty = BindableProperty.Create(nameof(ThumbImage), typeof(FileImageSource), typeof(Slider), default(FileImageSource));
+               public static readonly BindableProperty ThumbImageSourceProperty = BindableProperty.Create(nameof(ThumbImageSource), typeof(ImageSource), typeof(Slider), default(ImageSource));
+
+               [Obsolete("ThumbImageProperty is obsolete as of 4.0.0. Please use ThumbImageSourceProperty instead.")]
+               [EditorBrowsable(EditorBrowsableState.Never)]
+               public static readonly BindableProperty ThumbImageProperty = ThumbImageSourceProperty;
 
                public static readonly BindableProperty DragStartedCommandProperty = BindableProperty.Create(nameof(DragStartedCommand), typeof(ICommand), typeof(Slider), default(ICommand));
 
@@ -96,9 +100,17 @@ namespace Xamarin.Forms
                        set { SetValue(ThumbColorProperty, value); }
                }
 
+               public ImageSource ThumbImageSource
+               {
+                       get { return (ImageSource)GetValue(ThumbImageSourceProperty); }
+                       set { SetValue(ThumbImageSourceProperty, value); }
+               }
+
+               [Obsolete("ThumbImage is obsolete as of 4.0.0. Please use ThumbImageSource instead.")]
+               [EditorBrowsable(EditorBrowsableState.Never)]
                public FileImageSource ThumbImage
                {
-                       get { return (FileImageSource)GetValue(ThumbImageProperty); }
+                       get { return GetValue(ThumbImageProperty) as FileImageSource; }
                        set { SetValue(ThumbImageProperty, value); }
                }
 
index 2da4da2..c4f9322 100644 (file)
@@ -45,20 +45,19 @@ namespace Xamarin.Forms
                                return;
                        }
 
-                       if (width == _layoutInformation.Constraint.Width && height == _layoutInformation.Constraint.Height)
+                       LayoutInformation layoutInformationCopy = _layoutInformation;
+                       if (width == layoutInformationCopy.Constraint.Width && height == layoutInformationCopy.Constraint.Height)
                        {
                                StackOrientation orientation = Orientation;
 
-                               AlignOffAxis(_layoutInformation, orientation, width, height);
-                               ProcessExpanders(_layoutInformation, orientation, x, y, width, height);
+                               AlignOffAxis(layoutInformationCopy, orientation, width, height);
+                               ProcessExpanders(layoutInformationCopy, orientation, x, y, width, height);
                        }
                        else
                        {
-                               CalculateLayout(_layoutInformation, x, y, width, height, true);
+                               CalculateLayout(layoutInformationCopy, x, y, width, height, true);
                        }
 
-                       LayoutInformation layoutInformationCopy = _layoutInformation;
-
                        for (var i = 0; i < LogicalChildrenInternal.Count; i++)
                        {
                                var child = (View)LogicalChildrenInternal[i];
index 0692674..2f1969f 100644 (file)
@@ -10,6 +10,8 @@ namespace Xamarin.Forms
                public static readonly BindableProperty StreamProperty = BindableProperty.Create("Stream", typeof(Func<CancellationToken, Task<Stream>>), typeof(StreamImageSource),
                        default(Func<CancellationToken, Task<Stream>>));
 
+               public override bool IsEmpty => Stream == null;
+
                public virtual Func<CancellationToken, Task<Stream>> Stream
                {
                        get { return (Func<CancellationToken, Task<Stream>>)GetValue(StreamProperty); }
index d609b83..a2355ac 100644 (file)
@@ -23,7 +23,7 @@ namespace Xamarin.Forms
                                throw new ArgumentNullException("activated");
 
                        Text = name;
-                       Icon = icon;
+                       IconImageSource = icon;
                        Clicked += (s, e) => activated();
                        Order = order;
                        Priority = priority;
index d163bf5..cb073ef 100644 (file)
@@ -31,6 +31,8 @@ namespace Xamarin.Forms
                                Store.CreateDirectoryAsync(CacheName).Wait();
                }
 
+               public override bool IsEmpty => Uri == null;
+
                public TimeSpan CacheValidity
                {
                        get { return _cacheValidity; }
index ba17aca..7f8e954 100644 (file)
@@ -326,10 +326,6 @@ namespace Xamarin.Forms.Material.Android
                VisualElement IBorderVisualElementRenderer.Element => Element;
                AView IBorderVisualElementRenderer.View => this;
 
-               // IButtonLayoutRenderer
-               Button IButtonLayoutRenderer.Element => Element;
-               AppCompatButton IButtonLayoutRenderer.View => this;
-
                // IVisualElementRenderer
                VisualElement IVisualElementRenderer.Element => Element;
                VisualElementTracker IVisualElementRenderer.Tracker => _tracker;
@@ -362,6 +358,9 @@ namespace Xamarin.Forms.Material.Android
 
                // ITabStop
                AView ITabStop.TabStop => this;
+
+               // IButtonLayoutRenderer
+               AppCompatButton IButtonLayoutRenderer.View => this;
        }
 }
 #endif
index c76a144..0559b79 100644 (file)
@@ -6,6 +6,7 @@ using Android.Support.V7.Widget;
 using Android.Util;
 using Android.Views;
 using Xamarin.Forms.Platform.Android.FastRenderers;
+using Xamarin.Forms.Internals;
 using Xamarin.Forms.PlatformConfiguration.AndroidSpecific;
 using AColor = Android.Graphics.Color;
 using AView = Android.Views.View;
@@ -201,12 +202,6 @@ namespace Xamarin.Forms.Platform.Android.AppCompat
                        remove => ((IVisualElementRenderer)this).ElementChanged -= value;
                }
 
-               Button IButtonLayoutRenderer.Element => Element;
                AppCompatButton IButtonLayoutRenderer.View => Control;
-               event EventHandler<VisualElementChangedEventArgs> IButtonLayoutRenderer.ElementChanged
-               {
-                       add => ((IVisualElementRenderer)this).ElementChanged += value;
-                       remove => ((IVisualElementRenderer)this).ElementChanged -= value;
-               }
        }
 }
index 45b3764..2aeb8eb 100644 (file)
@@ -327,7 +327,7 @@ namespace Xamarin.Forms.Platform.Android.AppCompat
                                Presented = Element.IsPresented;
                                _isPresentingFromCore = false;
                        }
-                       else if (e.PropertyName == Page.BackgroundImageProperty.PropertyName)
+                       else if (e.PropertyName == Page.BackgroundImageSourceProperty.PropertyName)
                                UpdateBackgroundImage(Element);
                        else if (e.PropertyName == VisualElement.BackgroundColorProperty.PropertyName)
                                UpdateBackgroundColor(Element);
@@ -379,9 +379,11 @@ namespace Xamarin.Forms.Platform.Android.AppCompat
 
                void UpdateBackgroundImage(Page view)
                {
-                       string backgroundImage = view.BackgroundImage;
-                       if (!string.IsNullOrEmpty(backgroundImage))
-                               this.SetBackground(Context.GetDrawable(backgroundImage));
+                       _ = this.ApplyDrawableAsync(view, Page.BackgroundImageSourceProperty, Context, drawable =>
+                       {
+                               if (drawable != null)
+                                       this.SetBackground(drawable);
+                       });
                }
 
                void UpdateDetail()
index 18b18b4..961982d 100644 (file)
@@ -544,7 +544,7 @@ namespace Xamarin.Forms.Platform.Android.AppCompat
 
                protected virtual void OnToolbarItemPropertyChanged(object sender, PropertyChangedEventArgs e)
                {
-                       if (e.PropertyName == MenuItem.IsEnabledProperty.PropertyName || e.PropertyName == MenuItem.TextProperty.PropertyName || e.PropertyName == MenuItem.IconProperty.PropertyName)
+                       if (e.PropertyName == MenuItem.IsEnabledProperty.PropertyName || e.PropertyName == MenuItem.TextProperty.PropertyName || e.PropertyName == MenuItem.IconImageSourceProperty.PropertyName)
                                UpdateMenu();
                }
 
@@ -915,10 +915,8 @@ namespace Xamarin.Forms.Platform.Android.AppCompat
 
                protected virtual void UpdateMenuItemIcon(Context context, IMenuItem menuItem, ToolbarItem toolBarItem)
                {
-                       FileImageSource icon = toolBarItem.Icon;
-                       if (!string.IsNullOrEmpty(icon))
+                       _ = this.ApplyDrawableAsync(toolBarItem, ToolbarItem.IconImageSourceProperty, Context, iconDrawable =>
                        {
-                               Drawable iconDrawable = context.GetFormsDrawable(icon);
                                if (iconDrawable != null)
                                {
                                        if (!menuItem.IsEnabled)
@@ -927,9 +925,8 @@ namespace Xamarin.Forms.Platform.Android.AppCompat
                                        }
 
                                        menuItem.SetIcon(iconDrawable);
-                                       iconDrawable.Dispose();
                                }
-                       }
+                       });
                }
 
                void UpdateToolbar()
@@ -1014,9 +1011,9 @@ namespace Xamarin.Forms.Platform.Android.AppCompat
                void UpdateTitleIcon()
                {
                        Page currentPage = Element.CurrentPage;
-                       var source = NavigationPage.GetTitleIcon(currentPage);
+                       ImageSource source = NavigationPage.GetTitleIcon(currentPage);
 
-                       if (source == null)
+                       if (source == null || source.IsEmpty)
                        {
                                _toolbar.RemoveView(_titleIconView);
                                _titleIconView?.Dispose();
@@ -1031,41 +1028,15 @@ namespace Xamarin.Forms.Platform.Android.AppCompat
                                _toolbar.AddView(_titleIconView, 0);
                        }
 
-                       UpdateBitmap(source, _imageSource);
-                       _imageSource = source;
-               }
-
-               async void UpdateBitmap(ImageSource source, ImageSource previousSource = null)
-               {
-                       if (Equals(source, previousSource))
-                               return;
-
-                       _titleIconView.SetImageResource(global::Android.Resource.Color.Transparent);
-
-                       Bitmap bitmap = null;
-                       IImageSourceHandler handler;
-
-                       if (source != null && (handler = Registrar.Registered.GetHandlerForObject<IImageSourceHandler>(source)) != null)
+                       if (_imageSource != source)
                        {
-                               try
+                               _imageSource = source;
+                               _titleIconView.SetImageResource(global::Android.Resource.Color.Transparent);
+                               _ = this.ApplyDrawableAsync(currentPage, NavigationPage.TitleIconProperty, Context, drawable =>
                                {
-                                       bitmap = await handler.LoadImageAsync(source, Context);
-                               }
-                               catch (TaskCanceledException)
-                               {
-                               }
-                               catch (IOException ex)
-                               {
-                                       Internals.Log.Warning("Xamarin.Forms.Platform.Android.AppCompat.NavigationPageRenderer", "Error updating bitmap: {0}", ex);
-                               }
+                                       _titleIconView.SetImageDrawable(drawable);
+                               });
                        }
-
-                       if (bitmap == null && source is FileImageSource)
-                               _titleIconView.SetImageResource(ResourceManager.GetDrawableByName(((FileImageSource)source).File));
-                       else
-                               _titleIconView.SetImageBitmap(bitmap);
-
-                       bitmap?.Dispose();
                }
 
                void UpdateTitleView()
index 5c7890c..d844500 100644 (file)
@@ -520,21 +520,25 @@ namespace Xamarin.Forms.Platform.Android.AppCompat
                                        tab.SetText(page.Title);
                                }
                        }
-                       else if (e.PropertyName == Page.IconProperty.PropertyName)
+                       else if (e.PropertyName == Page.IconImageSourceProperty.PropertyName)
                        {
                                var page = (Page)sender;
                                var index = Element.Children.IndexOf(page);
-                               FileImageSource icon = page.Icon;
-
                                if (IsBottomTabPlacement)
                                {
                                        var menuItem = _bottomNavigationView.Menu.GetItem(index);
-                                       menuItem.SetIcon(GetIconDrawable(icon));
+                                       _ = this.ApplyDrawableAsync(page, Page.IconImageSourceProperty, Context, icon =>
+                                       {
+                                               menuItem.SetIcon(icon);
+                                       });
                                }
                                else
                                {
                                        TabLayout.Tab tab = _tabLayout.GetTabAt(index);
-                                       SetTabIcon(tab, icon);
+                                       _ = this.ApplyDrawableAsync(page, Page.IconImageSourceProperty, Context, icon =>
+                                       {
+                                               SetTabIcon(tab, icon);
+                                       });
                                }
                        }
                }
@@ -655,12 +659,11 @@ namespace Xamarin.Forms.Platform.Android.AppCompat
                        for (var i = 0; i < Element.Children.Count; i++)
                        {
                                Page child = Element.Children[i];
-                               FileImageSource icon = child.Icon;
-                               if (string.IsNullOrEmpty(icon))
-                                       continue;
-
                                var menuItem = bottomNavigationView.Menu.GetItem(i);
-                               menuItem.SetIcon(GetIconDrawable(icon));
+                               _ = this.ApplyDrawableAsync(child, Page.IconImageSourceProperty, Context, icon =>
+                               {
+                                       menuItem.SetIcon(icon);
+                               });
                        }
                }
 
@@ -677,22 +680,18 @@ namespace Xamarin.Forms.Platform.Android.AppCompat
                        for (var i = 0; i < Element.Children.Count; i++)
                        {
                                Page child = Element.Children[i];
-                               FileImageSource icon = child.Icon;
-                               if (string.IsNullOrEmpty(icon))
-                                       continue;
-
                                TabLayout.Tab tab = tabs.GetTabAt(i);
-                               SetTabIcon(tab, icon);
+                               _ = this.ApplyDrawableAsync(child, Page.IconImageSourceProperty, Context, icon =>
+                               {
+                                       SetTabIcon(tab, icon);
+                               });
                        }
                }
 
-               protected virtual Drawable GetIconDrawable(FileImageSource icon) =>
-                       Context.GetDrawable(icon);
-
-               protected virtual void SetTabIcon(TabLayout.Tab tab, FileImageSource icon)
+               void SetTabIcon(TabLayout.Tab tab, Drawable icon)
                {
-                       tab.SetIcon(GetIconDrawable(icon));
-                       this.SetIconColorFilter(tab);
+                       tab.SetIcon(icon);
+                       SetIconColorFilter(tab);
                }
 
                void UpdateBarBackgroundColor()
index be66f84..fea6d96 100644 (file)
@@ -35,7 +35,8 @@ namespace Xamarin.Forms.Platform.Android
                bool _borderAdjustsPadding;
                bool _maintainLegacyMeasurements;
 
-               public ButtonLayoutManager(IButtonLayoutRenderer renderer) : this(renderer, false, false, false, true)
+               public ButtonLayoutManager(IButtonLayoutRenderer renderer)
+                       : this(renderer, false, false, false, true)
                {
                }
 
@@ -89,19 +90,18 @@ namespace Xamarin.Forms.Platform.Android
 
                        Drawable drawable = null;
                        Drawable[] drawables = TextViewCompat.GetCompoundDrawablesRelative(view);
-                       if(drawables != null)
+                       if (drawables != null)
                        {
                                foreach (var compoundDrawable in drawables)
                                {
                                        if (compoundDrawable != null)
                                        {
-                                               drawable = compoundDrawable;                                            
+                                               drawable = compoundDrawable;
                                                break;
                                        }
                                }
                        }
 
-
                        if (drawable != null)
                        {
                                int iconWidth = drawable.IntrinsicWidth;
@@ -183,7 +183,7 @@ namespace Xamarin.Forms.Platform.Android
 
                        if (e.PropertyName == Button.PaddingProperty.PropertyName)
                                UpdatePadding();
-                       else if (e.PropertyName == Button.ImageProperty.PropertyName || e.PropertyName == Button.ContentLayoutProperty.PropertyName)
+                       else if (e.PropertyName == Button.ImageSourceProperty.PropertyName || e.PropertyName == Button.ContentLayoutProperty.PropertyName)
                                UpdateImage();
                        else if (e.PropertyName == Button.TextProperty.PropertyName || e.PropertyName == VisualElement.IsVisibleProperty.PropertyName)
                                UpdateTextAndImage();
@@ -257,28 +257,27 @@ namespace Xamarin.Forms.Platform.Android
                        if (view == null)
                                return;
 
-                       FileImageSource elementImage = _element.Image;
-                       string imageFile = elementImage?.File;
+                       ImageSource elementImage = _element.ImageSource;
 
-                       if (elementImage == null || string.IsNullOrEmpty(imageFile))
+                       if (elementImage == null || elementImage.IsEmpty)
                        {
                                view.SetCompoundDrawablesWithIntrinsicBounds(null, null, null, null);
                                return;
                        }
 
-                       using (var image = Context.GetDrawable(imageFile))
-                       {
-                               // 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 (in OnLayout)
-                               // to handle the vertical centering 
-                               var layout = string.IsNullOrEmpty(_element.Text) ? _imageOnlyLayout : _element.ContentLayout;
-
-                               if(_maintainLegacyMeasurements)
-                                       view.CompoundDrawablePadding = (int)layout.Spacing;
-                               else
-                                       view.CompoundDrawablePadding = (int)Context.ToPixels(layout.Spacing);
+                       // 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 (in OnLayout)
+                       // to handle the vertical centering 
+                       var layout = string.IsNullOrEmpty(_element.Text) ? _imageOnlyLayout : _element.ContentLayout;
+
+                       if (_maintainLegacyMeasurements)
+                               view.CompoundDrawablePadding = (int)layout.Spacing;
+                       else
+                               view.CompoundDrawablePadding = (int)Context.ToPixels(layout.Spacing);
 
+                       _renderer.ApplyDrawableAsync(Button.ImageSourceProperty, Context, image =>
+                       {
                                switch (layout.Position)
                                {
                                        case Button.ButtonContentLayout.ImagePosition.Top:
@@ -295,7 +294,12 @@ namespace Xamarin.Forms.Platform.Android
                                                TextViewCompat.SetCompoundDrawablesRelativeWithIntrinsicBounds(view, image, null, null, null);
                                                break;
                                }
-                       }
+
+                               // Invalidating here causes a crazy amount of increased measure invalidations
+                               // when I tested with Issue4484 it caused about 800 calls to invalidate measure vs the 8 without this
+                               // I'm pretty sure it gets into a layout / invalidation loop where these are invalidating mid layout                            
+                               //_element?.InvalidateMeasureNonVirtual(InvalidationTrigger.MeasureChanged);
+                       });
                }
        }
 }
index 48fffb3..6c786d4 100644 (file)
@@ -193,13 +193,12 @@ namespace Xamarin.Forms.Platform.Android
                                MenuItem action = ActionModeContext.ContextActions[i];
 
                                IMenuItem item = menu.Add(global::Android.Views.Menu.None, i,global::Android.Views.Menu.None, action.Text);
-                               var icon = action.Icon;
-                               if (icon != null)
+
+                               _ = _context.ApplyDrawableAsync(action, MenuItem.IconImageSourceProperty, iconDrawable =>
                                {
-                                       Drawable iconDrawable = _context.GetFormsDrawable(icon);
                                        if (iconDrawable != null)
                                                item.SetIcon(iconDrawable);
-                               }
+                               });
 
                                action.PropertyChanged += changed;
                                action.PropertyChanging += changing;
index 95bb538..d6eaeff 100644 (file)
@@ -1,7 +1,4 @@
-using System;
-using System.Threading.Tasks;
-using Android.Graphics;
-using Android.Graphics.Drawables;
+using System.Threading.Tasks;
 using AImageView = Android.Widget.ImageView;
 
 namespace Xamarin.Forms.Platform.Android
@@ -14,7 +11,6 @@ namespace Xamarin.Forms.Platform.Android
                public static Task UpdateBitmap(this AImageView imageView, ImageSource newImageSource, ImageSource previousImageSourc) =>
                        imageView.UpdateBitmap(null, null, newImageSource, previousImageSourc);
 
-               // TODO hartez 2017/04/07 09:33:03 Review this again, not sure it's handling the transition from previousImage to 'null' newImage correctly
                static async Task UpdateBitmap(
                        this AImageView imageView,
                        IImageElement newView,
@@ -38,9 +34,6 @@ namespace Xamarin.Forms.Platform.Android
                        (imageView as IImageRendererController)?.SkipInvalidate();
                        imageView.SetImageResource(global::Android.Resource.Color.Transparent);
 
-                       bool setByImageViewHandler = false;
-                       Bitmap bitmap = null;
-
                        try
                        {
                                if (newImageSource != null)
@@ -49,38 +42,27 @@ namespace Xamarin.Forms.Platform.Android
                                        if (imageViewHandler != null)
                                        {
                                                await imageViewHandler.LoadImageAsync(newImageSource, imageView);
-                                               setByImageViewHandler = true;
                                        }
                                        else
                                        {
-                                               var imageSourceHandler = Internals.Registrar.Registered.GetHandlerForObject<IImageSourceHandler>(newImageSource);
-                                               bitmap = await imageSourceHandler.LoadImageAsync(newImageSource, imageView.Context);
+                                               using (var drawable = await imageView.Context.GetFormsDrawableAsync(newImageSource))
+                                               {
+                                                       // only set the image if we are still on the same one
+                                                       if (!imageView.IsDisposed() && Equals(newView?.Source, newImageSource))
+                                                               imageView.SetImageDrawable(drawable);
+                                               }
                                        }
                                }
                        }
-                       catch (TaskCanceledException)
-                       {
-                               imageController?.SetIsLoading(false);
-                       }
-
-                       // Check if the source on the new image has changed since the image was loaded
-                       if (newView != null && !Equals(newView?.Source, newImageSource))
+                       finally
                        {
-                               bitmap?.Dispose();
-                               return;
-                       }
-
-                       if (!setByImageViewHandler && !imageView.IsDisposed())
-                       {
-                               if (bitmap == null && newImageSource is FileImageSource)
-                                       imageView.SetImageResource(ResourceManager.GetDrawableByName(((FileImageSource)newImageSource).File));
-                               else
-                                       imageView.SetImageBitmap(bitmap);
+                               // only mark as finished if we are still working on the same image
+                               if (Equals(newView?.Source, newImageSource))
+                               {
+                                       imageController?.SetIsLoading(false);
+                                       imageController?.NativeSizeChanged();
+                               }
                        }
-
-                       bitmap?.Dispose();
-                       imageController?.SetIsLoading(false);
-                       imageController?.NativeSizeChanged();
                }
        }
 }
index 2d5da5b..aefa185 100644 (file)
@@ -19,8 +19,9 @@ namespace Xamarin.Forms.Platform.Android.FastRenderers
                                return;
 
                        var automationIdParent = s_defaultDrawerId;
-                       if (!string.IsNullOrEmpty(page.Master?.Icon))
-                               automationIdParent = page.Master.Icon.AutomationId;
+                       var icon = page.Master?.IconImageSource;
+                       if (icon != null && !icon.IsEmpty)
+                               automationIdParent = page.Master.IconImageSource.AutomationId;
                        else if (!string.IsNullOrEmpty(page.AutomationId))
                                automationIdParent = page.AutomationId;
 
index d2b8b20..4e9a4b3 100644 (file)
@@ -29,7 +29,7 @@ namespace Xamarin.Forms.Platform.Android.FastRenderers
                BorderBackgroundManager _backgroundTracker;
                ButtonLayoutManager _buttonLayoutManager;
                IPlatformElementConfiguration<PlatformConfiguration.Android, Button> _platformElementConfiguration;
-               private Button _button;
+               Button _button;
 
                public event EventHandler<VisualElementChangedEventArgs> ElementChanged;
                public event EventHandler<PropertyChangedEventArgs> ElementPropertyChanged;
@@ -345,12 +345,6 @@ namespace Xamarin.Forms.Platform.Android.FastRenderers
                        return _platformElementConfiguration;
                }
 
-               Button IButtonLayoutRenderer.Element => Button;
                AppCompatButton IButtonLayoutRenderer.View => this;
-               event EventHandler<VisualElementChangedEventArgs> IButtonLayoutRenderer.ElementChanged
-               {
-                       add => ((IVisualElementRenderer)this).ElementChanged += value;
-                       remove => ((IVisualElementRenderer)this).ElementChanged -= value;
-               }
        }
 }
index a2bb807..642f6b0 100644 (file)
@@ -61,7 +61,7 @@ namespace Xamarin.Forms.Platform.Android.FastRenderers
                        var imageController = (IImageController)renderer.Element;
 
                        if (e.PropertyName == Image.SourceProperty.PropertyName ||
-                               e.PropertyName == Button.ImageProperty.PropertyName)
+                               e.PropertyName == Button.ImageSourceProperty.PropertyName)
                        {
                                try
                                {
index 85328e8..c47613f 100644 (file)
@@ -1,12 +1,9 @@
-using System;
-using Android.Support.V7.Widget;
+using Android.Support.V7.Widget;
 
 namespace Xamarin.Forms.Platform.Android
 {
-       public interface IButtonLayoutRenderer
+       public interface IButtonLayoutRenderer : IVisualElementRenderer
        {
-               AppCompatButton View { get; }
-               Button Element { get; }
-               event EventHandler<VisualElementChangedEventArgs> ElementChanged;
+               new AppCompatButton View { get; }
        }
-}
\ No newline at end of file
+}
index fc35642..020ad63 100644 (file)
@@ -423,13 +423,11 @@ namespace Xamarin.Forms.Platform.Android
                                else
                                {
                                        IMenuItem menuItem = menu.Add(item.Text);
-                                       var icon = item.Icon;
-                                       if (!string.IsNullOrEmpty(icon))
+                                       _ = _context.ApplyDrawableAsync(item, MenuItem.IconImageSourceProperty, iconDrawable =>
                                        {
-                                               Drawable iconDrawable = _context.GetFormsDrawable(icon);
                                                if (iconDrawable != null)
                                                        menuItem.SetIcon(iconDrawable);
-                                       }
+                                       });
                                        menuItem.SetEnabled(controller.IsEnabled);
                                        menuItem.SetShowAsAction(ShowAsAction.Always);
                                        menuItem.SetOnMenuItemClickListener(new GenericMenuClickListener(controller.Activate));
@@ -574,7 +572,7 @@ namespace Xamarin.Forms.Platform.Android
                                ClearMasterDetailToggle();
                                return;
                        }
-                       if (!CurrentMasterDetailPage.ShouldShowToolbarButton() || string.IsNullOrEmpty(CurrentMasterDetailPage.Master.Icon) ||
+                       if (!CurrentMasterDetailPage.ShouldShowToolbarButton() || CurrentMasterDetailPage.Master.IconImageSource.IsEmpty ||
                                (MasterDetailPageController.ShouldShowSplitMode && CurrentMasterDetailPage.IsPresented))
                        {
                                //clear out existing icon;
@@ -775,7 +773,6 @@ namespace Xamarin.Forms.Platform.Android
 
                void GetNewMasterDetailToggle()
                {
-                       int icon = ResourceManager.GetDrawableByName(CurrentMasterDetailPage.Master.Icon);
                        var drawer = GetRenderer(CurrentMasterDetailPage) as MasterDetailRenderer;
                        if (drawer == null)
                                return;
@@ -785,6 +782,13 @@ namespace Xamarin.Forms.Platform.Android
                                return;
                        }
 
+                       // TODO: this must be changed to support the other image source types
+                       var fileImageSource = CurrentMasterDetailPage.Master.IconImageSource as FileImageSource;
+                       if (fileImageSource == null)
+                                       throw new InvalidOperationException("Icon property must be a FileImageSource on Master page");
+
+                       int icon = ResourceManager.GetDrawableByName(fileImageSource);
+
                        FastRenderers.AutomationPropertiesProvider.GetDrawerAccessibilityResources(_activity, CurrentMasterDetailPage, out int resourceIdOpen, out int resourceIdClose);
 #pragma warning disable 618 // Eventually we will need to determine how to handle the v7 ActionBarDrawerToggle for AppCompat
                        MasterDetailPageToggle = new ActionBarDrawerToggle(_activity, drawer, icon,
@@ -817,7 +821,7 @@ namespace Xamarin.Forms.Platform.Android
                                _activity.InvalidateOptionsMenu();
                        else if (e.PropertyName == MenuItem.TextProperty.PropertyName)
                                _activity.InvalidateOptionsMenu();
-                       else if (e.PropertyName == MenuItem.IconProperty.PropertyName)
+                       else if (e.PropertyName == MenuItem.IconImageSourceProperty.PropertyName)
                                _activity.InvalidateOptionsMenu();
                }
 
@@ -860,7 +864,7 @@ namespace Xamarin.Forms.Platform.Android
                                modalRenderer = CreateRenderer(modal, _context);
                                SetRenderer(modal, modalRenderer);
 
-                               if (modal.BackgroundColor == Color.Default && modal.BackgroundImage == null)
+                               if (modal.BackgroundColor == Color.Default && modal.BackgroundImageSource == null)
                                        modalRenderer.View.SetWindowBackground();
                        }
                        modalRenderer.Element.Layout(new Rectangle(0, 0, _context.FromPixels(_renderer.Width), _context.FromPixels(_renderer.Height)));
@@ -1073,22 +1077,15 @@ namespace Xamarin.Forms.Platform.Android
                        if (ShouldShowActionBarTitleArea())
                        {
                                actionBar.Title = view.Title;
-                               FileImageSource titleIcon = NavigationPage.GetTitleIcon(view);
-                               if (!string.IsNullOrWhiteSpace(titleIcon))
-                               {
-                                       var iconBitmap = new BitmapDrawable(_context.Resources, ResourceManager.GetBitmap(_context.Resources, titleIcon));
-                                       if (iconBitmap != null && iconBitmap.Bitmap != null)
-                                               actionBar.SetLogo(iconBitmap);
-
-                                       useLogo = true;
-                                       showHome = true;
-                                       showTitle = true;
-                               }
-                               else
+                               _ = _context.ApplyDrawableAsync(view, NavigationPage.TitleIconProperty, icon =>
                                {
-                                       showHome = true;
-                                       showTitle = true;
-                               }
+                                       if (icon != null)
+                                               actionBar.SetLogo(icon);
+                               });
+                               var titleIcon = NavigationPage.GetTitleIcon(view);
+                               useLogo = titleIcon != null && titleIcon.IsEmpty;
+                               showHome = true;
+                               showTitle = true;
                        }
 
                        ActionBarDisplayOptions options = 0;
index 71f04a6..8e752ea 100644 (file)
@@ -3,6 +3,7 @@ using System.ComponentModel;
 using Android.Content;
 using Android.Graphics;
 using Android.Util;
+using Xamarin.Forms.Internals;
 using Xamarin.Forms.PlatformConfiguration.AndroidSpecific;
 using static System.String;
 using AButton = Android.Widget.Button;
@@ -39,6 +40,7 @@ namespace Xamarin.Forms.Platform.Android
                        AutoPackage = false;
                        _visualElementRenderer = this;
                        _backgroundTracker = new BorderBackgroundManager(this);
+                       
                }
 
                AButton NativeButton
@@ -136,7 +138,7 @@ namespace Xamarin.Forms.Platform.Android
                                UpdateEnabled();
                        else if (e.PropertyName == Button.FontProperty.PropertyName)
                                UpdateFont();
-                       else if (e.PropertyName == Button.ImageProperty.PropertyName)
+                       else if (e.PropertyName == Button.ImageSourceProperty.PropertyName)
                                UpdateBitmap();
                        else if (e.PropertyName == VisualElement.IsVisibleProperty.PropertyName)
                                UpdateText();
@@ -167,18 +169,15 @@ namespace Xamarin.Forms.Platform.Android
 
                void UpdateBitmap()
                {
-                       var elementImage = Element.Image;
-                       var imageFile = elementImage?.File;
+                       var elementImage = Element.ImageSource;
                        _imageHeight = -1;
 
-                       if (elementImage == null || IsNullOrEmpty(imageFile))
+                       if (elementImage == null || elementImage.IsEmpty)
                        {
                                Control.SetCompoundDrawablesWithIntrinsicBounds(null, null, null, null);
                                return;
                        }
 
-                       var image = Context.GetDrawable(imageFile);
-
                        if (IsNullOrEmpty(Element.Text))
                        {
                                // No text, so no need for relative position; just center the image
@@ -186,39 +185,51 @@ namespace Xamarin.Forms.Platform.Android
                                // (which handles the horizontal centering) and some tricksy padding (in OnLayout)
                                // to handle the vertical centering 
 
-                               // Clear any previous padding and set the image as top/center
-                               UpdateContentEdge();
-                               Control.SetCompoundDrawablesWithIntrinsicBounds(null, image, null, null);
+                               this.ApplyDrawableAsync(Button.ImageSourceProperty, Context, image =>
+                               {
+                                       // Clear any previous padding and set the image as top/center
+                                       UpdateContentEdge();
+                                       Control.SetCompoundDrawablesWithIntrinsicBounds(null, image, null, null);
 
-                               // Keep track of the image height so we can use it in OnLayout
-                               _imageHeight = image?.IntrinsicHeight ?? -1;
+                                       // Keep track of the image height so we can use it in OnLayout
+                                       _imageHeight = image?.IntrinsicHeight ?? -1;
 
-                               image?.Dispose();
+                                       // Invalidating here causes a crazy amount of increased measure invalidations
+                                       // when I tested with Issue4484 it caused about 800 calls to invalidate measure vs the 8 without this
+                                       // I'm pretty sure it gets into a layout / invalidation loop where these are invalidating mid layout                            
+                                       //Element?.InvalidateMeasureNonVirtual(InvalidationTrigger.MeasureChanged);
+                               });
                                return;
                        }
 
-                       var layout = Element.ContentLayout;
+                       this.ApplyDrawableAsync(Button.ImageSourceProperty, Context, image =>
+                       {
+                               var layout = Element.ContentLayout;
 
-                       Control.CompoundDrawablePadding = (int)layout.Spacing;
+                               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;
-                       }
+                               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();
+                               // Invalidating here causes a crazy amount of increased measure invalidations
+                               // when I tested with Issue4484 it caused about 800 calls to invalidate measure vs the 8 without this
+                               // I'm pretty sure it gets into a layout / invalidation loop where these are invalidating mid layout                            
+                               //Element?.InvalidateMeasureNonVirtual(InvalidationTrigger.MeasureChanged);
+                       });
                }
 
                void UpdateEnabled()
index 11232cf..0348789 100644 (file)
@@ -277,7 +277,7 @@ namespace Xamarin.Forms.Platform.Android
 
                void HandleMasterPropertyChanged(object sender, PropertyChangedEventArgs e)
                {
-                       if (e.PropertyName == Page.TitleProperty.PropertyName || e.PropertyName == Page.IconProperty.PropertyName)
+                       if (e.PropertyName == Page.TitleProperty.PropertyName || e.PropertyName == Page.IconImageSourceProperty.PropertyName)
                                Platform?.UpdateMasterDetailToggle(true);
                }
 
@@ -299,7 +299,7 @@ namespace Xamarin.Forms.Platform.Android
                        }
                        else if (e.PropertyName == "IsGestureEnabled")
                                SetGestureState();
-                       else if (e.PropertyName == Page.BackgroundImageProperty.PropertyName)
+                       else if (e.PropertyName == Page.BackgroundImageSourceProperty.PropertyName)
                                UpdateBackgroundImage(_page);
                        if (e.PropertyName == VisualElement.BackgroundColorProperty.PropertyName)
                                UpdateBackgroundColor(_page);
@@ -353,8 +353,10 @@ namespace Xamarin.Forms.Platform.Android
 
                void UpdateBackgroundImage(Page view)
                {
-                       if (!string.IsNullOrEmpty(view.BackgroundImage))
-                               this.SetBackground(Context.GetDrawable(view.BackgroundImage));
+                       _ = this.ApplyDrawableAsync(view, Page.BackgroundImageSourceProperty, Context, drawable =>
+                       {
+                               this.SetBackground(drawable);
+                       });
                }
 
                void UpdateDetail()
index bb096a6..5fec150 100644 (file)
@@ -80,7 +80,7 @@ namespace Xamarin.Forms.Platform.Android
                protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
                {
                        base.OnElementPropertyChanged(sender, e);
-                       if (e.PropertyName == Page.BackgroundImageProperty.PropertyName)
+                       if (e.PropertyName == Page.BackgroundImageSourceProperty.PropertyName)
                                UpdateBackground(true);
                        else if (e.PropertyName == VisualElement.BackgroundColorProperty.PropertyName)
                                UpdateBackground(false);
@@ -118,23 +118,29 @@ namespace Xamarin.Forms.Platform.Android
                {
                        Page page = Element;
 
-                       string bkgndImage = page.BackgroundImage;
-                       if (!string.IsNullOrEmpty(bkgndImage))
-                               this.SetBackground(Context.GetDrawable(bkgndImage));
-                       else
+                       _ = this.ApplyDrawableAsync(page, Page.BackgroundImageSourceProperty, Context, drawable =>
                        {
-                               Color bkgndColor = page.BackgroundColor;
-                               bool isDefaultBkgndColor = bkgndColor.IsDefault;
-                               if (page.Parent is BaseShellItem && isDefaultBkgndColor)
+                               if (drawable != null)
                                {
-                                       var color = Forms.IsMarshmallowOrNewer ?
-                                               Context.Resources.GetColor(AColorRes.BackgroundLight, Context.Theme) :
-                                               new AColor(ContextCompat.GetColor(Context, global::Android.Resource.Color.BackgroundLight));
-                                       SetBackgroundColor(color);
+                                       this.SetBackground(drawable);
                                }
-                               else if (!isDefaultBkgndColor || setBkndColorEvenWhenItsDefault)
-                                       SetBackgroundColor(bkgndColor.ToAndroid());
-                       }
+                               else
+                               {
+                                       Color bkgndColor = page.BackgroundColor;
+                                       bool isDefaultBkgndColor = bkgndColor.IsDefault;
+                                       if (page.Parent is BaseShellItem && isDefaultBkgndColor)
+                                       {
+                                               var color = Forms.IsMarshmallowOrNewer ?
+                                                       Context.Resources.GetColor(AColorRes.BackgroundLight, Context.Theme) :
+                                                       new AColor(ContextCompat.GetColor(Context, global::Android.Resource.Color.BackgroundLight));
+                                               SetBackgroundColor(color);
+                                       }
+                                       else if (!isDefaultBkgndColor || setBkndColorEvenWhenItsDefault)
+                                       {
+                                               SetBackgroundColor(bkgndColor.ToAndroid());
+                                       }
+                               }
+                       });
                }
 
                void IOrderedTraversalController.UpdateTraversalOrder()
index 27f3e78..5da045e 100644 (file)
@@ -83,21 +83,29 @@ namespace Xamarin.Forms.Platform.Android
                                foreach (var element in group)
                                {
                                        string title = null;
-                                       ImageSource icon = null;
+                                       BindableObject bindable = null;
+                                       BindableProperty property = null;
                                        if (element is BaseShellItem shellItem)
                                        {
                                                title = shellItem.Title;
-                                               icon = shellItem.FlyoutIcon;
+                                               bindable = shellItem;
+                                               property = BaseShellItem.FlyoutIconProperty;
                                        }
                                        else if (element is MenuItem menuItem)
                                        {
                                                title = menuItem.Text;
-                                               icon = menuItem.Icon;
+                                               bindable = menuItem;
+                                               property = MenuItem.IconImageSourceProperty;
                                        }
 
                                        var item = menu.Add(gid, id++, 0, new Java.Lang.String(title));
-                                       if (icon != null)
-                                               SetMenuItemIcon(item, icon);
+                                       if (bindable != null && property != null)
+                                       {
+                                               _ = _shellContext.ApplyDrawableAsync(bindable, property, drawable =>
+                                               {
+                                                       item.SetIcon(drawable);
+                                               });
+                                       }
                                }
                                gid++;
                        }
@@ -107,12 +115,5 @@ namespace Xamarin.Forms.Platform.Android
                {
                        BuildMenu();
                }
-
-               async void SetMenuItemIcon(IMenuItem menuItem, ImageSource source)
-               {
-                       var drawable = await Context.GetFormsDrawable(source);
-                       menuItem.SetIcon(drawable);
-                       drawable?.Dispose();
-               }
        }
 }
\ No newline at end of file
index e6840f7..dd42c13 100644 (file)
@@ -159,7 +159,11 @@ namespace Xamarin.Forms.Platform.Android
                                        lp.Dispose();
 
                                        image.ImageTintList = ColorStateList.ValueOf(Color.Black.MultiplyAlpha(0.6).ToAndroid());
-                                       SetImage(image, shellContent.Icon);
+                                       ShellContext.ApplyDrawableAsync(shellContent, ShellSection.IconProperty, icon =>
+                                       {
+                                               if (!image.IsDisposed())
+                                                       image.SetImageDrawable(icon);
+                                       });
 
                                        innerLayout.AddView(image);
 
@@ -310,7 +314,11 @@ namespace Xamarin.Forms.Platform.Android
                                {
                                        var menuItem = menu.Add(0, i, 0, title);
                                        menuItems.Add(menuItem);
-                                       loadTasks.Add(SetMenuItemIcon(menuItem, item.Icon));
+                                       loadTasks.Add(ShellContext.ApplyDrawableAsync(item, ShellSection.IconProperty, icon =>
+                                       {
+                                               if (icon != null)
+                                                       menuItem.SetIcon(icon);
+                                       }));
                                        UpdateShellSectionEnabled(item, menuItem);
                                        if (item == ShellSection)
                                        {
@@ -354,20 +362,6 @@ namespace Xamarin.Forms.Platform.Android
                                UpdateTabBarVisibility();
                }
 
-               async void SetImage(ImageView image, ImageSource source)
-               {
-                       image.SetImageDrawable(await Context.GetFormsDrawable(source));
-               }
-
-               async Task SetMenuItemIcon(IMenuItem menuItem, ImageSource source)
-               {
-                       if (source == null)
-                               return;
-                       var drawable = await Context.GetFormsDrawable(source);
-                       menuItem.SetIcon(drawable);
-                       drawable?.Dispose();
-               }
-
                void SetupMenu()
                {
                        using (var menu = _bottomView.Menu)
index 737b5c7..9913eb8 100644 (file)
@@ -155,9 +155,6 @@ namespace Xamarin.Forms.Platform.Android
 
                protected virtual void LoadView(SearchHandler searchHandler)
                {
-                       var searchImage = searchHandler.QueryIcon;
-                       var clearImage = searchHandler.ClearIcon;
-                       var clearPlaceholderImage = searchHandler.ClearPlaceholderIcon;
                        var query = searchHandler.Query;
                        var placeholder = searchHandler.Placeholder;
 
@@ -177,7 +174,7 @@ namespace Xamarin.Forms.Platform.Android
 
                        int padding = (int)context.ToPixels(8);
 
-                       _searchButton = CreateImageButton(context, searchImage, Resource.Drawable.abc_ic_search_api_material, padding, 0);
+                       _searchButton = CreateImageButton(context, searchHandler, SearchHandler.QueryIconProperty, Resource.Drawable.abc_ic_search_api_material, padding, 0);
 
                        lp = new LinearLayout.LayoutParams(0, LP.MatchParent)
                        {
@@ -204,8 +201,8 @@ namespace Xamarin.Forms.Platform.Android
                        // A note on accessibility. The _textBlocks hint is what android defaults to reading in the screen
                        // reader. Therefor we do not need to set something else.
 
-                       _clearButton = CreateImageButton(context, clearImage, Resource.Drawable.abc_ic_clear_material, 0, padding);
-                       _clearPlaceholderButton = CreateImageButton(context, clearPlaceholderImage, -1, 0, padding);
+                       _clearButton = CreateImageButton(context, searchHandler, SearchHandler.ClearIconProperty, Resource.Drawable.abc_ic_clear_material, 0, padding);
+                       _clearPlaceholderButton = CreateImageButton(context, searchHandler, SearchHandler.ClearPlaceholderIconProperty, -1, 0, padding);
 
                        linearLayout.AddView(_searchButton);
                        linearLayout.AddView(_textBlock);
@@ -296,17 +293,27 @@ namespace Xamarin.Forms.Platform.Android
                {
                }
 
-               AImageButton CreateImageButton(Context context, ImageSource image, int defaultImage, int leftMargin, int rightMargin)
+               AImageButton CreateImageButton(Context context, BindableObject bindable, BindableProperty property, int defaultImage, int leftMargin, int rightMargin)
                {
                        var result = new AImageButton(context);
                        result.SetPadding(0, 0, 0, 0);
                        result.Focusable = false;
+                       result.SetScaleType(ImageView.ScaleType.FitCenter);
 
                        string defaultHint = null;
                        string defaultDescription = null;
-                       AutomationPropertiesProvider.SetContentDescription(result, image, ref defaultDescription, ref defaultHint);
+                       if (bindable.GetValue(property) is ImageSource image)
+                               AutomationPropertiesProvider.SetContentDescription(result, image, ref defaultDescription, ref defaultHint);
 
-                       SetImage(result, image, defaultImage);
+                       _shellContext.ApplyDrawableAsync(bindable, property, drawable =>
+                       {
+                               if (drawable != null)
+                                       result.SetImageDrawable(drawable);
+                               else if (defaultImage > 0)
+                                       result.SetImageResource(defaultImage);
+                               else
+                                       result.SetImageDrawable(null);
+                       });
                        var lp = new LinearLayout.LayoutParams((int)Context.ToPixels(22), LP.MatchParent)
                        {
                                LeftMargin = leftMargin,
@@ -330,24 +337,6 @@ namespace Xamarin.Forms.Platform.Android
                        Controller.ItemSelected(item);
                }
 
-               async void SetImage(AImageButton button, ImageSource image, int defaultValue)
-               {
-                       button.SetScaleType(ImageView.ScaleType.FitCenter);
-                       if (image != null)
-                       {
-                               using (var drawable = await Context.GetFormsDrawable(image))
-                                       button.SetImageDrawable(drawable);
-                       }
-                       else if (defaultValue > 0)
-                       {
-                               await Task.Run(() => button.SetImageResource(defaultValue)).ConfigureAwait(false);
-                       }
-                       else
-                       {
-                               button.SetImageDrawable(null);
-                       }
-               }
-
                void UpdateClearButtonState()
                {
                        if (string.IsNullOrEmpty(_textBlock.Text))
index 3d80d5d..42fe361 100644 (file)
@@ -300,7 +300,7 @@ namespace Xamarin.Forms.Platform.Android
                        Drawable icon = null;
 
                        if (image != null)
-                               icon = await context.GetFormsDrawable(image);
+                               icon = await context.GetFormsDrawableAsync(image);
 
                        if (text != null)
                                icon = new FlyoutIconDrawerDrawable(context, TintColor, icon, text);
@@ -337,7 +337,7 @@ namespace Xamarin.Forms.Platform.Android
                                        icon = shell.FlyoutIcon;
                                        if (icon != null)
                                        {
-                                               var drawable = await context.GetFormsDrawable(icon);
+                                               var drawable = await context.GetFormsDrawableAsync(icon);
                                                actionBarDrawerToggle.DrawerArrowDrawable = new FlyoutIconDrawerDrawable(context, TintColor, drawable, null);
                                        }
                                        return;
@@ -348,18 +348,19 @@ namespace Xamarin.Forms.Platform.Android
 
                protected virtual void UpdateMenuItemIcon(Context context, IMenuItem menuItem, ToolbarItem toolBarItem)
                {
-                       FileImageSource icon = toolBarItem.Icon;
-                       if (!string.IsNullOrEmpty(icon))
+                       _shellContext.ApplyDrawableAsync(toolBarItem, ToolbarItem.IconImageSourceProperty, baseDrawable =>
                        {
-                               using (var baseDrawable = context.GetFormsDrawable(icon))
-                               using (var constant = baseDrawable.GetConstantState())
-                               using (var newDrawable = constant.NewDrawable())
-                               using (var iconDrawable = newDrawable.Mutate())
+                               if (baseDrawable != null)
                                {
-                                       iconDrawable.SetColorFilter(TintColor.ToAndroid(Color.White), PorterDuff.Mode.SrcAtop);
-                                       menuItem.SetIcon(iconDrawable);
+                                       using (var constant = baseDrawable.GetConstantState())
+                                       using (var newDrawable = constant.NewDrawable())
+                                       using (var iconDrawable = newDrawable.Mutate())
+                                       {
+                                               iconDrawable.SetColorFilter(TintColor.ToAndroid(Color.White), PorterDuff.Mode.SrcAtop);
+                                               menuItem.SetIcon(iconDrawable);
+                                       }
                                }
-                       }
+                       });
                }
 
                protected virtual void UpdateNavBarVisible(Toolbar toolbar, Page page)
index 1cce466..b8492d4 100644 (file)
@@ -122,7 +122,7 @@ namespace Xamarin.Forms.Platform.Android
                                        UpdateMinimumTrackColor();
                                else if (e.PropertyName == Slider.MaximumTrackColorProperty.PropertyName)
                                        UpdateMaximumTrackColor();
-                               else if (e.PropertyName == Slider.ThumbImageProperty.PropertyName)
+                               else if (e.PropertyName == Slider.ThumbImageSourceProperty.PropertyName)
                                        UpdateThumbImage();
                                else if (e.PropertyName == Slider.ThumbColorProperty.PropertyName)
                                        UpdateThumbColor();
@@ -133,7 +133,8 @@ namespace Xamarin.Forms.Platform.Android
                {
                        UpdateMinimumTrackColor();
                        UpdateMaximumTrackColor();
-                       if (!string.IsNullOrEmpty(Element.ThumbImage))
+                       var thumbImage = Element.ThumbImageSource;
+                       if (thumbImage != null && !thumbImage.IsEmpty)
                        {
                                UpdateThumbImage();
                        }
@@ -195,13 +196,10 @@ namespace Xamarin.Forms.Platform.Android
 
                private void UpdateThumbImage()
                {
-                       if (Element != null)
+                       this.ApplyDrawableAsync(Slider.ThumbImageSourceProperty, Context, drawable =>
                        {
-                               if (string.IsNullOrEmpty(Element.ThumbImage))
-                                       Control.SetThumb(defaultthumb);
-                               else
-                                       Control.SetThumb(Context.GetDrawable(Element.ThumbImage));
-                       }
+                               Control.SetThumb(drawable ?? defaultthumb);
+                       });
                }
 
                protected override void OnLayout(bool changed, int l, int t, int r, int b)
index 53f0695..b6c1259 100644 (file)
@@ -1,13 +1,15 @@
 using System;
+using System.IO;
 using System.Linq;
 using System.Reflection;
+using System.Threading;
 using System.Threading.Tasks;
 using Android.Content;
 using Android.Content.Res;
 using Android.Graphics;
 using Android.Graphics.Drawables;
-using Path = System.IO.Path;
 using Xamarin.Forms.Internals;
+using Path = System.IO.Path;
 using AndroidAppCompat = Android.Support.V7.Content.Res.AppCompatResources;
 using System.ComponentModel;
 
@@ -25,33 +27,192 @@ namespace Xamarin.Forms.Platform.Android
 
                public static Type LayoutClass { get; set; }
 
-               internal static async Task<Drawable> GetFormsDrawable(this Context context, ImageSource imageSource)
+               internal static async Task<Drawable> GetFormsDrawableAsync(this Context context, ImageSource imageSource, CancellationToken cancellationToken = default(CancellationToken))
                {
-                       if (imageSource is FileImageSource fileSource)
-                               return context.GetFormsDrawable(fileSource);
+                       if (imageSource == null || imageSource.IsEmpty)
+                               return null;
+
+                       // try take a shortcut for files
+                       if (imageSource is FileImageSource fileImageSource)
+                       {
+                               var file = fileImageSource.File;
+                               var id = IdFromTitle(file, DrawableClass);
+
+                               // try the drawables via id
+                               if (id != 0)
+                               {
+                                       var drawable = AndroidAppCompat.GetDrawable(context, id);
+                                       if (drawable != null)
+                                               return drawable;
+                               }
+
+                               // try a direct file on the file system
+                               if (File.Exists(file))
+                               {
+                                       using (var bitmap = await BitmapFactory.DecodeFileAsync(file).ConfigureAwait(false))
+                                       {
+                                               if (bitmap != null)
+                                                       return new BitmapDrawable(context.Resources, bitmap);
+                                       }
+                               }
+
+                               // try the bitmap resources via id
+                               if (id != 0)
+                               {
+                                       using (var bitmap = await BitmapFactory.DecodeResourceAsync(context.Resources, id).ConfigureAwait(false))
+                                       {
+                                               if (bitmap != null)
+                                                       return new BitmapDrawable(context.Resources, bitmap);
+                                       }
+                               }
+                       }
+
+                       // fall back to the handler
+                       using (var bitmap = await context.GetFormsBitmapAsync(imageSource, cancellationToken).ConfigureAwait(false))
+                       {
+                               if (bitmap != null)
+                                       return new BitmapDrawable(context.Resources, bitmap);
+                       }
+
+                       return null;
+               }
+
+               internal static async Task<Bitmap> GetFormsBitmapAsync(this Context context, ImageSource imageSource, CancellationToken cancellationToken = default(CancellationToken))
+               {
+                       if (imageSource == null || imageSource.IsEmpty)
+                               return null;
 
                        var handler = Registrar.Registered.GetHandlerForObject<IImageSourceHandler>(imageSource);
-                       var icon = await handler.LoadImageAsync(imageSource, context);
-                       var drawable = new BitmapDrawable(context.Resources, icon);
-                       return drawable;
+                       if (handler == null)
+                               return null;
+
+                       try
+                       {
+                               return await handler.LoadImageAsync(imageSource, context, cancellationToken).ConfigureAwait(false);
+                       }
+                       catch (OperationCanceledException)
+                       {
+                               Internals.Log.Warning("Image loading", "Image load cancelled");
+                       }
+                       catch (Exception ex)
+                       {
+                               Internals.Log.Warning("Image loading", $"Image load failed: {ex}");
+                       }
+
+                       return null;
                }
 
-               internal static Drawable GetFormsDrawable(this Context context, FileImageSource fileImageSource)
+               internal static Task ApplyDrawableAsync(this IShellContext shellContext, BindableObject bindable, BindableProperty imageSourceProperty, Action<Drawable> onSet, Action<bool> onLoading = null, CancellationToken cancellationToken = default(CancellationToken))
                {
-                       var file = fileImageSource.File;
-                       Drawable drawable = context.GetDrawable(fileImageSource);
-                       if (drawable == null)
+                       _ = shellContext ?? throw new ArgumentNullException(nameof(shellContext));
+                       var renderer = shellContext as IVisualElementRenderer ?? throw new InvalidOperationException($"The shell context {shellContext.GetType()} must be a {typeof(IVisualElementRenderer)}.");
+
+                       return renderer.ApplyDrawableAsync(bindable, imageSourceProperty, shellContext.AndroidContext, onSet, onLoading, cancellationToken);
+               }
+
+               internal static Task ApplyDrawableAsync(this IVisualElementRenderer renderer,
+                                                                                 BindableProperty imageSourceProperty,
+                                                                                 Context context,
+                                                                                 Action<Drawable> onSet,
+                                                                                 Action<bool> onLoading = null,
+                                                                                 CancellationToken cancellationToken = default(CancellationToken))
+               {
+                       return renderer.ApplyDrawableAsync(null, imageSourceProperty, context, onSet, onLoading, cancellationToken);
+               }
+
+               internal static async Task ApplyDrawableAsync(this IVisualElementRenderer renderer,
+                                                                                               BindableObject bindable,
+                                                                                               BindableProperty imageSourceProperty,
+                                                                                               Context context,
+                                                                                               Action<Drawable> onSet,
+                                                                                               Action<bool> onLoading = null,
+                                                                                               CancellationToken cancellationToken = default(CancellationToken))
+               {
+                       _ = renderer ?? throw new ArgumentNullException(nameof(renderer));
+                       _ = context ?? throw new ArgumentNullException(nameof(context));
+                       _ = imageSourceProperty ?? throw new ArgumentNullException(nameof(imageSourceProperty));
+                       _ = onSet ?? throw new ArgumentNullException(nameof(onSet));
+
+                       // TODO: it might be good to make sure the renderer has not been disposed
+
+                       // make sure things are good before we start
+                       var element = bindable ?? renderer.Element;
+
+                       if (element == null || renderer.View == null)
+                               return;
+
+                       onLoading?.Invoke(true);
+                       if (element.GetValue(imageSourceProperty) is ImageSource initialSource && !initialSource.IsEmpty)
                        {
-                               var bitmap = GetBitmap(context.Resources, file) ?? BitmapFactory.DecodeFile(file);
-                               if (bitmap == null)
+                               try
                                {
-                                       var source = Registrar.Registered.GetHandlerForObject<IImageSourceHandler>(fileImageSource);
-                                       bitmap = source.LoadImageAsync(fileImageSource, context).GetAwaiter().GetResult();
+                                       using (var drawable = await context.GetFormsDrawableAsync(initialSource, cancellationToken))
+                                       {
+                                               // TODO: it might be good to make sure the renderer has not been disposed
+
+                                               // we are back, so update the working element
+                                               element = bindable ?? renderer.Element;
+
+                                               // makse sure things are good now that we are back
+                                               if (element == null || renderer.View == null)
+                                                       return;
+
+                                               // only set if we are still on the same image
+                                               if (element.GetValue(imageSourceProperty) == initialSource)
+                                                       onSet(drawable);
+                                       }
                                }
-                               if (bitmap != null)
-                                       drawable = new BitmapDrawable(context.Resources, bitmap);
+                               finally
+                               {
+                                       if (element != null && onLoading != null)
+                                       {
+                                               // only mark as finished if we are still on the same image
+                                               if (element.GetValue(imageSourceProperty) == initialSource)
+                                                       onLoading.Invoke(false);
+                                       }
+                               }
+                       }
+                       else
+                       {
+                               onSet(null);
+                               onLoading?.Invoke(false);
+                       }
+               }
+
+               internal static async Task ApplyDrawableAsync(this Context context, BindableObject bindable, BindableProperty imageSourceProperty, Action<Drawable> onSet, Action<bool> onLoading = null, CancellationToken cancellationToken = default(CancellationToken))
+               {
+                       _ = context ?? throw new ArgumentNullException(nameof(context));
+                       _ = bindable ?? throw new ArgumentNullException(nameof(bindable));
+                       _ = imageSourceProperty ?? throw new ArgumentNullException(nameof(imageSourceProperty));
+                       _ = onSet ?? throw new ArgumentNullException(nameof(onSet));
+
+                       onLoading?.Invoke(true);
+                       if (bindable.GetValue(imageSourceProperty) is ImageSource initialSource)
+                       {
+                               try
+                               {
+                                       using (var drawable = await context.GetFormsDrawableAsync(initialSource, cancellationToken))
+                                       {
+                                               // only set if we are still on the same image
+                                               if (bindable.GetValue(imageSourceProperty) == initialSource)
+                                                       onSet(drawable);
+                                       }
+                               }
+                               finally
+                               {
+                                       if (onLoading != null)
+                                       {
+                                               // only mark as finished if we are still on the same image
+                                               if (bindable.GetValue(imageSourceProperty) == initialSource)
+                                                       onLoading.Invoke(false);
+                                       }
+                               }
+                       }
+                       else
+                       {
+                               onSet(null);
+                               onLoading?.Invoke(false);
                        }
-                       return drawable;
                }
 
                public static Bitmap GetBitmap(this Resources resource, FileImageSource fileImageSource)
index bfcef2e..d8b4776 100644 (file)
@@ -3,6 +3,7 @@ using System;
 using System.Collections.Generic;
 using System.ComponentModel;
 using System.Linq;
+using Xamarin.Forms.Platform.GTK.Extensions;
 
 namespace Xamarin.Forms.Platform.GTK.Cells
 {
@@ -131,12 +132,11 @@ namespace Xamarin.Forms.Platform.GTK.Cells
                        {
                                var menuItem = new ImageMenuItem(item.Text);
 
-                               string icon = item.Icon;
-
-                               if (!string.IsNullOrEmpty(icon))
+                               _ = item.ApplyNativeImageAsync(MenuItem.IconImageSourceProperty, icon =>
                                {
-                                       menuItem.Image = new Gtk.Image(icon);
-                               }
+                                       if (icon != null)
+                                               menuItem.Image = new Gtk.Image(icon);
+                               });
 
                                menuItem.ButtonPressEvent += (sender, args) =>
                                {
index ec3e843..3b2ae58 100644 (file)
@@ -10,11 +10,7 @@ namespace Xamarin.Forms.Platform.GTK.Cells
                {
                        var gtkImageCell = base.GetCell(item, reusableView, listView) as ImageCell;
                        var imageCell = (Xamarin.Forms.ImageCell)item;
-
-#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
                        SetImage(imageCell, gtkImageCell);
-#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
-
                        return gtkImageCell;
                }
 
@@ -35,7 +31,7 @@ namespace Xamarin.Forms.Platform.GTK.Cells
                                        detailColor);
                }
 
-               protected override async void CellPropertyChanged(object sender, PropertyChangedEventArgs args)
+               protected override void CellPropertyChanged(object sender, PropertyChangedEventArgs args)
                {
                        base.CellPropertyChanged(sender, args);
 
@@ -52,41 +48,17 @@ namespace Xamarin.Forms.Platform.GTK.Cells
                        }
                        else if (args.PropertyName == Xamarin.Forms.ImageCell.ImageSourceProperty.PropertyName)
                        {
-                               await SetImage(imageCell, gtkImageCell);
+                               SetImage(imageCell, gtkImageCell);
                        }
                }
 
-               private static async System.Threading.Tasks.Task SetImage(Xamarin.Forms.ImageCell cell, ImageCell target)
+               private static void SetImage(Xamarin.Forms.ImageCell cell, ImageCell target)
                {
-                       var source = cell.ImageSource;
-
                        target.Image = null;
-
-                       Renderers.IImageSourceHandler handler;
-
-                       if (source != null && (handler =
-                               Internals.Registrar.Registered.GetHandlerForObject<Renderers.IImageSourceHandler>(source)) != null)
+                       _ = cell.ApplyNativeImageAsync(Xamarin.Forms.ImageCell.ImageSourceProperty, image =>
                        {
-                               Gdk.Pixbuf image;
-
-                               try
-                               {
-                                       image = await handler.LoadImageAsync(source).ConfigureAwait(false);
-                               }
-                               catch (System.Threading.Tasks.TaskCanceledException)
-                               {
-                                       image = null;
-                               }
-                               catch(Exception)
-                               {
-                                       image = null;
-                               }
-
                                target.Image = image;
-
-                       }
-                       else
-                               target.Image = null;
+                       });
                }
        }
 }
index 33397b5..63a6788 100644 (file)
@@ -174,21 +174,9 @@ namespace Xamarin.Forms.Platform.GTK.Controls
                        } while (_root.Children.Length > 0);
                }
 
-               public void SetBackgroundImage(string backgroundImagePath)
+               public async void SetBackgroundImage(ImageSource imageSource)
                {
-                       if(string.IsNullOrEmpty(backgroundImagePath))
-                       {
-                               return;
-                       }
-
-                       try
-                       {
-                               _image.Pixbuf = new Pixbuf(backgroundImagePath);
-                       }
-                       catch (Exception ex)
-                       {
-                               Internals.Log.Warning("CarouselPage BackgroundImage", "Could not load background image: {0}", ex);
-                       }
+                       _image.Pixbuf = await imageSource.GetNativeImageAsync();
                }
 
                protected override void OnSizeAllocated(Gdk.Rectangle allocation)
index e45f400..76cbb39 100644 (file)
@@ -97,26 +97,6 @@ namespace Xamarin.Forms.Platform.GTK.Controls
                        RecreateContainer();
                }
 
-               public void SetImageFromFile(string fileName)
-               {
-                       if (string.IsNullOrEmpty(fileName))
-                               return;
-
-                       try
-                       {
-                               var iconPixBuf = new Pixbuf(fileName);
-
-                               if (iconPixBuf != null)
-                               {
-                                       ImageWidget.Pixbuf = iconPixBuf;
-                               }
-                       }
-                       catch (Exception ex)
-                       {
-                               Internals.Log.Warning("Image Loading", $"Image failed to load: {ex}");
-                       }
-               }
-
                public override void Destroy()
                {
                        base.Destroy();
index 5adff56..985fa0a 100644 (file)
@@ -1,5 +1,6 @@
 ï»¿using Gdk;
 using Gtk;
+using Xamarin.Forms.Platform.GTK.Extensions;
 
 namespace Xamarin.Forms.Platform.GTK.Controls
 {
@@ -95,11 +96,9 @@ namespace Xamarin.Forms.Platform.GTK.Controls
                        }
                }
 
-               public void SetBackgroundImage(string backgroundImagePath)
+               public async void SetBackgroundImage(ImageSource imageSource)
                {
-                       _backgroundPixbuf = !string.IsNullOrEmpty(backgroundImagePath)
-                               ? new Pixbuf(backgroundImagePath)
-                               : null;
+                       _backgroundPixbuf = await imageSource.GetNativeImageAsync();
 
                        for (int i = 0; i < _noteBook.NPages; i++)
                        {
index 0d7a651..dfacec4 100644 (file)
@@ -62,21 +62,9 @@ namespace Xamarin.Forms.Platform.GTK.Controls
                        _contentContainerWrapper.SetBackgroundColor(backgroundColor);
                }
 
-               public void SetBackgroundImage(string backgroundImagePath)
+               public async void SetBackgroundImage(ImageSource imageSource)
                {
-                       if (string.IsNullOrEmpty(backgroundImagePath))
-                       {
-                               return;
-                       }
-
-                       try
-                       {
-                               _image.Pixbuf = new Pixbuf(backgroundImagePath);
-                       }
-                       catch (Exception ex)
-                       {
-                               Internals.Log.Warning("Page BackgroundImage", "Could not load background image: {0}", ex);
-                       }
+                       _image.Pixbuf = await imageSource.GetNativeImageAsync();
                }
 
                public void PushModal(Widget modal)
index aa10052..a0e553d 100644 (file)
@@ -1,6 +1,10 @@
 ï»¿using Gdk;
 using System;
 using System.IO;
+using System.Threading;
+using System.Threading.Tasks;
+using Xamarin.Forms.Internals;
+using Xamarin.Forms.Platform.GTK.Renderers;
 
 namespace Xamarin.Forms.Platform.GTK.Extensions
 {
@@ -45,5 +49,124 @@ namespace Xamarin.Forms.Platform.GTK.Extensions
                                return null;
                        }
                }
+
+               internal static async Task<Pixbuf> GetNativeImageAsync(this ImageSource imageSource, CancellationToken cancellationToken = default(CancellationToken))
+               {
+                       if (imageSource == null || imageSource.IsEmpty)
+                               return null;
+
+                       var handler = Registrar.Registered.GetHandlerForObject<IImageSourceHandler>(imageSource);
+                       if (handler == null)
+                               return null;
+
+                       try
+                       {
+                               return await handler.LoadImageAsync(imageSource, cancellationToken).ConfigureAwait(false);
+                       }
+                       catch (OperationCanceledException)
+                       {
+                               Log.Warning("Image loading", "Image load cancelled");
+                       }
+                       catch (Exception ex)
+                       {
+                               Log.Warning("Image loading", $"Image load failed: {ex}");
+                       }
+
+                       return null;
+               }
+
+               internal static Task ApplyNativeImageAsync(this IVisualElementRenderer renderer, BindableProperty imageSourceProperty, Action<Pixbuf> onSet, Action<bool> onLoading = null, CancellationToken cancellationToken = default(CancellationToken))
+               {
+                       return renderer.ApplyNativeImageAsync(null, imageSourceProperty, onSet, onLoading, cancellationToken);
+               }
+
+               internal static async Task ApplyNativeImageAsync(this IVisualElementRenderer renderer, BindableObject bindable, BindableProperty imageSourceProperty, Action<Pixbuf> onSet, Action<bool> onLoading = null, CancellationToken cancellationToken = default(CancellationToken))
+               {
+                       _ = renderer ?? throw new ArgumentNullException(nameof(renderer));
+                       _ = imageSourceProperty ?? throw new ArgumentNullException(nameof(imageSourceProperty));
+                       _ = onSet ?? throw new ArgumentNullException(nameof(onSet));
+
+                       // TODO: it might be good to make sure the renderer has not been disposed
+
+                       // makse sure things are good before we start
+                       var element = bindable ?? renderer.Element;
+
+                       var nativeRenderer = renderer as IVisualNativeElementRenderer;
+
+                       if (element == null || renderer.Container == null || (nativeRenderer != null && nativeRenderer.Control == null))
+                               return;
+
+                       onLoading?.Invoke(true);
+                       if (element.GetValue(imageSourceProperty) is ImageSource initialSource && !initialSource.IsEmpty)
+                       {
+                               try
+                               {
+                                       using (var drawable = await initialSource.GetNativeImageAsync(cancellationToken))
+                                       {
+                                               // TODO: it might be good to make sure the renderer has not been disposed
+
+                                               // we are back, so update the working element
+                                               element = bindable ?? renderer.Element;
+
+                                               // makse sure things are good now that we are back
+                                               if (element == null || renderer.Container == null || (nativeRenderer != null && nativeRenderer.Control == null))
+                                                       return;
+
+                                               // only set if we are still on the same image
+                                               if (element.GetValue(imageSourceProperty) == initialSource)
+                                                       onSet(drawable);
+                                       }
+                               }
+                               finally
+                               {
+                                       if (element != null && onLoading != null)
+                                       {
+                                               // only mark as finished if we are still on the same image
+                                               if (element.GetValue(imageSourceProperty) == initialSource)
+                                                       onLoading.Invoke(false);
+                                       }
+                               }
+                       }
+                       else
+                       {
+                               onSet(null);
+                               onLoading?.Invoke(false);
+                       }
+               }
+
+               internal static async Task ApplyNativeImageAsync(this BindableObject bindable, BindableProperty imageSourceProperty, Action<Pixbuf> onSet, Action<bool> onLoading = null, CancellationToken cancellationToken = default(CancellationToken))
+               {
+                       _ = bindable ?? throw new ArgumentNullException(nameof(bindable));
+                       _ = imageSourceProperty ?? throw new ArgumentNullException(nameof(imageSourceProperty));
+                       _ = onSet ?? throw new ArgumentNullException(nameof(onSet));
+
+                       onLoading?.Invoke(true);
+                       if (bindable.GetValue(imageSourceProperty) is ImageSource initialSource)
+                       {
+                               try
+                               {
+                                       using (var drawable = await initialSource.GetNativeImageAsync(cancellationToken))
+                                       {
+                                               // only set if we are still on the same image
+                                               if (bindable.GetValue(imageSourceProperty) == initialSource)
+                                                       onSet(drawable);
+                                       }
+                               }
+                               finally
+                               {
+                                       if (onLoading != null)
+                                       {
+                                               // only mark as finished if we are still on the same image
+                                               if (bindable.GetValue(imageSourceProperty) == initialSource)
+                                                       onLoading.Invoke(false);
+                                       }
+                               }
+                       }
+                       else
+                       {
+                               onSet(null);
+                               onLoading?.Invoke(false);
+                       }
+               }
        }
 }
index bd1cc87..e80ada9 100644 (file)
@@ -4,18 +4,6 @@ namespace Xamarin.Forms.Platform.GTK.Extensions
 {
        public static class PageExtensions
        {
-               internal static bool ShouldDisplayNativeWindow(this Page page)
-               {
-                       var parentPage = page.Parent as Page;
-
-                       if (parentPage != null)
-                       {
-                               return string.IsNullOrEmpty(parentPage.BackgroundImage);
-                       }
-
-                       return true;
-               }
-
                public static GtkFormsContainer CreateContainer(this Page view)
                {
                        if (!Forms.IsInitialized)
index cea2d5f..829786e 100644 (file)
@@ -76,17 +76,15 @@ namespace Xamarin.Forms.Platform.GTK
                        if (_toolbar == null || _navigation == null)
                                return;
 
-                       var iconPath = GetCurrentPageIconPath();
-
-                       if (!string.IsNullOrEmpty(iconPath))
-                       {
-                               _toolbarIcon.Pixbuf = new Pixbuf(iconPath);
-                               _toolbarIcon.SetSizeRequest(GtkToolbarConstants.ToolbarIconWidth, GtkToolbarConstants.ToolbarIconHeight);
-                       }
-                       else
+                       _toolbarIcon.WidthRequest = 1;
+                       _ = _navigation?.Peek(0)?.ApplyNativeImageAsync(Page.IconImageSourceProperty, icon =>
                        {
-                               _toolbarIcon.WidthRequest = 1;
-                       }
+                               if (icon != null)
+                               {
+                                       _toolbarIcon.Pixbuf = icon;
+                                       _toolbarIcon.SetSizeRequest(GtkToolbarConstants.ToolbarIconWidth, GtkToolbarConstants.ToolbarIconHeight);
+                               }
+                       });
                }
 
                public void UpdateTitle()
@@ -147,7 +145,7 @@ namespace Xamarin.Forms.Platform.GTK
                                e.PropertyName.Equals(NavigationPage.BarBackgroundColorProperty.PropertyName) ||
                                e.PropertyName.Equals(NavigationPage.HasNavigationBarProperty.PropertyName) ||
                                e.PropertyName.Equals(Page.TitleProperty.PropertyName) ||
-                               e.PropertyName.Equals(Page.IconProperty.PropertyName))
+                               e.PropertyName.Equals(Page.IconImageSourceProperty.PropertyName))
                                UpdateToolBar();
                }
 
@@ -158,13 +156,6 @@ namespace Xamarin.Forms.Platform.GTK
                        return _navigation.Peek(0).Title ?? string.Empty;
                }
 
-               private string GetCurrentPageIconPath()
-               {
-                       if (_navigation == null)
-                               return string.Empty;
-                       return _navigation.Peek(0).Icon ?? string.Empty;
-               }
-
                private void UpdateBarBackgroundColor(Controls.Page page)
                {
                        if (Navigation != null)
@@ -410,7 +401,7 @@ namespace Xamarin.Forms.Platform.GTK
                                UpdateToolbarItems();
                        else if (e.PropertyName == MenuItem.TextProperty.PropertyName)
                                UpdateToolbarItems();
-                       else if (e.PropertyName == MenuItem.IconProperty.PropertyName)
+                       else if (e.PropertyName == MenuItem.IconImageSourceProperty.PropertyName)
                                UpdateToolbarItems();
                }
 
@@ -437,7 +428,7 @@ namespace Xamarin.Forms.Platform.GTK
 
                        public static ToolButton CreateToolButton(ToolbarItem item)
                        {
-                               var pixBuf = item.Icon.ToPixbuf();
+                               var pixBuf = item.IconImageSource.ToPixbuf();
                                Gtk.Image icon = pixBuf != null ? new Gtk.Image(pixBuf) : null;
                                ToolButton button = new ToolButton(icon, item.Text);
                                ApplyDefaultDimensions(button);
diff --git a/Xamarin.Forms.Platform.GTK/IVisualNativeElementRenderer.cs b/Xamarin.Forms.Platform.GTK/IVisualNativeElementRenderer.cs
new file mode 100644 (file)
index 0000000..3dcae99
--- /dev/null
@@ -0,0 +1,9 @@
+using Control = Gtk.Widget;
+
+namespace Xamarin.Forms.Platform.GTK
+{
+       public interface IVisualNativeElementRenderer : IVisualElementRenderer
+       {
+               Control Control { get; }
+       }
+}
index cd2386a..7515465 100644 (file)
@@ -185,14 +185,14 @@ namespace Xamarin.Forms.Platform.GTK.Renderers
 
                protected virtual void UpdateBackgroundImage()
                {
-                       Control.SetBackgroundImage(Page.BackgroundImage);
+                       Control.SetBackgroundImage(Page.BackgroundImageSource);
                }
 
                protected virtual void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
                {
                        if (e.PropertyName == VisualElement.BackgroundColorProperty.PropertyName)
                                UpdateBackgroundColor();
-                       else if (e.PropertyName == Xamarin.Forms.Page.BackgroundImageProperty.PropertyName)
+                       else if (e.PropertyName == Xamarin.Forms.Page.BackgroundImageSourceProperty.PropertyName)
                                UpdateBackgroundImage();
                }
 
index 506a4ea..f689e70 100644 (file)
@@ -67,7 +67,7 @@ namespace Xamarin.Forms.Platform.GTK.Renderers
                                UpdateBorder();
                        else if (e.PropertyName == Button.BorderWidthProperty.PropertyName)
                                UpdateBorder();
-                       else if (e.PropertyName == Button.ImageProperty.PropertyName || e.PropertyName == Button.ContentLayoutProperty.PropertyName)
+                       else if (e.PropertyName == Button.ImageSourceProperty.PropertyName || e.PropertyName == Button.ContentLayoutProperty.PropertyName)
                                UpdateContent();
                }
 
@@ -161,17 +161,17 @@ namespace Xamarin.Forms.Platform.GTK.Renderers
 
                private void UpdateContent()
                {
-                       if (!string.IsNullOrEmpty(Element.Image))
+                       this.ApplyNativeImageAsync(Button.ImageSourceProperty, image =>
                        {
-                               Control.SetImageFromFile(Element.Image);
-                               Control.ImageSpacing = (uint)Element.ContentLayout.Spacing;
-                               Control.SetImagePosition(Element.ContentLayout.Position.AsPositionType());
-                               Control.ImageWidget.Visible = true;
-                       }
-                       else
-                       {
-                               Control.ImageWidget.Visible = false;
-                       }
+                               if (image != null)
+                               {
+                                       Control.ImageWidget.Pixbuf = image;
+                                       Control.ImageSpacing = (uint)Element.ContentLayout.Spacing;
+                                       Control.SetImagePosition(Element.ContentLayout.Position.AsPositionType());
+                               }
+
+                               Control.ImageWidget.Visible = image != null;
+                       });
                }
        }
 }
index d42f647..54dbcef 100644 (file)
@@ -106,7 +106,7 @@ namespace Xamarin.Forms.Platform.GTK.Renderers
 
                protected override void UpdateBackgroundImage()
                {
-                       Widget?.SetBackgroundImage(Page.BackgroundImage);
+                       Widget?.SetBackgroundImage(Page.BackgroundImageSource);
                }
 
                private void Init()
index 3046aa8..bfd866e 100644 (file)
@@ -4,6 +4,7 @@ using System.ComponentModel;
 using System.IO;
 using System.Threading;
 using System.Threading.Tasks;
+using Xamarin.Forms.Platform.GTK.Extensions;
 
 namespace Xamarin.Forms.Platform.GTK.Renderers
 {
@@ -84,42 +85,19 @@ namespace Xamarin.Forms.Platform.GTK.Renderers
                                Control.Pixbuf = null;
                        }
 
-                       IImageSourceHandler handler;
-
                        ((IImageController)Element).SetIsLoading(true);
 
-                       if (source != null
-                               && (handler = Internals.Registrar.Registered.GetHandlerForObject<IImageSourceHandler>(source)) != null)
-                       {
-                               Pixbuf image;
-
-                               try
-                               {
-                                       image = await handler.LoadImageAsync(source);
-                               }
-                               catch (OperationCanceledException)
-                               {
-                                       image = null;
-                                       Internals.Log.Warning("Image loading", "Image load cancelled");
-                               }
-                               catch(Exception ex)
-                               {
-                                       image = null;
-                                       Internals.Log.Warning("Image loading", $"Image load failed: {ex}");
-                               }
-
-                               var imageView = Control;
-                               if (imageView != null)
-                                       imageView.Pixbuf = image;
+                       var image = await source.GetNativeImageAsync();
 
-                               if (!_isDisposed)
-                                       ((IVisualElementController)Element).NativeSizeChanged();
-                       }
-                       else
-                               Control.Pixbuf = null;
+                       var imageView = Control;
+                       if (imageView != null)
+                               imageView.Pixbuf = image;
 
                        if (!_isDisposed)
+                       {
+                               ((IVisualElementController)Element).NativeSizeChanged();
                                ((IImageController)Element).SetIsLoading(false);
+                       }
                }
 
                void SetAspect()
index c235889..8b64766 100644 (file)
@@ -117,7 +117,7 @@ namespace Xamarin.Forms.Platform.GTK.Renderers
 
                private async void HandleMasterPropertyChanged(object sender, PropertyChangedEventArgs e)
                {
-                       if (e.PropertyName == Xamarin.Forms.Page.IconProperty.PropertyName)
+                       if (e.PropertyName == Xamarin.Forms.Page.IconImageSourceProperty.PropertyName)
                                await UpdateHamburguerIconAsync();
                }
 
@@ -195,26 +195,18 @@ namespace Xamarin.Forms.Platform.GTK.Renderers
                        }
                }
 
-               private async Task UpdateHamburguerIconAsync()
+               private Task UpdateHamburguerIconAsync()
                {
-                       var hamburguerIcon = Page.Master.Icon;
-
-                       if (hamburguerIcon != null)
+                       return Page.Master.ApplyNativeImageAsync(Xamarin.Forms.Page.IconImageSourceProperty, image =>
                        {
-                               IImageSourceHandler handler =
-                                       Registrar.Registered.GetHandlerForObject<IImageSourceHandler>(hamburguerIcon);
-
-                               var image = await handler.LoadImageAsync(hamburguerIcon);
                                Widget.UpdateHamburguerIcon(image);
 
-                               var navigationPage = Page.Detail as NavigationPage;
-
-                               if (navigationPage != null)
+                               if (Page.Detail is NavigationPage navigationPage)
                                {
                                        var navigationRenderer = Platform.GetRenderer(navigationPage) as IToolbarTracker;
                                        navigationRenderer?.NativeToolbarTracker.UpdateToolBar();
                                }
-                       }
+                       });
                }
 
                private MasterBehaviorType GetMasterBehavior(MasterBehavior masterBehavior)
index 2426c90..c30d8ea 100644 (file)
@@ -156,11 +156,11 @@ namespace Xamarin.Forms.Platform.GTK.Renderers
                {
                        base.UpdateBackgroundImage();
 
-                       var parent = Widget?.Parent as EventBox;
-
-                       if (parent != null)
+                       if (Widget?.Parent is EventBox parent)
                        {
-                               parent.VisibleWindow = Page.CurrentPage?.ShouldDisplayNativeWindow() ?? true;
+                               parent.VisibleWindow = Page.CurrentPage?.Parent is Page parentPage
+                                       ? parentPage.BackgroundImageSource.IsEmpty
+                                       : true;
                        }
                }
 
@@ -258,7 +258,7 @@ namespace Xamarin.Forms.Platform.GTK.Renderers
                {
                        if (e.PropertyName == Xamarin.Forms.Page.TitleProperty.PropertyName)
                                UpdateTitle();
-                       else if (e.PropertyName == Xamarin.Forms.Page.IconProperty.PropertyName)
+                       else if (e.PropertyName == Xamarin.Forms.Page.IconImageSourceProperty.PropertyName)
                                UpdateIcon();
                }
 
index c119853..fa10444 100644 (file)
@@ -87,7 +87,7 @@ namespace Xamarin.Forms.Platform.GTK.Renderers
 
                protected override void UpdateBackgroundImage()
                {
-                       Widget?.SetBackgroundImage(Page.BackgroundImage);
+                       Widget?.SetBackgroundImage(Page.BackgroundImageSource);
                }
 
                protected override void Dispose(bool disposing)
@@ -142,7 +142,7 @@ namespace Xamarin.Forms.Platform.GTK.Renderers
                        Widget.InsertPage(
                                pageRenderer.Container,
                                page.Title,
-                               page.Icon?.ToPixbuf(new Size(DefaultIconWidth, DefaultIconHeight)),
+                               page.IconImageSource?.ToPixbuf(new Size(DefaultIconWidth, DefaultIconHeight)),
                                index);
 
                        Widget.ShowAll();
@@ -185,11 +185,11 @@ namespace Xamarin.Forms.Platform.GTK.Renderers
 
                                Widget.SetTabLabelText(index, page.Title);
                        }
-                       else if (e.PropertyName == Xamarin.Forms.Page.IconProperty.PropertyName)
+                       else if (e.PropertyName == Xamarin.Forms.Page.IconImageSourceProperty.PropertyName)
                        {
                                var page = (Page)sender;
                                var index = TabbedPage.GetIndex(page);
-                               var icon = page.Icon;
+                               var icon = page.IconImageSource;
 
                                Widget.SetTabIcon(index, icon.ToPixbuf());
                        }
index bb93d02..3c22f55 100644 (file)
@@ -8,7 +8,7 @@ using Control = Gtk.Widget;
 
 namespace Xamarin.Forms.Platform.GTK
 {
-       public class VisualElementRenderer<TElement, TNativeElement> : Container, IVisualElementRenderer, IDisposable, IEffectControlProvider
+       public class VisualElementRenderer<TElement, TNativeElement> : Container, IVisualNativeElementRenderer, IVisualElementRenderer, IDisposable, IEffectControlProvider
                where TElement : VisualElement
                where TNativeElement : Control
        {
@@ -50,6 +50,8 @@ namespace Xamarin.Forms.Platform.GTK
 
                public TNativeElement Control { get; set; }
 
+               Control IVisualNativeElementRenderer.Control => Control;
+
                public TElement Element { get; set; }
 
                public Container Container => this;
index 559e92e..4e3a167 100644 (file)
     <Compile Include="IDesiredSizeProvider.cs" />
     <Compile Include="IVisualElementRenderer.cs" />
     <Compile Include="GtkToolbarTracker.cs" />
+    <Compile Include="IVisualNativeElementRenderer.cs" />
     <Compile Include="Packagers\LayoutElementPackager.cs" />
     <Compile Include="Packagers\PageElementPackager.cs" />
     <Compile Include="Packagers\VisualElementPackager.cs" />
index decf11d..6cf8a23 100644 (file)
@@ -24,7 +24,7 @@ namespace Xamarin.Forms.Platform.MacOS
                        return result;
                }
 
-               protected override async void HandlePropertyChanged(object sender, PropertyChangedEventArgs args)
+               protected override void HandlePropertyChanged(object sender, PropertyChangedEventArgs args)
                {
                        var tvc = (CellNSView)sender;
                        var imageCell = (ImageCell)tvc.Cell;
@@ -32,37 +32,18 @@ namespace Xamarin.Forms.Platform.MacOS
                        base.HandlePropertyChanged(sender, args);
 
                        if (args.PropertyName == ImageCell.ImageSourceProperty.PropertyName)
-                               await SetImage(imageCell, tvc);
+                               SetImage(imageCell, tvc);
                }
 
-               static async Task SetImage(ImageCell cell, CellNSView target)
+               static void SetImage(ImageCell cell, CellNSView target)
                {
-                       var source = cell.ImageSource;
-
                        target.ImageView.Image = null;
 
-                       IImageSourceHandler handler;
-
-                       if (source != null && (handler = Internals.Registrar.Registered.GetHandlerForObject<IImageSourceHandler>(source)) != null)
+                       _ = cell.ApplyNativeImageAsync(ImageCell.ImageSourceProperty, image =>
                        {
-                               NSImage uiimage;
-                               try
-                               {
-                                       uiimage = await handler.LoadImageAsync(source).ConfigureAwait(false);
-                               }
-                               catch (TaskCanceledException)
-                               {
-                                       uiimage = null;
-                               }
-
-                               NSRunLoop.Main.BeginInvokeOnMainThread(() =>
-                               {
-                                       target.ImageView.Image = uiimage;
-                                       target.NeedsLayout = true;
-                               });
-                       }
-                       else
-                               target.ImageView.Image = null;
+                               target.ImageView.Image = image;
+                               target.NeedsLayout = true;
+                       });
                }
        }
 }
\ No newline at end of file
index 0952173..5b59237 100644 (file)
@@ -1,4 +1,8 @@
-using AppKit;
+using System;
+using System.Threading;
+using System.Threading.Tasks;
+using AppKit;
+using Xamarin.Forms.Internals;
 
 namespace Xamarin.Forms.Platform.MacOS
 {
@@ -18,5 +22,124 @@ namespace Xamarin.Forms.Platform.MacOS
                        resizedImage.UnlockFocus();
                        return resizedImage;
                }
+
+               internal static async Task<NSImage> GetNativeImageAsync(this ImageSource source, CancellationToken cancellationToken = default(CancellationToken))
+               {
+                       if (source == null || source.IsEmpty)
+                               return null;
+
+                       var handler = Internals.Registrar.Registered.GetHandlerForObject<IImageSourceHandler>(source);
+                       if (handler == null)
+                               return null;
+
+                       try
+                       {
+                               return await handler.LoadImageAsync(source, scale: (float)NSScreen.MainScreen.BackingScaleFactor, cancelationToken: cancellationToken);
+                       }
+                       catch (OperationCanceledException)
+                       {
+                               Log.Warning("Image loading", "Image load cancelled");
+                       }
+                       catch (Exception ex)
+                       {
+                               Log.Warning("Image loading", $"Image load failed: {ex}");
+                       }
+
+                       return null;
+               }
+
+               internal static Task ApplyNativeImageAsync(this IVisualElementRenderer renderer, BindableProperty imageSourceProperty, Action<NSImage> onSet, Action<bool> onLoading = null, CancellationToken cancellationToken = default(CancellationToken))
+               {
+                       return renderer.ApplyNativeImageAsync(null, imageSourceProperty, onSet, onLoading, cancellationToken);
+               }
+
+               internal static async Task ApplyNativeImageAsync(this IVisualElementRenderer renderer, BindableObject bindable, BindableProperty imageSourceProperty, Action<NSImage> onSet, Action<bool> onLoading = null, CancellationToken cancellationToken = default(CancellationToken))
+               {
+                       _ = renderer ?? throw new ArgumentNullException(nameof(renderer));
+                       _ = imageSourceProperty ?? throw new ArgumentNullException(nameof(imageSourceProperty));
+                       _ = onSet ?? throw new ArgumentNullException(nameof(onSet));
+
+                       // TODO: it might be good to make sure the renderer has not been disposed
+
+                       // makse sure things are good before we start
+                       var element = bindable ?? renderer.Element;
+
+                       var nativeRenderer = renderer as IVisualNativeElementRenderer;
+
+                       if (element == null || renderer.NativeView == null || (nativeRenderer != null && nativeRenderer.Control == null))
+                               return;
+
+                       onLoading?.Invoke(true);
+                       if (element.GetValue(imageSourceProperty) is ImageSource initialSource && !initialSource.IsEmpty)
+                       {
+                               try
+                               {
+                                       using (var drawable = await initialSource.GetNativeImageAsync(cancellationToken))
+                                       {
+                                               // TODO: it might be good to make sure the renderer has not been disposed
+
+                                               // we are back, so update the working element
+                                               element = bindable ?? renderer.Element;
+
+                                               // makse sure things are good now that we are back
+                                               if (element == null || renderer.NativeView == null || (nativeRenderer != null && nativeRenderer.Control == null))
+                                                       return;
+
+                                               // only set if we are still on the same image
+                                               if (element.GetValue(imageSourceProperty) == initialSource)
+                                                       onSet(drawable);
+                                       }
+                               }
+                               finally
+                               {
+                                       if (element != null && onLoading != null)
+                                       {
+                                               // only mark as finished if we are still on the same image
+                                               if (element.GetValue(imageSourceProperty) == initialSource)
+                                                       onLoading.Invoke(false);
+                                       }
+                               }
+                       }
+                       else
+                       {
+                               onSet(null);
+                               onLoading?.Invoke(false);
+                       }
+               }
+
+               internal static async Task ApplyNativeImageAsync(this BindableObject bindable, BindableProperty imageSourceProperty, Action<NSImage> onSet, Action<bool> onLoading = null, CancellationToken cancellationToken = default(CancellationToken))
+               {
+                       _ = bindable ?? throw new ArgumentNullException(nameof(bindable));
+                       _ = imageSourceProperty ?? throw new ArgumentNullException(nameof(imageSourceProperty));
+                       _ = onSet ?? throw new ArgumentNullException(nameof(onSet));
+
+                       onLoading?.Invoke(true);
+                       if (bindable.GetValue(imageSourceProperty) is ImageSource initialSource)
+                       {
+                               try
+                               {
+                                       using (var nsimage = await initialSource.GetNativeImageAsync(cancellationToken))
+                                       {
+                                               // only set if we are still on the same image
+                                               if (bindable.GetValue(imageSourceProperty) == initialSource)
+                                                       onSet(nsimage);
+                                       }
+                               }
+                               finally
+                               {
+                                       if (onLoading != null)
+                                       {
+                                               // only mark as finished if we are still on the same image
+                                               if (bindable.GetValue(imageSourceProperty) == initialSource)
+                                                       onLoading.Invoke(false);
+                                       }
+                               }
+                       }
+                       else
+                       {
+                               onSet(null);
+                               onLoading?.Invoke(false);
+                       }
+               }
        }
 }
\ No newline at end of file
index a67efba..c610ffb 100644 (file)
@@ -1,6 +1,7 @@
 ï»¿using System;
 using System.Linq;
 using AppKit;
+using Xamarin.Forms.Platform.MacOS;
 
 namespace Xamarin.Forms.Platform.macOS.Extensions
 {
@@ -36,8 +37,11 @@ namespace Xamarin.Forms.Platform.macOS.Extensions
                                nsMenuItem.Tag = i;
                        nsMenuItem.Enabled = menuItem.IsEnabled;
                        nsMenuItem.Activated += (sender, e) => ((IMenuItemController)menuItem).Activate();
-                       if (!string.IsNullOrEmpty(menuItem.Icon))
-                               nsMenuItem.Image = new NSImage(menuItem.Icon);
+                       _ = menuItem.ApplyNativeImageAsync(MenuItem.IconImageSourceProperty, image =>
+                       {
+                               if (image != null)
+                                       nsMenuItem.Image = image;
+                       });
 
                        return nsMenuItem;
                }
@@ -54,12 +58,12 @@ namespace Xamarin.Forms.Platform.macOS.Extensions
                                {
                                        menuItem.Enabled = item.IsEnabled;
                                }
-                               if (property.Equals(nameof(MenuItem.Icon)))
+                               if (property.Equals(nameof(MenuItem.IconImageSource)))
                                {
-                                       if (!string.IsNullOrEmpty(item.Icon))
-                                               menuItem.Image = new NSImage(item.Icon);
-                                       else
-                                               menuItem.Image = null;
+                                       _ = item.ApplyNativeImageAsync(MenuItem.IconImageSourceProperty, image =>
+                                       {
+                                               menuItem.Image = image;
+                                       });
                                }
                        }
                }
index bd262e2..d05a8d0 100644 (file)
@@ -361,7 +361,7 @@ namespace Xamarin.Forms.Platform.MacOS
                                        var tbI = new ToolbarItem
                                        {
                                                Text = item.Title,
-                                               Icon = item.Icon,
+                                               IconImageSource = item.IconImageSource,
                                                Command = new Command(() => tabbedPage.SelectedItem = item)
                                        };
                                        items.Add(tbI);
@@ -371,8 +371,7 @@ namespace Xamarin.Forms.Platform.MacOS
                        UpdateGroup(_tabbedGroup, items, ToolbarItemWidth, ToolbarItemSpacing);
                }
 
-               void UpdateGroup(NativeToolbarGroup group, IList<ToolbarItem> toolbarItems, double itemWidth,
-                  double itemSpacing)
+               void UpdateGroup(NativeToolbarGroup group, IList<ToolbarItem> toolbarItems, double itemWidth, double itemSpacing)
                {
                        int count = toolbarItems.Count;
                        group.Items.Clear();
@@ -404,10 +403,12 @@ namespace Xamarin.Forms.Platform.MacOS
                                        button.Activated += (sender, e) => ((IMenuItemController)element).Activate();
 
                                        button.BezelStyle = NSBezelStyle.TexturedRounded;
-                                       if (!string.IsNullOrEmpty(element.Icon))
-                                               button.Image = new NSImage(element.Icon);
-
-                                       button.SizeToFit();
+                                       _ = element.ApplyNativeImageAsync(ToolbarItem.IconImageSourceProperty, image =>
+                                       {
+                                               if (image != null)
+                                                       button.Image = image;
+                                               button.SizeToFit();
+                                       });
 
                                        button.Enabled = item.Enabled = element.IsEnabled;
                                        element.PropertyChanged -= ToolBarItemPropertyChanged;
index 2e8a949..81fc775 100644 (file)
@@ -76,7 +76,7 @@ namespace Xamarin.Forms.Platform.MacOS
                                UpdateBorder();
                        else if (e.PropertyName == VisualElement.BackgroundColorProperty.PropertyName)
                                UpdateBackgroundVisibility();
-                       else if (e.PropertyName == Button.ImageProperty.PropertyName)
+                       else if (e.PropertyName == Button.ImageSourceProperty.PropertyName)
                                UpdateImage();
                }
 
@@ -112,30 +112,19 @@ namespace Xamarin.Forms.Platform.MacOS
                        Control.Font = Element.Font.ToNSFont();
                }
 
-               async void UpdateImage()
+               void UpdateImage()
                {
-                       IImageSourceHandler handler;
-                       FileImageSource source = Element.Image;
-                       if (source != null && (handler = Internals.Registrar.Registered.GetHandlerForObject<IImageSourceHandler>(source)) != null)
+                       this.ApplyNativeImageAsync(Button.ImageSourceProperty, image =>
                        {
-                               NSImage uiimage;
-                               try
-                               {
-                                       uiimage = await handler.LoadImageAsync(source);
-                               }
-                               catch (OperationCanceledException)
-                               {
-                                       uiimage = null;
-                               }
                                NSButton button = Control;
-                               if (button != null && uiimage != null)
+                               if (button != null && image != null)
                                {
-                                       button.Image = uiimage;
+                                       button.Image = image;
                                        if (!string.IsNullOrEmpty(button.Title))
                                                button.ImagePosition = Element.ToNSCellImagePosition();
+                                       ((IVisualElementController)Element).NativeSizeChanged();
                                }
-                       }
-                       ((IVisualElementController)Element).NativeSizeChanged();
+                       });
                }
 
                void UpdateText()
index 38021ae..e0077f5 100644 (file)
@@ -192,7 +192,7 @@ namespace Xamarin.Forms.Platform.MacOS
                                UpdateCurrentPage();
                        else if (e.PropertyName == VisualElement.BackgroundColorProperty.PropertyName)
                                UpdateBackground();
-                       else if (e.PropertyName == Page.BackgroundImageProperty.PropertyName)
+                       else if (e.PropertyName == Page.BackgroundImageSourceProperty.PropertyName)
                                UpdateBackground();
                }
 
@@ -201,16 +201,18 @@ namespace Xamarin.Forms.Platform.MacOS
                        if (View.Layer == null)
                                return;
 
-                       string bgImage = ((Page)Element).BackgroundImage;
-
-                       if (!string.IsNullOrEmpty(bgImage))
+                       this.ApplyNativeImageAsync(Page.BackgroundImageSourceProperty, image =>
                        {
-                               View.Layer.BackgroundColor = NSColor.FromPatternImage(NSImage.ImageNamed(bgImage)).CGColor;
-                               return;
-                       }
-
-                       Color bgColor = Element.BackgroundColor;
-                       View.Layer.BackgroundColor = bgColor.IsDefault ? NSColor.White.CGColor : bgColor.ToCGColor();
+                               if (image != null)
+                               {
+                                       View.Layer.BackgroundColor = NSColor.FromPatternImage(image).CGColor;
+                               }
+                               else
+                               {
+                                       Color bgColor = Element.BackgroundColor;
+                                       View.Layer.BackgroundColor = bgColor.IsDefault ? NSColor.White.CGColor : bgColor.ToCGColor();
+                               }
+                       });
                }
 
                void UpdateCurrentPage(bool animated = true)
index 1cc8b53..b0a3951 100644 (file)
@@ -92,36 +92,20 @@ namespace Xamarin.Forms.Platform.MacOS
                                Control.Layer.Contents = null;
                        }
 
-                       IImageSourceHandler handler;
-
-                       Element.SetIsLoading(true);
+                       if (!_isDisposed)
+                               Element.SetIsLoading(true);
 
-                       if (source != null && (handler = Internals.Registrar.Registered.GetHandlerForObject<IImageSourceHandler>(source)) != null)
+                       using (var nsImage = await source.GetNativeImageAsync())
                        {
-                               NSImage nsImage;
-                               try
-                               {
-                                       nsImage = await handler.LoadImageAsync(source, scale: (float)NSScreen.MainScreen.BackingScaleFactor);
-                               }
-                               catch (OperationCanceledException)
-                               {
-                                       nsImage = null;
-                               }
-
-                               var imageView = Control;
-                               if (imageView != null)
-                                       imageView.Layer.Contents = nsImage != null ? nsImage.CGImage : null;
-                               if (nsImage != null)
-                                       nsImage.Dispose();
-
-                               if (!_isDisposed)
-                                       ((IVisualElementController)Element).NativeSizeChanged();
+                               if (!_isDisposed && Control is NSView imageView)
+                                       imageView.Layer.Contents = nsImage?.CGImage;
                        }
-                       else
-                               Control.Layer.Contents = null;
 
                        if (!_isDisposed)
+                       {
+                               ((IVisualElementController)Element).NativeSizeChanged();
                                Element.SetIsLoading(false);
+                       }
                }
 
                void SetOpacity()
index 1598793..b32f77d 100644 (file)
@@ -162,7 +162,7 @@ namespace Xamarin.Forms.Platform.MacOS
                {
                        if (e.PropertyName == VisualElement.BackgroundColorProperty.PropertyName)
                                UpdateBackground();
-                       else if (e.PropertyName == Page.BackgroundImageProperty.PropertyName)
+                       else if (e.PropertyName == Page.BackgroundImageSourceProperty.PropertyName)
                                UpdateBackground();
                        else if (e.PropertyName == Page.TitleProperty.PropertyName)
                                UpdateTitle();
@@ -172,14 +172,18 @@ namespace Xamarin.Forms.Platform.MacOS
 
                void UpdateBackground()
                {
-                       string bgImage = ((Page)Element).BackgroundImage;
-                       if (!string.IsNullOrEmpty(bgImage))
+                       this.ApplyNativeImageAsync(Page.BackgroundImageSourceProperty, bgImage =>
                        {
-                               View.Layer.BackgroundColor = NSColor.FromPatternImage(NSImage.ImageNamed(bgImage)).CGColor;
-                               return;
-                       }
-                       Color bgColor = Element.BackgroundColor;
-                       View.Layer.BackgroundColor = bgColor.IsDefault ? NSColor.White.CGColor : bgColor.ToCGColor();
+                               if (bgImage != null)
+                               {
+                                       View.Layer.BackgroundColor = NSColor.FromPatternImage(bgImage).CGColor;
+                               }
+                               else
+                               {
+                                       Color bgColor = Element.BackgroundColor;
+                                       View.Layer.BackgroundColor = bgColor.IsDefault ? NSColor.White.CGColor : bgColor.ToCGColor();
+                               }
+                       });
                }
 
                void UpdateTitle()
index e3c3ea6..95d1973 100644 (file)
@@ -200,20 +200,20 @@ namespace Xamarin.Forms.Platform.MacOS
                protected virtual NSTabViewItem GetTabViewItem(Page page, IVisualElementRenderer pageRenderer)
                {
                        var tvi = new NSTabViewItem { ViewController = pageRenderer.ViewController, Label = page.Title ?? "" };
-                       if (!string.IsNullOrEmpty (page.Icon)) {
-                               var image = GetTabViewItemIcon (page.Icon);
-                               if (image != null)
-                                       tvi.Image = image;
-                       }
+                       _ = this.ApplyNativeImageAsync(page, Page.IconImageSourceProperty, icon =>
+                       {
+                               if (icon != null)
+                               {
+                                       var image = GetTabViewItemIcon(icon);
+                                       if (image != null)
+                                               tvi.Image = image;
+                               }
+                       });
                        return tvi;
                }
 
-               protected virtual NSImage GetTabViewItemIcon(string imageName)
+               protected virtual NSImage GetTabViewItemIcon(NSImage image)
                {
-                       var image = NSImage.ImageNamed (imageName);
-                       if(image == null)
-                               image = new NSImage (imageName);
-
                        if (image == null)
                                return null;
 
@@ -239,21 +239,22 @@ namespace Xamarin.Forms.Platform.MacOS
                                var index = TabbedPage.GetIndex(page);
                                TabViewItems[index].Label = page.Title;
                        }
-                       else if (e.PropertyName == Page.IconProperty.PropertyName)
+                       else if (e.PropertyName == Page.IconImageSourceProperty.PropertyName)
                        {
                                var page = (Page)sender;
 
                                var index = TabbedPage.GetIndex(page);
-                               TabViewItems[index].Label = page.Title;
+                               var item = TabViewItems[index];
 
-                               if (!string.IsNullOrEmpty(page.Icon))
-                               {
-                                       TabViewItems[index].Image = new NSImage(page.Icon);
-                               }
-                               else if (TabViewItems[index].Image != null)
+                               item.Label = page.Title;
+
+                               _ = this.ApplyNativeImageAsync(page, Page.IconImageSourceProperty, icon =>
                                {
-                                       TabViewItems[index].Image = new NSImage();
-                               }
+                                       if (icon != null)
+                                               item.Image = icon;
+                                       else if (item.Image != null)
+                                               item.Image = new NSImage();
+                               });
                        }
                }
 
diff --git a/Xamarin.Forms.Platform.Tizen/Extensions/ImageExtensions.cs b/Xamarin.Forms.Platform.Tizen/Extensions/ImageExtensions.cs
new file mode 100644 (file)
index 0000000..7e49b75
--- /dev/null
@@ -0,0 +1,8 @@
+namespace Xamarin.Forms.Platform.Tizen
+{
+       internal static class ImageExtensions
+       {
+               internal static bool IsNullOrEmpty(this ImageSource imageSource) =>
+                       imageSource == null || imageSource.IsEmpty;
+       }
+}
index 2101816..716b80b 100644 (file)
@@ -68,7 +68,7 @@ namespace Xamarin.Forms.Platform.Tizen.Native
 
                void UpdateIcon()
                {
-                       if (string.IsNullOrEmpty(_item.Icon))
+                       if (_item.IconImageSource.IsNullOrEmpty())
                        {
                                //On 5.0, the part content should be removed before the style is changed, otherwise, EFL does not remove the part content.
                                Image = null;
@@ -79,14 +79,14 @@ namespace Xamarin.Forms.Platform.Tizen.Native
                                // In reverse, the style should be set before setting the part content.
                                UpdateStyle();
                                Native.Image iconImage = new Native.Image(Forms.NativeParent);
-                               var task = iconImage.LoadFromImageSourceAsync(_item.Icon);
+                               _ = iconImage.LoadFromImageSourceAsync(_item.IconImageSource);
                                Image = iconImage;
                        }
                }
 
                void UpdateStyle()
                {
-                       if (string.IsNullOrEmpty(_item.Icon))
+                       if (_item.IconImageSource.IsNullOrEmpty())
                        {
                                if (string.IsNullOrEmpty(_item.Text))
                                {
index f9ad55d..3fcbe38 100644 (file)
@@ -12,7 +12,7 @@ namespace Xamarin.Forms.Platform.Tizen
                        RegisterPropertyHandler(Button.FontSizeProperty, UpdateFontSize);
                        RegisterPropertyHandler(Button.FontAttributesProperty, UpdateFontAttributes);
                        RegisterPropertyHandler(Button.TextColorProperty, UpdateTextColor);
-                       RegisterPropertyHandler(Button.ImageProperty, UpdateBitmap);
+                       RegisterPropertyHandler(Button.ImageSourceProperty, UpdateBitmap);
                        RegisterPropertyHandler(Button.BorderColorProperty, UpdateBorder);
                        RegisterPropertyHandler(Button.CornerRadiusProperty, UpdateBorder);
                        RegisterPropertyHandler(Button.BorderWidthProperty, UpdateBorder);
@@ -105,10 +105,10 @@ namespace Xamarin.Forms.Platform.Tizen
 
                void UpdateBitmap()
                {
-                       if (!string.IsNullOrEmpty(Element.Image))
+                       if (!Element.ImageSource.IsNullOrEmpty())
                        {
                                Control.Image = new Native.Image(Control);
-                               var task = Control.Image.LoadFromImageSourceAsync(Element.Image);
+                               _ = Control.Image.LoadFromImageSourceAsync(Element.ImageSource);
                        }
                        else
                        {
index 4477d36..a831753 100644 (file)
@@ -18,7 +18,7 @@ namespace Xamarin.Forms.Platform.Tizen
                /// </summary>
                public PageRenderer()
                {
-                       RegisterPropertyHandler(Page.BackgroundImageProperty, UpdateBackgroundImage);
+                       RegisterPropertyHandler(Page.BackgroundImageSourceProperty, UpdateBackgroundImage);
                }
 
                protected override void OnElementChanged(ElementChangedEventArgs<Page> e)
@@ -63,13 +63,16 @@ namespace Xamarin.Forms.Platform.Tizen
 
                void UpdateBackgroundImage(bool initiaize)
                {
-                       if (initiaize && string.IsNullOrWhiteSpace(Element.BackgroundImage))
+                       if (initiaize && Element.BackgroundImageSource.IsNullOrEmpty())
                                return;
 
-                       if (string.IsNullOrWhiteSpace(Element.BackgroundImage))
+                       // TODO: investigate if we can use the other image source types: stream, font, uri
+
+                       var bgImage = Element.BackgroundImageSource as FileImageSource;
+                       if (bgImage.IsNullOrEmpty())
                                _page.File = null;
                        else
-                               _page.File = ResourcePath.GetPath(Element.BackgroundImage);
+                               _page.File = ResourcePath.GetPath(bgImage);
                }
 
                void OnLayoutUpdated(object sender, Native.LayoutEventArgs e)
index 09b06d6..e3c2e7c 100644 (file)
@@ -271,13 +271,19 @@ namespace Xamarin.Forms.Platform.Tizen
                EToolbarItem AddToolbarItem(Page newItem, int index)
                {
                        EToolbarItem toolbarItem;
+
+                       // TODO: investigate if we can use the other image source types: stream, font, uri
+
+                       var iconSource = newItem.IconImageSource as FileImageSource;
+                       var icon = iconSource.IsNullOrEmpty() ? null : ResourcePath.GetPath(iconSource);
+
                        if (index == 0)
                        {
-                               toolbarItem = _toolbar.Prepend(newItem.Title, string.IsNullOrEmpty(newItem.Icon) ? null : ResourcePath.GetPath(newItem.Icon));
+                               toolbarItem = _toolbar.Prepend(newItem.Title, icon);
                        }
                        else
                        {
-                               toolbarItem = _toolbar.InsertAfter(_toolbarItemList[index - 1], newItem.Title, string.IsNullOrEmpty(newItem.Icon) ? null : ResourcePath.GetPath(newItem.Icon));
+                               toolbarItem = _toolbar.InsertAfter(_toolbarItemList[index - 1], newItem.Title, icon);
                        }
                        _toolbarItemList.Insert(index, toolbarItem);
                        _itemToItemPage.Add(toolbarItem, newItem);
index 0fde30f..8a1426b 100755 (executable)
@@ -36,5 +36,10 @@ namespace Xamarin.Forms.Platform.Tizen
 
                        return res;
                }
+
+               internal static string GetPath(ImageSource icon)
+               {
+                       throw new NotImplementedException();
+               }
        }
 }
index 16fcfdc..9cd312a 100644 (file)
@@ -21,7 +21,7 @@ namespace Xamarin.Forms.Platform.UWP
 
                protected override void OnPropertyChanged(object sender, PropertyChangedEventArgs e)
                {
-                       if (e.PropertyName == VisualElement.BackgroundColorProperty.PropertyName || e.PropertyName == Page.BackgroundImageProperty.PropertyName)
+                       if (e.PropertyName == VisualElement.BackgroundColorProperty.PropertyName || e.PropertyName == Page.BackgroundImageSourceProperty.PropertyName)
                        {
                                UpdateBackground();
                        }
@@ -37,7 +37,7 @@ namespace Xamarin.Forms.Platform.UWP
                                UpdateBackground();
                }
 
-               void UpdateBackground()
+               async void UpdateBackground()
                {
                        if (Element == null)
                                return;
@@ -46,14 +46,10 @@ namespace Xamarin.Forms.Platform.UWP
                        if (element == null)
                                return;
 
-                       string backgroundImage = Element.BackgroundImage;
+                       var backgroundImage = await Element.BackgroundImageSource.ToWindowsImageSourceAsync();
                        if (backgroundImage != null)
                        {
-                               Uri uri;
-                               if (!Uri.TryCreate(backgroundImage, UriKind.RelativeOrAbsolute, out uri) || !uri.IsAbsoluteUri)
-                                       uri = new Uri("ms-appx:///" + backgroundImage);
-
-                               element.SetValue(_backgroundProperty, new ImageBrush { ImageSource = new BitmapImage(uri) });
+                               element.SetValue(_backgroundProperty, new ImageBrush { ImageSource = backgroundImage });
                        }
                        else
                        {
index 72a2073..38160ad 100644 (file)
@@ -79,7 +79,7 @@ namespace Xamarin.Forms.Platform.UWP
                {
                        base.OnElementPropertyChanged(sender, e);
 
-                       if (e.PropertyName == Button.TextProperty.PropertyName || e.PropertyName == Button.ImageProperty.PropertyName)
+                       if (e.PropertyName == Button.TextProperty.PropertyName || e.PropertyName == Button.ImageSourceProperty.PropertyName)
                        {
                                UpdateContent();
                        }
@@ -154,43 +154,53 @@ namespace Xamarin.Forms.Platform.UWP
                        Control.BorderThickness = Element.BorderWidth == (double)Button.BorderWidthProperty.DefaultValue ? new WThickness(3) : new WThickness(Element.BorderWidth);
                }
 
-               void UpdateContent()
+               async void UpdateContent()
                {
                        var text = Element.Text;
-                       var elementImage = Element.Image;
+                       var elementImage = await Element.ImageSource.ToWindowsImageSourceAsync();
 
                        // No image, just the text
                        if (elementImage == null)
                        {
                                Control.Content = text;
+                               Element?.InvalidateMeasureNonVirtual(InvalidationTrigger.RendererReady);
                                return;
                        }
 
-                       var bmp = new BitmapImage(new Uri("ms-appx:///" + elementImage.File));
-
+                       var size = elementImage.GetImageSourceSize();
                        var image = new WImage
                        {
-                               Source = bmp,
+                               Source = elementImage,
                                VerticalAlignment = VerticalAlignment.Center,
                                HorizontalAlignment = HorizontalAlignment.Center,
-                               Stretch = Stretch.Uniform
+                               Stretch = Stretch.Uniform,
+                               Width = size.Width,
+                               Height = size.Height,
                        };
 
-                       bmp.ImageOpened += (sender, args) => {
-                               image.Width = bmp.PixelWidth;
-                               image.Height = bmp.PixelHeight;
-                               Element?.InvalidateMeasureNonVirtual(InvalidationTrigger.RendererReady);
-                       };
+                       // BitmapImage is a special case that has an event when the image is loaded
+                       // when this happens, we want to resize the button
+                       if (elementImage is BitmapImage bmp)
+                       {
+                               bmp.ImageOpened += (sender, args) => {
+                                       var actualSize = bmp.GetImageSourceSize();
+                                       image.Width = actualSize.Width;
+                                       image.Height = actualSize.Height;
+                                       Element?.InvalidateMeasureNonVirtual(InvalidationTrigger.RendererReady);
+                               };
+                       }
 
                        // No text, just the image
                        if (string.IsNullOrEmpty(text))
                        {
                                Control.Content = image;
+                               Element?.InvalidateMeasureNonVirtual(InvalidationTrigger.RendererReady);
                                return;
                        }
 
                        // Both image and text, so we need to build a container for them
                        Control.Content = CreateContentContainer(Element.ContentLayout, image, text);
+                       Element?.InvalidateMeasureNonVirtual(InvalidationTrigger.RendererReady);
                }
 
                static StackPanel CreateContentContainer(Button.ButtonContentLayout layout, WImage image, string text)
index fec0a2e..b4ad96e 100644 (file)
@@ -1,12 +1,17 @@
 ï»¿using System;
 using System.Runtime.CompilerServices;
+using System.Threading;
 using System.Threading.Tasks;
 using Windows.Foundation;
 using Windows.UI.Xaml;
+using Windows.UI.Xaml.Controls;
 using Windows.UI.Xaml.Input;
+using Windows.UI.Xaml.Media;
 using Xamarin.Forms.Internals;
 using WImageSource = Windows.UI.Xaml.Media.ImageSource;
 using UwpScrollBarVisibility = Windows.UI.Xaml.Controls.ScrollBarVisibility;
+using Windows.UI.Xaml.Media.Imaging;
+using Microsoft.Graphics.Canvas.UI.Xaml;
 
 namespace Xamarin.Forms.Platform.UWP
 {
@@ -32,27 +37,6 @@ namespace Xamarin.Forms.Platform.UWP
                        self.SetBinding(property, new Windows.UI.Xaml.Data.Binding { Path = new PropertyPath(path), Converter = converter });
                }
 
-               public static async Task<WImageSource> ToWindowsImageSource(this ImageSource source)
-               {
-                       IImageSourceHandler handler;
-                       if (source != null && (handler = Registrar.Registered.GetHandlerForObject<IImageSourceHandler>(source)) != null)
-                       {
-                               try
-                               {
-                                       return await handler.LoadImageAsync(source);
-                               }
-                               catch (OperationCanceledException)
-                               {
-                                       return null;
-                               }
-
-                       }
-                       else
-                       {
-                               return null;
-                       }
-               }
-
                internal static InputScopeNameValue GetKeyboardButtonType(this ReturnType returnType)
                {
                        switch (returnType)
index d2c5213..824d707 100644 (file)
 ï»¿using System;
 using Microsoft.Graphics.Canvas.UI.Xaml;
 using Windows.UI.Xaml.Media.Imaging;
-using WinImageSource = Windows.UI.Xaml.Media.ImageSource;
+using System.Runtime.CompilerServices;
+using System.Threading;
+using System.Threading.Tasks;
+using Windows.Foundation;
+using Windows.UI.Xaml;
+using Windows.UI.Xaml.Controls;
+using Windows.UI.Xaml.Input;
+using Windows.UI.Xaml.Media;
+using Xamarin.Forms.Internals;
+using WImageSource = Windows.UI.Xaml.Media.ImageSource;
 
 namespace Xamarin.Forms.Platform.UWP
 {
        internal static class ImageExtensions
        {
-               public static SizeRequest GetDesiredSize(this WinImageSource source)
+               public static Size GetImageSourceSize(this WImageSource source)
                {
-                       if (source is BitmapSource bitmap)
+                       if (source is null)
                        {
-                               return new SizeRequest(
-                                       new Size
-                                       {
-                                               Width = bitmap.PixelWidth,
-                                               Height = bitmap.PixelHeight
-                                       });
+                               return Size.Zero;
+                       }
+                       else if (source is BitmapSource bitmap)
+                       {
+                               return new Size
+                               {
+                                       Width = bitmap.PixelWidth,
+                                       Height = bitmap.PixelHeight
+                               };
                        }
                        else if (source is CanvasImageSource canvas)
                        {
-                               return new SizeRequest(
-                                       new Size
-                                       {
-                                               Width = canvas.SizeInPixels.Width,
-                                               Height = canvas.SizeInPixels.Height
-                                       });
+                               return new Size
+                               {
+                                       Width = canvas.Size.Width,
+                                       Height = canvas.Size.Height
+                               };
                        }
-                       else
+
+                       throw new InvalidCastException($"\"{source.GetType().FullName}\" is not supported.");
+               }
+
+               public static IconElement ToWindowsIconElement(this ImageSource source)
+               {
+                       return source.ToWindowsIconElementAsync().GetAwaiter().GetResult();
+               }
+
+               public static async Task<IconElement> ToWindowsIconElementAsync(this ImageSource source, CancellationToken cancellationToken = default(CancellationToken))
+               {
+                       if (source == null || source.IsEmpty)
+                               return null;
+
+                       var handler = Registrar.Registered.GetHandlerForObject<IIconElementHandler>(source);
+                       if (handler == null)
+                               return null;
+
+                       try
                        {
-                               throw new InvalidCastException($"\"{source.GetType().FullName}\" is not supported.");
+                               return await handler.LoadIconElementAsync(source, cancellationToken);
                        }
+                       catch (OperationCanceledException)
+                       {
+                               // no-op
+                       }
+
+                       return null;
+               }
+
+               public static WImageSource ToWindowsImageSource(this ImageSource source)
+               {
+                       return source.ToWindowsImageSourceAsync().GetAwaiter().GetResult();
+               }
+
+               public static async Task<WImageSource> ToWindowsImageSourceAsync(this ImageSource source, CancellationToken cancellationToken = default(CancellationToken))
+               {
+                       if (source == null || source.IsEmpty)
+                               return null;
+
+                       var handler = Registrar.Registered.GetHandlerForObject<IImageSourceHandler>(source);
+                       if (handler == null)
+                               return null;
+
+                       try
+                       {
+                               return await handler.LoadImageAsync(source, cancellationToken);
+                       }
+                       catch (OperationCanceledException)
+                       {
+                               Log.Warning("Image loading", "Image load cancelled");
+                       }
+                       catch (Exception ex)
+                       {
+                               Log.Warning("Image loading", $"Image load failed: {ex}");
+                       }
+
+                       return null;
                }
        }
 }
index 486bef9..cc2c9d2 100644 (file)
@@ -1,11 +1,12 @@
 ï»¿using System;
 using System.Threading;
 using System.Threading.Tasks;
+using Windows.UI.Xaml.Controls;
 using Windows.UI.Xaml.Media.Imaging;
 
 namespace Xamarin.Forms.Platform.UWP
 {
-       public sealed class FileImageSourceHandler : IImageSourceHandler
+       public sealed class FileImageSourceHandler : IImageSourceHandler, IIconElementHandler
        {
                public Task<Windows.UI.Xaml.Media.ImageSource> LoadImageAsync(ImageSource imagesource, CancellationToken cancellationToken = new CancellationToken())
                {
@@ -19,5 +20,18 @@ namespace Xamarin.Forms.Platform.UWP
 
                        return Task.FromResult(image);
                }
+
+               public Task<IconElement> LoadIconElementAsync(ImageSource imagesource, CancellationToken cancellationToken = default(CancellationToken))
+               {
+                       IconElement image = null;
+
+                       if (imagesource is FileImageSource filesource)
+                       {
+                               string file = filesource.File;
+                               image = new BitmapIcon { UriSource = new Uri("ms-appx:///" + file) };
+                       }
+
+                       return Task.FromResult(image);
+               }
        }
 }
\ No newline at end of file
index 1503704..a92d95d 100644 (file)
@@ -4,10 +4,12 @@ using System.Threading.Tasks;
 using Microsoft.Graphics.Canvas;
 using Microsoft.Graphics.Canvas.Text;
 using Microsoft.Graphics.Canvas.UI.Xaml;
+using Windows.UI.Xaml.Controls;
+using Windows.UI.Xaml.Media;
 
 namespace Xamarin.Forms.Platform.UWP
 {
-       public sealed class FontImageSourceHandler : IImageSourceHandler
+       public sealed class FontImageSourceHandler : IImageSourceHandler, IIconElementHandler
        {
                float _minimumDpi = 300;
 
@@ -32,10 +34,32 @@ namespace Xamarin.Forms.Platform.UWP
                                        Options = CanvasDrawTextOptions.Default,
                                };
                                var iconcolor = (fontsource.Color != Color.Default ? fontsource.Color : Color.White).ToWindowsColor();
-                               ds.DrawText(fontsource.Glyph, textFormat.FontSize / 2, 0, iconcolor, textFormat);
+
+                               // offset by 1 as we added a 1 inset
+                               var x = textFormat.FontSize / 2f + 1f;
+                               var y = -1f;
+                               ds.DrawText(fontsource.Glyph, x, y, iconcolor, textFormat);
                        }
 
                        return Task.FromResult((Windows.UI.Xaml.Media.ImageSource)imageSource);
                }
+
+               public Task<IconElement> LoadIconElementAsync(ImageSource imagesource, CancellationToken cancellationToken = default(CancellationToken))
+               {
+                       IconElement image = null;
+
+                       if (imagesource is FontImageSource fontImageSource)
+                       {
+                               image = new FontIcon
+                               {
+                                       Glyph = fontImageSource.Glyph,
+                                       FontFamily = new FontFamily(fontImageSource.FontFamily),
+                                       FontSize = fontImageSource.Size,
+                                       Foreground = fontImageSource.Color.ToBrush()
+                               };
+                       }
+
+                       return Task.FromResult(image);
+               }
        }
 }
index 8ea586a..a8b6dc6 100644 (file)
@@ -2,6 +2,7 @@
 using Windows.UI.Xaml;
 using Windows.UI.Xaml.Controls.Primitives;
 using Windows.UI.Xaml.Media.Imaging;
+using WImageSource = Windows.UI.Xaml.Media.ImageSource;
 
 namespace Xamarin.Forms.Platform.UWP
 {
@@ -11,7 +12,7 @@ namespace Xamarin.Forms.Platform.UWP
                internal Thumb ImageThumb { get; set; }
 
                public static readonly DependencyProperty ThumbImageProperty = 
-                       DependencyProperty.Register(nameof(ThumbImage), typeof(BitmapImage), 
+                       DependencyProperty.Register(nameof(ThumbImage), typeof(WImageSource), 
                        typeof(FormsSlider), new PropertyMetadata(null, PropertyChangedCallback));
 
                static void PropertyChangedCallback(DependencyObject dependencyObject,
@@ -40,9 +41,9 @@ namespace Xamarin.Forms.Platform.UWP
                        }
                }
 
-               public BitmapImage ThumbImage
+               public WImageSource ThumbImage
                {
-                       get { return (BitmapImage)GetValue(ThumbImageProperty); }
+                       get { return (WImageSource)GetValue(ThumbImageProperty); }
                        set { SetValue(ThumbImageProperty, value); }
                }
 
diff --git a/Xamarin.Forms.Platform.UAP/IIconElementHandler.cs b/Xamarin.Forms.Platform.UAP/IIconElementHandler.cs
new file mode 100644 (file)
index 0000000..b7117bb
--- /dev/null
@@ -0,0 +1,11 @@
+using System.Threading;
+using System.Threading.Tasks;
+using Windows.UI.Xaml.Controls;
+
+namespace Xamarin.Forms.Platform.UWP
+{
+       public interface IIconElementHandler : IRegisterable
+       {
+               Task<IconElement> LoadIconElementAsync(ImageSource imagesource, CancellationToken cancellationToken = default(CancellationToken));
+       }
+}
index 53b95cc..977e81b 100644 (file)
@@ -54,7 +54,10 @@ namespace Xamarin.Forms.Platform.UWP
 
                        _measured = true;
 
-                       return _image.Source.GetDesiredSize();
+                       // we have to include the padding, otherwise the image is smaller than expected
+                       var padding = new Size(Element.Padding.HorizontalThickness, Element.Padding.VerticalThickness);
+
+                       return new SizeRequest(_image.Source.GetImageSourceSize() + padding);
                }
 
 
index 2e69084..a152df0 100644 (file)
@@ -1,5 +1,6 @@
 using System;
 using System.Threading.Tasks;
+using Xamarin.Forms.Internals;
 
 namespace Xamarin.Forms.Platform.UWP
 {
@@ -7,16 +8,9 @@ namespace Xamarin.Forms.Platform.UWP
        {
                public object Convert(object value, Type targetType, object parameter, string language)
                {
-                       var source = (ImageSource)value;
-                       IImageSourceHandler handler;
-
-                       if (source != null && (handler = Internals.Registrar.Registered.GetHandlerForObject<IImageSourceHandler>(source)) != null)
-                       {
-                               Task<Windows.UI.Xaml.Media.ImageSource> task = handler.LoadImageAsync(source);
-                               return new AsyncValue<Windows.UI.Xaml.Media.ImageSource>(task, null);
-                       }
-
-                       return null;
+                       return value is ImageSource source
+                               ? source.ToWindowsImageSourceAsync().AsAsyncValue()
+                               : null;
                }
 
                public object ConvertBack(object value, Type targetType, object parameter, string language)
index 11c6d3e..f29a374 100644 (file)
@@ -112,33 +112,20 @@ namespace Xamarin.Forms.Platform.UWP
 
                        imageController?.SetIsLoading(true);
 
-                       ImageSource source = imageElement.Source;
-                       IImageSourceHandler handler;
-                       if (source != null && (handler = Registrar.Registered.GetHandlerForObject<IImageSourceHandler>(source)) != null)
+                       try
                        {
-                               Windows.UI.Xaml.Media.ImageSource imagesource;
-
-                               try
-                               {
-                                       imagesource = await handler.LoadImageAsync(source);
-                               }
-                               catch (OperationCanceledException)
-                               {
-                                       imagesource = null;
-                               }
-
-                               // In the time it takes to await the imagesource, some zippy little app
-                               // might have disposed of this Image already.
+                               var imagesource = await imageElement.Source.ToWindowsImageSourceAsync();
+
+                               if (renderer.IsDisposed)
+                                       return;
+
                                if (Control != null)
-                               {
                                        renderer.SetImage(imagesource);
-                               }
 
                                RefreshImage(imageElement as IViewController);
                        }
-                       else
+                       finally
                        {
-                               renderer.SetImage(null);
                                imageController?.SetIsLoading(false);
                        }
                }
index f941558..362bc37 100644 (file)
@@ -29,7 +29,7 @@ namespace Xamarin.Forms.Platform.UWP
 
                        _measured = true;
 
-                       return Control.Source.GetDesiredSize();
+                       return new SizeRequest(Control.Source.GetImageSourceSize());
                }
 
                protected override void Dispose(bool disposing)
@@ -3,13 +3,16 @@ using Windows.UI.Xaml.Controls;
 
 namespace Xamarin.Forms.Platform.UWP
 {
-       internal class FileImageSourcePathConverter : Windows.UI.Xaml.Data.IValueConverter
+       internal class ImageSourceIconElementConverter : Windows.UI.Xaml.Data.IValueConverter
        {
                public object Convert(object value, Type targetType, object parameter, string language)
                {
-                       var source = (FileImageSource)value;
-                       string uri = "ms-appx:///" + (source != null ? source.File : string.Empty);
-                       return new BitmapIcon { UriSource = new Uri(uri) };
+                       // TODO: investigate whether we can use AsyncValye<T> instead of blocking
+
+                       if (value is ImageSource source)
+                               return source.ToWindowsIconElement();
+
+                       return null;
                }
 
                public object ConvertBack(object value, Type targetType, object parameter, string language)
index c13c13a..40080bf 100644 (file)
@@ -343,7 +343,7 @@ namespace Xamarin.Forms.Platform.UWP
                        if (_detail == null)
                                return;
 
-                       Control.DetailTitleIcon = await NavigationPage.GetTitleIcon(GetCurrentPage()).ToWindowsImageSource();
+                       Control.DetailTitleIcon = await NavigationPage.GetTitleIcon(GetCurrentPage()).ToWindowsImageSourceAsync();
                        Control.InvalidateMeasure();
                }
 
index 9a3b59d..83643eb 100644 (file)
@@ -541,7 +541,7 @@ namespace Xamarin.Forms.Platform.UWP
 
                        ImageSource source = NavigationPage.GetTitleIcon(_currentPage);
 
-                       _titleIcon = await source.ToWindowsImageSource();
+                       _titleIcon = await source.ToWindowsImageSourceAsync();
 
                        _container.TitleIcon = _titleIcon;
 
index 8459f68..2f024b4 100644 (file)
@@ -233,7 +233,7 @@ namespace Xamarin.Forms.Platform.UWP
                Page _currentPage;
                readonly NavigationModel _navModel = new NavigationModel();
                readonly ToolbarTracker _toolbarTracker = new ToolbarTracker();
-               readonly FileImageSourcePathConverter _fileImageSourcePathConverter = new FileImageSourcePathConverter();
+               readonly ImageSourceIconElementConverter _imageSourceIconElementConverter = new ImageSourceIconElementConverter();
                Windows.UI.Xaml.Controls.ProgressBar GetBusyIndicator()
                {
                        if (_busyIndicator == null)
@@ -410,12 +410,12 @@ namespace Xamarin.Forms.Platform.UWP
 
                                var button = new AppBarButton();
                                button.SetBinding(AppBarButton.LabelProperty, "Text");
-                               button.SetBinding(AppBarButton.IconProperty, "Icon", _fileImageSourcePathConverter);
+                               button.SetBinding(AppBarButton.IconProperty, "Icon", _imageSourceIconElementConverter);
                                button.Command = new MenuItemCommand(item);
                                button.DataContext = item;
                                button.SetValue(NativeAutomationProperties.AutomationIdProperty, item.AutomationId);
                                button.SetAutomationPropertiesName(item);
-                               button.SetAutomationPropertiesAccessibilityView(item);                                                     
+                               button.SetAutomationPropertiesAccessibilityView(item);
                                button.SetAutomationPropertiesHelpText(item);
                                button.SetAutomationPropertiesLabeledBy(item);
 
@@ -509,9 +509,11 @@ namespace Xamarin.Forms.Platform.UWP
                        if (options.Accept != null)
                                alertDialog.PrimaryButtonText = options.Accept;
 
-                       while (s_currentAlert != null)
+                       var currentAlert = s_currentAlert;
+                       while (currentAlert != null)
                        {
-                               await s_currentAlert;
+                               await currentAlert;
+                               currentAlert = s_currentAlert;
                        }
 
                        s_currentAlert = ShowAlert(alertDialog);
index 79c25ae..4118d41 100644 (file)
@@ -30,7 +30,7 @@
        <uwp:TextAlignmentToHorizontalAlignmentConverter x:Key="AlignmentConverter" />
        <uwp:KeyboardConverter x:Key="KeyboardConverter" />
        <uwp:MasterBackgroundConverter x:Key="MasterBackgroundConverter" />
-       <uwp:FileImageSourcePathConverter x:Key="FileImageSourcePathConverter" />
+       <uwp:ImageSourceIconElementConverter x:Key="ImageSourceIconElementConverter" />
        <x:Double x:Key="TitleBarHeight">48</x:Double>
 
        <DataTemplate x:Key="PushPinTemplate">
index 7155767..d6f0fc3 100644 (file)
@@ -143,7 +143,7 @@ namespace Xamarin.Forms.Platform.UWP
                                UpdateMaximumTrackColor();
                        else if (e.PropertyName == Slider.ThumbColorProperty.PropertyName)
                                UpdateThumbColor();
-                       else if (e.PropertyName == Slider.ThumbImageProperty.PropertyName)
+                       else if (e.PropertyName == Slider.ThumbImageSourceProperty.PropertyName)
                                UpdateThumbImage();
                }
 
@@ -165,14 +165,14 @@ namespace Xamarin.Forms.Platform.UWP
                                () => thumb.Background, brush => thumb.Background = brush);
                }
 
-               void UpdateThumbImage()
+               async void UpdateThumbImage()
                {
                        if (Element == null || Control == null)
                        {
                                return;
                        }
 
-                       var thumbImage = Element.ThumbImage;
+                       var thumbImage = Element.ThumbImageSource;
 
                        if (thumbImage == null)
                        {
@@ -180,7 +180,7 @@ namespace Xamarin.Forms.Platform.UWP
                                return;
                        }
 
-                       Control.ThumbImage = new BitmapImage(new Uri($"ms-appx:///{thumbImage.File}"));
+                       Control.ThumbImage = await thumbImage.ToWindowsImageSourceAsync();
                }
 
                protected override void UpdateBackgroundColor()
index faf80d9..d5bc726 100644 (file)
@@ -426,9 +426,6 @@ namespace Xamarin.Forms.Platform.UWP
                        if (Control == null || Element == null)
                                return;
 
-                       if (!Element.IsSet(Specifics.HeaderIconsEnabledProperty))
-                               return;
-
                        bool headerIconsEnabled = Element.OnThisPlatform().GetHeaderIconsEnabled();
                        bool invalidateMeasure = false;
 
index 0c58d7a..7f2ec6c 100644 (file)
     <Compile Include="WindowsPlatformServices.cs" />
     <Compile Include="WindowsResourcesProvider.cs" />
     <Compile Include="ActivityIndicatorRenderer.cs" />
-    <Compile Include="AsyncValue.cs" />
     <Compile Include="BackgroundTracker.cs" />
     <Compile Include="BoolToVisibilityConverter.cs" />
     <Compile Include="BoxViewRenderer.cs" />
     <Compile Include="ExportRendererAttribute.cs" />
     <Compile Include="Extensions.cs" />
     <Compile Include="FileImageSourceHandler.cs" />
-    <Compile Include="FileImageSourcePathConverter.cs" />
+    <Compile Include="ImageSourceIconElementConverter.cs" />
     <Compile Include="FontExtensions.cs" />
     <Compile Include="FormsButton.cs" />
     <Compile Include="FrameRenderer.cs" />
     <Compile Include="HeightConverter.cs" />
     <Compile Include="ICellRenderer.cs" />
     <Compile Include="IImageSourceHandler.cs" />
+    <Compile Include="IIconElementHandler.cs" />
     <Compile Include="ImageConverter.cs" />
     <Compile Include="ImageRenderer.cs" />
     <Compile Include="IVisualElementRenderer.cs" />
index 43e6613..25530c0 100644 (file)
@@ -1,9 +1,7 @@
 ï»¿using System;
-using System.Collections.Generic;
 using System.Globalization;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
+using Xamarin.Forms.Internals;
+using WImageSource = System.Windows.Media.ImageSource;
 
 namespace Xamarin.Forms.Platform.WPF
 {
@@ -11,19 +9,10 @@ namespace Xamarin.Forms.Platform.WPF
        {
                public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
                {
-                       var source = (ImageSource)value;
-                       IImageSourceHandler handler;
-                       
-                       if (source != null && (handler = Internals.Registrar.Registered.GetHandlerForObject<IImageSourceHandler>(source)) != null)
-                       {
-                               Task<System.Windows.Media.ImageSource> image = handler.LoadImageAsync(source);
-                               image.Wait();
-                               return image.Result;
-                       }
-
-                       return null;
+                       var task = (value as ImageSource)?.ToWindowsImageSourceAsync();
+                       return task?.AsAsyncValue() ?? AsyncValue<WImageSource>.Null;
                }
-               
+
                public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
                {
                        throw new NotImplementedException();
index d8c492c..8a4aabe 100644 (file)
@@ -2,8 +2,11 @@
 using System.Collections.Generic;
 using System.Linq;
 using System.Text;
+using System.Threading;
 using System.Threading.Tasks;
 using System.Windows.Media;
+using Xamarin.Forms.Internals;
+using WImageSource = System.Windows.Media.ImageSource;
 
 namespace Xamarin.Forms.Platform.WPF
 {
@@ -22,5 +25,35 @@ namespace Xamarin.Forms.Platform.WPF
                                        return Stretch.Uniform;
                        }
                }
+
+               public static WImageSource ToWindowsImageSource(this ImageSource source)
+               {
+                       return source.ToWindowsImageSourceAsync().GetAwaiter().GetResult();
+               }
+
+               public static async Task<WImageSource> ToWindowsImageSourceAsync(this ImageSource source, CancellationToken cancellationToken = default(CancellationToken))
+               {
+                       if (source == null || source.IsEmpty)
+                               return null;
+
+                       var handler = Registrar.Registered.GetHandlerForObject<IImageSourceHandler>(source);
+                       if (handler == null)
+                               return null;
+
+                       try
+                       {
+                               return await handler.LoadImageAsync(source, cancellationToken);
+                       }
+                       catch (OperationCanceledException)
+                       {
+                               Log.Warning("Image loading", "Image load cancelled");
+                       }
+                       catch (Exception ex)
+                       {
+                               Log.Warning("Image loading", $"Image load failed: {ex}");
+                       }
+
+                       return null;
+               }
        }
 }
index 747e0bc..9c6ab1c 100644 (file)
@@ -4,6 +4,7 @@ using System.Windows;
 using System.Windows.Controls;
 using System.Windows.Media;
 using System.Windows.Media.Imaging;
+using Xamarin.Forms.Internals;
 using WButton = System.Windows.Controls.Button;
 using WImage = System.Windows.Controls.Image;
 using WThickness = System.Windows.Thickness;
@@ -45,7 +46,7 @@ namespace Xamarin.Forms.Platform.WPF
                {
                        base.OnElementPropertyChanged(sender, e);
 
-                       if (e.PropertyName == Button.TextProperty.PropertyName || e.PropertyName == Button.ImageProperty.PropertyName)
+                       if (e.PropertyName == Button.TextProperty.PropertyName || e.PropertyName == Button.ImageSourceProperty.PropertyName)
                                UpdateContent();
                        else if (e.PropertyName == Button.TextColorProperty.PropertyName)
                                UpdateTextColor();
@@ -74,21 +75,22 @@ namespace Xamarin.Forms.Platform.WPF
                        Control.BorderThickness = Element.BorderWidth <= 0d ? new WThickness(1) : new WThickness(Element.BorderWidth);
                }
 
-               void UpdateContent()
+               async void UpdateContent()
                {
                        var text = Element.Text;
-                       var elementImage = Element.Image;
+                       var elementImage = await Element.ImageSource.ToWindowsImageSourceAsync();
 
                        // No image, just the text
                        if (elementImage == null)
                        {
                                Control.Content = text;
+                               Element?.InvalidateMeasureNonVirtual(InvalidationTrigger.RendererReady);
                                return;
                        }
 
                        var image = new WImage
                        {
-                               Source = new BitmapImage(new Uri("/" + elementImage.File, UriKind.Relative)),
+                               Source = elementImage,
                                Width = 30,
                                Height = 30,
                                VerticalAlignment = VerticalAlignment.Center,
@@ -99,6 +101,7 @@ namespace Xamarin.Forms.Platform.WPF
                        if (string.IsNullOrEmpty(text))
                        {
                                Control.Content = image;
+                               Element?.InvalidateMeasureNonVirtual(InvalidationTrigger.RendererReady);
                                return;
                        }
 
@@ -142,6 +145,7 @@ namespace Xamarin.Forms.Platform.WPF
                        container.Children.Add(textBlock);
 
                        Control.Content = container;
+                       Element?.InvalidateMeasureNonVirtual(InvalidationTrigger.RendererReady);
                }
 
                void UpdateFont()
index eeceb1c..2b6d7e8 100644 (file)
@@ -78,41 +78,24 @@ namespace Xamarin.Forms.Platform.WPF
                                return;
                        }
 
+                       var source = Element.Source;
+
                        Element.SetIsLoading(true);
-                       
-                       ImageSource source = Element.Source;
-                       IImageSourceHandler handler;
-                       if (source != null && (handler = Registrar.Registered.GetHandlerForObject<IImageSourceHandler>(source)) != null)
+                       try
                        {
-                               System.Windows.Media.ImageSource imagesource;
-
-                               try
-                               {
-                                       imagesource = await handler.LoadImageAsync(source);
-                               }
-                               catch (OperationCanceledException)
-                               {
-                                       imagesource = null;
-                               }
+                               var imagesource = await source.ToWindowsImageSourceAsync();
 
-                               // In the time it takes to await the imagesource, some zippy little app
-                               // might have disposed of this Image already.
-                               if (Control != null)
-                               {
+                               // only set if we are still on the same image
+                               if (Control != null && Element.Source == source)
                                        Control.Source = imagesource;
-                               }
-
-                               RefreshImage();
                        }
-                       else
+                       finally
                        {
-                               Control.Source = null;
-                               Element.SetIsLoading(false);
+                               // only mark as finished if we are still on the same image
+                               if (Element.Source == source)
+                                       Element.SetIsLoading(false);
                        }
-               }
 
-               void RefreshImage()
-               {
                        ((IVisualElementController)Element)?.InvalidateMeasure(InvalidationTrigger.RendererReady);
                }
        }
index b147697..71be0d6 100644 (file)
@@ -40,7 +40,7 @@ namespace Xamarin.Forms.Platform.WPF
                {
                        base.OnElementPropertyChanged(sender, e);
 
-                       if (e.PropertyName == Page.BackgroundImageProperty.PropertyName)
+                       if (e.PropertyName == Page.BackgroundImageSourceProperty.PropertyName)
                                UpdateBackground();
                        else if (e.PropertyName == Page.TitleProperty.PropertyName)
                                UpdateTitle();
@@ -73,21 +73,17 @@ namespace Xamarin.Forms.Platform.WPF
                        this.Control.HasNavigationBar = NavigationPage.GetHasNavigationBar(Element);
                }
 
-               protected override void UpdateBackground()
+               protected override async void UpdateBackground()
                {
-                       string bgImage = Element.BackgroundImage;
-                       if (!string.IsNullOrEmpty(bgImage))
-                       {
-                               ImageBrush imgBrush = new ImageBrush()
-                               {
-                                       ImageSource = new BitmapImage(new Uri(bgImage, UriKind.RelativeOrAbsolute))
-                               };
-                               Control.Background = imgBrush;
-                       }
-                       else
+                       var bgImage = Element.BackgroundImageSource;
+                       if (bgImage == null || bgImage.IsEmpty)
                        {
                                base.UpdateBackground();
+                               return;
                        }
+
+                       var img = await bgImage.ToWindowsImageSourceAsync();
+                       Control.Background = new ImageBrush { ImageSource = img };
                }
                
                void UpdateToolbar()
@@ -99,7 +95,7 @@ namespace Xamarin.Forms.Platform.WPF
                        {
                                var appBar = new FormsAppBarButton() { DataContext = item };
 
-                               var iconBinding = new System.Windows.Data.Binding(nameof(item.Icon))
+                               var iconBinding = new System.Windows.Data.Binding(nameof(item.IconImageSource))
                                {
                                        Converter = new IconConveter()
                                };
index f9931f3..caf8985 100644 (file)
                        </Grid.RowDefinitions>
 
                        <Image Grid.Column="0" Grid.RowSpan="2"
-                               Source="{Binding ImageSource, Converter={StaticResource ImageConverter}}"
+                               DataContext="{Binding ImageSource, Converter={StaticResource ImageConverter}}" Source="{Binding Value}"
                                VerticalAlignment="Center" />
 
                        <TextBlock Grid.Column="1" Grid.Row="0"
index 9238607..6dc9e3b 100644 (file)
@@ -32,17 +32,6 @@ namespace Xamarin.Forms.Platform.MacOS
 #endif
                }
 
-#if __MOBILE__
-               public static UIColor FromPatternImageFromBundle(string bgImage)
-               {
-                       var image = UIImage.FromBundle(bgImage);
-                       if (image == null)
-                               return UIColor.White;
-
-                       return UIColor.FromPatternImage(image);
-               }
-#endif
-
                public static Color ToColor(this UIColor color)
                {
                        nfloat red;
index 98006be..29d9191 100644 (file)
@@ -31,7 +31,7 @@ namespace Xamarin.Forms.Platform.iOS
                                _forceName = forceName;
                                _item = item;
 
-                               if (!string.IsNullOrEmpty(item.Icon?.File) && !forceName)
+                               if (item.IconImageSource != null && !item.IconImageSource.IsEmpty && !forceName)
                                        UpdateIconAndStyle();
                                else
                                        UpdateTextAndStyle();
@@ -60,14 +60,14 @@ namespace Xamarin.Forms.Platform.iOS
                                        UpdateIsEnabled();
                                else if (e.PropertyName == MenuItem.TextProperty.PropertyName)
                                {
-                                       if (string.IsNullOrEmpty(_item.Icon?.File) || _forceName)
+                                       if (_item.IconImageSource == null || _item.IconImageSource.IsEmpty || _forceName)
                                                UpdateTextAndStyle();
                                }
-                               else if (e.PropertyName == MenuItem.IconProperty.PropertyName)
+                               else if (e.PropertyName == MenuItem.IconImageSourceProperty.PropertyName)
                                {
                                        if (!_forceName)
                                        {
-                                               if (!string.IsNullOrEmpty(_item.Icon?.File))
+                                               if (_item.IconImageSource != null && !_item.IconImageSource.IsEmpty)
                                                        UpdateIconAndStyle();
                                                else
                                                        UpdateTextAndStyle();
@@ -81,7 +81,7 @@ namespace Xamarin.Forms.Platform.iOS
 
                        async void UpdateIconAndStyle()
                        {
-                               Image = await _item.Icon.GetNativeImageAsync();
+                               Image = await _item.IconImageSource.GetNativeImageAsync();
                                Style = UIBarButtonItemStyle.Plain;
                        }
 
@@ -130,7 +130,7 @@ namespace Xamarin.Forms.Platform.iOS
                        {
                                if (e.PropertyName == MenuItem.TextProperty.PropertyName)
                                        UpdateText();
-                               else if (e.PropertyName == MenuItem.IconProperty.PropertyName)
+                               else if (e.PropertyName == MenuItem.IconImageSourceProperty.PropertyName)
                                        UpdateIcon();
                                else if (e.PropertyName == MenuItem.IsEnabledProperty.PropertyName)
                                        UpdateIsEnabled();
@@ -143,9 +143,9 @@ namespace Xamarin.Forms.Platform.iOS
                        async void UpdateIcon()
                        {
                                UIImage image = null;
-                               if (!string.IsNullOrEmpty(_item.Icon?.File))
+                               if (_item.IconImageSource != null && !_item.IconImageSource.IsEmpty)
                                {
-                                       image = await _item.Icon.GetNativeImageAsync();
+                                       image = await _item.IconImageSource.GetNativeImageAsync();
                                }
                                ((SecondaryToolbarItemContent)CustomView).Image = image;
                        }
index a45b8db..1f0c699 100644 (file)
@@ -141,7 +141,7 @@ namespace Xamarin.Forms.Platform.iOS
 
                        if (e.PropertyName == Button.PaddingProperty.PropertyName)
                                UpdatePadding();
-                       else if (e.PropertyName == Button.ImageProperty.PropertyName)
+                       else if (e.PropertyName == Button.ImageSourceProperty.PropertyName)
                                _ = UpdateImageAsync();
                        else if (e.PropertyName == Button.TextProperty.PropertyName)
                                UpdateText();
index 86771c6..bada167 100644 (file)
@@ -304,7 +304,7 @@ namespace Xamarin.Forms.Platform.iOS
                                UpdateCurrentPage();
                        else if (e.PropertyName == VisualElement.BackgroundColorProperty.PropertyName)
                                UpdateBackground();
-                       else if (e.PropertyName == Page.BackgroundImageProperty.PropertyName)
+                       else if (e.PropertyName == Page.BackgroundImageSourceProperty.PropertyName)
                                UpdateBackground();
                }
 
@@ -361,17 +361,15 @@ namespace Xamarin.Forms.Platform.iOS
 
                void UpdateBackground()
                {
-                       string bgImage = ((Page)Element).BackgroundImage;
-                       if (!string.IsNullOrEmpty(bgImage))
+                       this.ApplyNativeImageAsync(Page.BackgroundImageSourceProperty, bgImage =>
                        {
-                               View.BackgroundColor = ColorExtensions.FromPatternImageFromBundle(bgImage);
-                               return;
-                       }
-                       Color bgColor = Element.BackgroundColor;
-                       if (bgColor.IsDefault)
-                               View.BackgroundColor = UIColor.White;
-                       else
-                               View.BackgroundColor = bgColor.ToUIColor();
+                               if (bgImage != null)
+                                       View.BackgroundColor = UIColor.FromPatternImage(bgImage);
+                               else if (Element.BackgroundColor.IsDefault)
+                                       View.BackgroundColor = UIColor.White;
+                               else
+                                       View.BackgroundColor = Element.BackgroundColor.ToUIColor();
+                       });
                }
 
                void UpdateCurrentPage(bool animated = true)
index 70283fc..d17d23e 100644 (file)
@@ -7,6 +7,7 @@ using System.Threading;
 using System.Threading.Tasks;
 using Foundation;
 using UIKit;
+using Xamarin.Forms.Internals;
 
 namespace Xamarin.Forms.Platform.iOS
 {
@@ -110,7 +111,7 @@ namespace Xamarin.Forms.Platform.iOS
                                if (Equals(oldSource, source))
                                        return;
 
-                               if (oldSource is FileImageSource && source is FileImageSource && ((FileImageSource)oldSource).File == ((FileImageSource)source).File)
+                               if (oldSource is FileImageSource oldFile && source is FileImageSource newFile && oldFile == newFile)
                                        return;
 
                                renderer.SetImage(null);
@@ -120,14 +121,21 @@ namespace Xamarin.Forms.Platform.iOS
                        try
                        {
                                var uiimage = await source.GetNativeImageAsync();
+
                                if (renderer.IsDisposed)
                                        return;
 
-                               renderer.SetImage(Control == null ? null : uiimage);
+                               // only set if we are still on the same image
+                               if (Control != null && imageElement.Source == source)
+                                       renderer.SetImage(uiimage);
+                               else
+                                       uiimage?.Dispose();
                        }
                        finally
                        {
-                               imageController?.SetIsLoading(false);
+                               // only mark as finished if we are still on the same image
+                               if (imageElement.Source == source)
+                                       imageController?.SetIsLoading(false);
                        }
 
                        (imageElement as IViewController)?.NativeSizeChanged();
@@ -135,20 +143,129 @@ namespace Xamarin.Forms.Platform.iOS
 
                internal static async Task<UIImage> GetNativeImageAsync(this ImageSource source, CancellationToken cancellationToken = default(CancellationToken))
                {
-                       IImageSourceHandler handler;
-                       if (source != null && (handler = Internals.Registrar.Registered.GetHandlerForObject<IImageSourceHandler>(source)) != null)
+                       if (source == null || source.IsEmpty)
+                               return null;
+
+                       var handler = Internals.Registrar.Registered.GetHandlerForObject<IImageSourceHandler>(source);
+                       if (handler == null)
+                               return null;
+
+                       try
+                       {
+                               return await handler.LoadImageAsync(source, scale: (float)UIScreen.MainScreen.Scale, cancelationToken: cancellationToken);
+                       }
+                       catch (OperationCanceledException)
+                       {
+                               Log.Warning("Image loading", "Image load cancelled");
+                       }
+                       catch (Exception ex)
+                       {
+                               Log.Warning("Image loading", $"Image load failed: {ex}");
+                       }
+
+                       return null;
+               }
+
+               internal static Task ApplyNativeImageAsync(this IShellContext shellContext, BindableObject bindable, BindableProperty imageSourceProperty, Action<UIImage> onSet, Action<bool> onLoading = null, CancellationToken cancellationToken = default(CancellationToken))
+               {
+                       _ = shellContext ?? throw new ArgumentNullException(nameof(shellContext));
+                       var renderer = shellContext as IVisualElementRenderer ?? throw new InvalidOperationException($"The shell context {shellContext.GetType()} must be a {typeof(IVisualElementRenderer)}.");
+
+                       return renderer.ApplyNativeImageAsync(bindable, imageSourceProperty, onSet, onLoading, cancellationToken);
+               }
+
+               internal static Task ApplyNativeImageAsync(this IVisualElementRenderer renderer, BindableProperty imageSourceProperty, Action<UIImage> onSet, Action<bool> onLoading = null, CancellationToken cancellationToken = default(CancellationToken))
+               {
+                       return renderer.ApplyNativeImageAsync(null, imageSourceProperty, onSet, onLoading, cancellationToken);
+               }
+
+               internal static async Task ApplyNativeImageAsync(this IVisualElementRenderer renderer, BindableObject bindable, BindableProperty imageSourceProperty, Action<UIImage> onSet, Action<bool> onLoading = null, CancellationToken cancellationToken = default(CancellationToken))
+               {
+                       _ = renderer ?? throw new ArgumentNullException(nameof(renderer));
+                       _ = imageSourceProperty ?? throw new ArgumentNullException(nameof(imageSourceProperty));
+                       _ = onSet ?? throw new ArgumentNullException(nameof(onSet));
+
+                       // TODO: it might be good to make sure the renderer has not been disposed
+
+                       // makse sure things are good before we start
+                       var element = bindable ?? renderer.Element;
+
+                       var nativeRenderer = renderer as IVisualNativeElementRenderer;
+
+                       if (element == null || renderer.NativeView == null || (nativeRenderer != null && nativeRenderer.Control == null))
+                               return;
+
+                       onLoading?.Invoke(true);
+                       if (element.GetValue(imageSourceProperty) is ImageSource initialSource && !initialSource.IsEmpty)
                        {
                                try
                                {
-                                       return await handler.LoadImageAsync(source, scale: (float)UIScreen.MainScreen.Scale, cancelationToken: cancellationToken);
+                                       using (var drawable = await initialSource.GetNativeImageAsync(cancellationToken))
+                                       {
+                                               // TODO: it might be good to make sure the renderer has not been disposed
+
+                                               // we are back, so update the working element
+                                               element = bindable ?? renderer.Element;
+
+                                               // makse sure things are good now that we are back
+                                               if (element == null || renderer.NativeView == null || (nativeRenderer != null && nativeRenderer.Control == null))
+                                                       return;
+
+                                               // only set if we are still on the same image
+                                               if (element.GetValue(imageSourceProperty) == initialSource)
+                                                       onSet(drawable);
+                                       }
                                }
-                               catch (OperationCanceledException ex)
+                               finally
                                {
-                                       Internals.Log.Warning(source.GetType().Name, "Error loading image: {0}", ex);
+                                       if (element != null && onLoading != null)
+                                       {
+                                               // only mark as finished if we are still on the same image
+                                               if (element.GetValue(imageSourceProperty) == initialSource)
+                                                       onLoading.Invoke(false);
+                                       }
                                }
                        }
+                       else
+                       {
+                               onSet(null);
+                               onLoading?.Invoke(false);
+                       }
+               }
 
-                       return null;
+               internal static async Task ApplyNativeImageAsync(this BindableObject bindable, BindableProperty imageSourceProperty, Action<UIImage> onSet, Action<bool> onLoading = null, CancellationToken cancellationToken = default(CancellationToken))
+               {
+                       _ = bindable ?? throw new ArgumentNullException(nameof(bindable));
+                       _ = imageSourceProperty ?? throw new ArgumentNullException(nameof(imageSourceProperty));
+                       _ = onSet ?? throw new ArgumentNullException(nameof(onSet));
+
+                       onLoading?.Invoke(true);
+                       if (bindable.GetValue(imageSourceProperty) is ImageSource initialSource)
+                       {
+                               try
+                               {
+                                       using (var nsimage = await initialSource.GetNativeImageAsync(cancellationToken))
+                                       {
+                                               // only set if we are still on the same image
+                                               if (bindable.GetValue(imageSourceProperty) == initialSource)
+                                                       onSet(nsimage);
+                                       }
+                               }
+                               finally
+                               {
+                                       if (onLoading != null)
+                                       {
+                                               // only mark as finished if we are still on the same image
+                                               if (bindable.GetValue(imageSourceProperty) == initialSource)
+                                                       onLoading.Invoke(false);
+                                       }
+                               }
+                       }
+                       else
+                       {
+                               onSet(null);
+                               onLoading?.Invoke(false);
+                       }
                }
        }
-}
\ No newline at end of file
+}
index 1c1c871..3436edc 100644 (file)
@@ -743,35 +743,36 @@ namespace Xamarin.Forms.Platform.iOS
                                return;
                        }
 
-                       EventHandler handler = (o, e) => masterDetailPage.IsPresented = !masterDetailPage.IsPresented;
-
-                       bool shouldUseIcon = masterDetailPage.Master.Icon != null;
-                       if (shouldUseIcon)
+                       await masterDetailPage.Master.ApplyNativeImageAsync(Page.IconImageSourceProperty, icon =>
                        {
-                               try
+                               if (icon != null)
                                {
-                                       var icon = await masterDetailPage.Master.Icon.GetNativeImageAsync();
-                                       containerController.NavigationItem.LeftBarButtonItem = new UIBarButtonItem(icon, UIBarButtonItemStyle.Plain, handler);
+                                       try
+                                       {
+                                               containerController.NavigationItem.LeftBarButtonItem = new UIBarButtonItem(icon, UIBarButtonItemStyle.Plain, OnItemTapped);
+                                       }
+                                       catch (Exception)
+                                       {
+                                               // Throws Exception otherwise would catch more specific exception type
+                                       }
                                }
-                               catch (Exception)
+
+                               if(icon == null || containerController.NavigationItem.LeftBarButtonItem == null)
                                {
-                                       // Throws Exception otherwise would catch more specific exception type
-                                       shouldUseIcon = false;
+                                       containerController.NavigationItem.LeftBarButtonItem = new UIBarButtonItem(masterDetailPage.Master.Title, UIBarButtonItemStyle.Plain, OnItemTapped);
                                }
-                       }
 
-                       if (!shouldUseIcon)
-                       {
-                               containerController.NavigationItem.LeftBarButtonItem = new UIBarButtonItem(masterDetailPage.Master.Title, UIBarButtonItemStyle.Plain, handler);
-                       }
-                       if (containerController.NavigationItem.LeftBarButtonItem != null)
-                       {
                                if (masterDetailPage != null && !string.IsNullOrEmpty(masterDetailPage.AutomationId))
                                        SetAutomationId(containerController.NavigationItem.LeftBarButtonItem, $"btn_{masterDetailPage.AutomationId}");
 #if __MOBILE__
                                containerController.NavigationItem.LeftBarButtonItem.SetAccessibilityHint(masterDetailPage);
                                containerController.NavigationItem.LeftBarButtonItem.SetAccessibilityLabel(masterDetailPage);
 #endif
+                       });
+
+                       void OnItemTapped(object sender, EventArgs e)
+                       {
+                               masterDetailPage.IsPresented = !masterDetailPage.IsPresented;
                        }
                }
 
@@ -1086,7 +1087,7 @@ namespace Xamarin.Forms.Platform.iOS
                                if (page == null)
                                        return;
 
-                               FileImageSource titleIcon = NavigationPage.GetTitleIcon(page);
+                               ImageSource titleIcon = NavigationPage.GetTitleIcon(page);
                                View titleView = NavigationPage.GetTitleView(page);
                                bool needContainer = titleView != null || titleIcon != null;
 
@@ -1117,12 +1118,12 @@ namespace Xamarin.Forms.Platform.iOS
                                }
                        }
 
-                       async void UpdateTitleImage(Container titleViewContainer, FileImageSource titleIcon)
+                       async void UpdateTitleImage(Container titleViewContainer, ImageSource titleIcon)
                        {
                                if (titleViewContainer == null)
                                        return;
 
-                               if (string.IsNullOrWhiteSpace(titleIcon))
+                               if (titleIcon == null || titleIcon.IsEmpty)
                                {
                                        titleViewContainer.Icon = null;
                                }
index afe427b..f698d39 100644 (file)
@@ -283,7 +283,7 @@ namespace Xamarin.Forms.Platform.iOS
                {
                        if (e.PropertyName == VisualElement.BackgroundColorProperty.PropertyName)
                                UpdateBackground();
-                       else if (e.PropertyName == Page.BackgroundImageProperty.PropertyName)
+                       else if (e.PropertyName == Page.BackgroundImageSourceProperty.PropertyName)
                                UpdateBackground();
                        else if (e.PropertyName == Page.TitleProperty.PropertyName)
                                UpdateTitle();
@@ -410,17 +410,18 @@ namespace Xamarin.Forms.Platform.iOS
                        if (NativeView == null)
                                return;
 
-                       string bgImage = ((Page)Element).BackgroundImage;
-                       if (!string.IsNullOrEmpty(bgImage))
+                       _ = this.ApplyNativeImageAsync(Page.BackgroundImageSourceProperty, bgImage =>
                        {
-                               NativeView.BackgroundColor = ColorExtensions.FromPatternImageFromBundle(bgImage);
-                               return;
-                       }
-                       Color bgColor = Element.BackgroundColor;
-                       if (bgColor.IsDefault)
-                               NativeView.BackgroundColor = UIColor.White;
-                       else
-                               NativeView.BackgroundColor = bgColor.ToUIColor();
+                               if (NativeView == null)
+                                       return;
+
+                               if (bgImage != null)
+                                       NativeView.BackgroundColor = UIColor.FromPatternImage(bgImage);
+                               else if (Element.BackgroundColor.IsDefault)
+                                       NativeView.BackgroundColor = UIColor.White;
+                               else
+                                       NativeView.BackgroundColor = Element.BackgroundColor.ToUIColor();
+                       });
                }
 
                void UpdateTitle()
index 5113068..9886145 100644 (file)
@@ -219,7 +219,7 @@ namespace Xamarin.Forms.Platform.iOS
 
                void HandleMasterPropertyChanged(object sender, PropertyChangedEventArgs e)
                {
-                       if (e.PropertyName == Page.IconProperty.PropertyName || e.PropertyName == Page.TitleProperty.PropertyName)
+                       if (e.PropertyName == Page.IconImageSourceProperty.PropertyName || e.PropertyName == Page.TitleProperty.PropertyName)
                                UpdateLeftBarButton();
                }
 
@@ -233,7 +233,7 @@ namespace Xamarin.Forms.Platform.iOS
                                UpdatePanGesture();
                        else if (e.PropertyName == VisualElement.BackgroundColorProperty.PropertyName)
                                UpdateBackground();
-                       else if (e.PropertyName == Page.BackgroundImageProperty.PropertyName)
+                       else if (e.PropertyName == Page.BackgroundImageSourceProperty.PropertyName)
                                UpdateBackground();
                }
 
@@ -301,12 +301,15 @@ namespace Xamarin.Forms.Platform.iOS
 
                void UpdateBackground()
                {
-                       if (!string.IsNullOrEmpty(((Page)Element).BackgroundImage))
-                               View.BackgroundColor = ColorExtensions.FromPatternImageFromBundle(((Page)Element).BackgroundImage);
-                       else if (Element.BackgroundColor == Color.Default)
-                               View.BackgroundColor = UIColor.White;
-                       else
-                               View.BackgroundColor = Element.BackgroundColor.ToUIColor();
+                       _ = this.ApplyNativeImageAsync(Page.BackgroundImageSourceProperty, bgImage =>
+                       {
+                               if (bgImage != null)
+                                       View.BackgroundColor = UIColor.FromPatternImage(bgImage);
+                               else if (Element.BackgroundColor == Color.Default)
+                                       View.BackgroundColor = UIColor.White;
+                               else
+                                       View.BackgroundColor = Element.BackgroundColor.ToUIColor();
+                       });
                }
 
                void UpdateMasterDetailContainers()
index feedfcb..1e2ef21 100644 (file)
@@ -313,11 +313,13 @@ namespace Xamarin.Forms.Platform.iOS
                        ((IShellSectionController)ShellSection).AddDisplayedPageObserver(this, OnDisplayedPageChanged);
                }
 
-               protected virtual async void UpdateTabBarItem()
+               protected virtual void UpdateTabBarItem()
                {
                        Title = ShellSection.Title;
-                       var icon = await ShellSection.Icon.GetNativeImageAsync();
-                       TabBarItem = new UITabBarItem(ShellSection.Title, icon, null);
+                       _ = _context.ApplyNativeImageAsync(ShellSection, ShellSection.IconProperty, icon =>
+                       {
+                               TabBarItem = new UITabBarItem(ShellSection.Title, icon, null);
+                       });
                }
 
                void DisposePage(Page page)
index f200acd..80c5dfb 100644 (file)
@@ -76,7 +76,8 @@ namespace Xamarin.Forms.Platform.iOS
                {
                        UpdateMinimumTrackColor();
                        UpdateMaximumTrackColor();
-                       if (!string.IsNullOrEmpty(Element.ThumbImage))
+                       var thumbImage = Element.ThumbImageSource;
+                       if (thumbImage != null && !thumbImage.IsEmpty)
                        {
                                UpdateThumbImage();
                        }
@@ -119,12 +120,14 @@ namespace Xamarin.Forms.Platform.iOS
                        }
                }
 
-               async void UpdateThumbImage()
+               void UpdateThumbImage()
                {
-                       var uiimage = await Element.ThumbImage.GetNativeImageAsync();
-                       Control?.SetThumbImage(uiimage, UIControlState.Normal);
-                       
-                       ((IVisualElementController)Element).NativeSizeChanged();
+                       _ = this.ApplyNativeImageAsync(Slider.ThumbImageSourceProperty, uiimage =>
+                       {
+                               Control?.SetThumbImage(uiimage, UIControlState.Normal);
+
+                               ((IVisualElementController)Element).NativeSizeChanged();
+                       });
                }
 
                protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
@@ -141,7 +144,7 @@ namespace Xamarin.Forms.Platform.iOS
                                UpdateMinimumTrackColor();
                        else if (e.PropertyName == Slider.MaximumTrackColorProperty.PropertyName)
                                UpdateMaximumTrackColor();
-                       else if (e.PropertyName == Slider.ThumbImageProperty.PropertyName)
+                       else if (e.PropertyName == Slider.ThumbImageSourceProperty.PropertyName)
                                UpdateThumbImage();
                        else if (e.PropertyName == Slider.ThumbColorProperty.PropertyName)
                                UpdateThumbColor();
index 0ffc7ba..28f17e9 100644 (file)
@@ -184,7 +184,7 @@ namespace Xamarin.Forms.Platform.iOS
                                if (renderer.ViewController.TabBarItem != null)
                                        renderer.ViewController.TabBarItem.Title = page.Title;
                        }
-                       else if (e.PropertyName == Page.IconProperty.PropertyName || e.PropertyName == Page.TitleProperty.PropertyName && Forms.IsiOS10OrNewer)
+                       else if (e.PropertyName == Page.IconImageSourceProperty.PropertyName || e.PropertyName == Page.TitleProperty.PropertyName && Forms.IsiOS10OrNewer)
                        {
                                var page = (Page)sender;
 
@@ -460,13 +460,8 @@ namespace Xamarin.Forms.Platform.iOS
                /// </returns>
                protected virtual async Task<Tuple<UIImage, UIImage>> GetIcon(Page page)
                {
-                       if (!string.IsNullOrEmpty(page.Icon?.File))
-                       {
-                               var icon = await page.Icon.GetNativeImageAsync();
-                               return Tuple.Create(icon, (UIImage)null);
-                       }
-
-                       return null;
+                       var icon = await page.IconImageSource.GetNativeImageAsync();
+                       return icon == null ? null : Tuple.Create(icon, (UIImage)null);
                }
        }
 }
\ No newline at end of file
index 33848eb..9291405 100644 (file)
@@ -280,7 +280,7 @@ namespace Xamarin.Forms.Platform.iOS
 
                void HandleMasterPropertyChanged(object sender, PropertyChangedEventArgs e)
                {
-                       if (e.PropertyName == Page.IconProperty.PropertyName || e.PropertyName == Page.TitleProperty.PropertyName)
+                       if (e.PropertyName == Page.IconImageSourceProperty.PropertyName || e.PropertyName == Page.TitleProperty.PropertyName)
                                MessagingCenter.Send<IVisualElementRenderer>(this, NavigationRenderer.UpdateToolbarButtons);
                }
 
@@ -329,12 +329,15 @@ namespace Xamarin.Forms.Platform.iOS
 
                void UpdateBackground()
                {
-                       if (!string.IsNullOrEmpty(((Page)Element).BackgroundImage))
-                               View.BackgroundColor = ColorExtensions.FromPatternImageFromBundle(((Page)Element).BackgroundImage);
-                       else if (Element.BackgroundColor == Color.Default)
-                               View.BackgroundColor = UIColor.White;
-                       else
-                               View.BackgroundColor = Element.BackgroundColor.ToUIColor();
+                       _ = this.ApplyNativeImageAsync(Page.BackgroundImageSourceProperty, bgImage =>
+                       {
+                               if (bgImage != null)
+                                       View.BackgroundColor = UIColor.FromPatternImage(bgImage);
+                               else if (Element.BackgroundColor == Color.Default)
+                                       View.BackgroundColor = UIColor.White;
+                               else
+                                       View.BackgroundColor = Element.BackgroundColor.ToUIColor();
+                       });
                }
 
                void UpdateControllers()
index a545b4a..e87a975 100644 (file)
@@ -137,7 +137,7 @@ namespace Xamarin.Forms.Xaml.UnitTests
                        public void xStaticAndImplicitOperators(bool useCompiledXaml)
                        {
                                var layout = new XStatic(useCompiledXaml);
-                               Assert.AreEqual("ic_close.png", layout.ToolbarItems[0].Icon.File);
+                               Assert.AreEqual("ic_close.png", (layout.ToolbarItems[0].IconImageSource as FileImageSource).File);
                        }
 
                        [TestCase(false)]