BarBackgroundColor = Color.Purple;
BarTextColor = Color.White;
Title = root.Title;
- Icon = root.Icon;
+ IconImageSource = root.IconImageSource;
}
}
}
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;
{
Content = new Label() { Text = (Children.Count + 1).ToString() },
Title = (Children.Count + 1).ToString(),
- Icon = "calculator.png"
+ IconImageSource = "calculator.png"
});
btnRemovePage.IsEnabled = true;
}),
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), () =>
{
{
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)
{
Title = "Test",
Content = layout,
- Icon = "calculator.png"
+ IconImageSource = "calculator.png"
});
}
})
};
- 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));
}
};
- 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);
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"
}
}
};
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)),
return new Button
{
Text = "Click Me",
- Image = "coffee.png",
+ ImageSource = "coffee.png",
ContentLayout = layout,
BackgroundColor = Color.Gray
};
public MenuPage ()
{
- Icon = "bank.png";
+ IconImageSource = "bank.png";
Title = "Carsousel Memory Bug";
BackgroundColor = Color.FromHex ("#000000");
public Page2 ()
{
Master = new Page () { Title = "Master",
- Icon = "Icon.png"
+ IconImageSource = "Icon.png"
};
Detail = new Page () { Title = "Detail" };
}
public SidemenuPage ()
{
Title = "Side";
- Icon = "menuIcon.png";
+ IconImageSource = "menuIcon.png";
var lbl = new Label { Text = "SideMenu" };
var btn = new Button { Text = "Menu Opener" };
}
public void ChangeIcon() {
- Icon = "bank.png";
+ IconImageSource = "bank.png";
}
}
{
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" });
}
public void ChangeIcon()
{
- Master.Icon = "settings";
+ Master.IconImageSource = "settings";
}
public void ChangeIcon2()
{
- Master.Icon = "menuIcon";
+ Master.IconImageSource = "menuIcon";
}
}
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);
}
cell.ContextActions.Add(new MenuItem
{
Text = "Action",
- Icon = "icon",
+ IconImageSource = "icon",
IsDestructive = true,
Command = new Command(() => DisplayAlert("TITLE", "Context action invoked", "Ok")),
});
cell.ContextActions.Add(new MenuItem
{
Text = "Action",
- Icon = "icon",
+ IconImageSource = "icon",
IsDestructive = true,
Command = new Command(() => DisplayAlert("TITLE", "Context action invoked", "Ok")),
});
{
var tbi = new ToolbarItem();
- tbi.Icon = "synchronize.png";
+ tbi.IconImageSource = "synchronize.png";
tbi.Order = ToolbarItemOrder.Primary;
tbi.Priority = 0;
var item = new MenuItem { Text = $"hello menu item {i}.{j}" };
if (withImage)
{
- item.Icon = Icon = "bank.png";
+ item.IconImageSource = IconImageSource = "bank.png";
}
if (addShortcut)
{
{
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."
{
var settings = new ToolbarItem
{
- Icon = "bank.png",
+ IconImageSource = "bank.png",
Text = "Settings",
Command = new Command(ShowSettingsPage),
};
Title = "Test Page";
- Icon = "Icon.png";
+ IconImageSource = "Icon.png";
}
Title = "Settings";
- Icon = "bank.png";
+ IconImageSource = "bank.png";
}
}
}
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;
}
{
public ListPageCode()
{
- Icon = "coffee.png";
+ IconImageSource = "coffee.png";
ListView view = new ListView(ListViewCachingStrategy.RecycleElement);
Content = view;
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 = {
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 } } };
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
{
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)},
}
};
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)},
}
};
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",
};
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);
{
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 ());
public Issue2628 ()
{
var button1 = new Button { Text = "Click !!!!!!!!!!"};
- BackgroundImage="bank.png";
+ BackgroundImageSource="bank.png";
button1.Clicked += ButtonAction;
Content = new StackLayout {
public void ButtonAction(object sender, EventArgs args)
{
- BackgroundImage="calculator.png";
+ BackgroundImageSource="calculator.png";
}
}
}
{
Title = "Master",
BackgroundColor = Color.SkyBlue,
- Icon = "menuIcon"
+ IconImageSource = "menuIcon"
};
Detail = new NavigationPage(new ContentPage
public ContractsPage ()
{
Title = "Contracts";
- Icon = "bank.png";
+ IconImageSource = "bank.png";
var grid = new Grid();
grid.ColumnDefinitions.Add(new ColumnDefinition());
{
// 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
var contentPage = new ContentPage()
{
Content = grid,
- Icon = "coffee.png"
+ IconImageSource = "coffee.png"
};
return contentPage;
Children.Add((createPage()));
Children.Add(new ContentPage()
{
- Icon = "calculator.png",
+ IconImageSource = "calculator.png",
Content = new Button()
{
Text = "Click Me",
{
public ListPageCode()
{
- Icon = "coffee.png";
+ IconImageSource = "coffee.png";
ListView view = new ListView(ListViewCachingStrategy.RecycleElement);
Content = view;
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"}
}
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()
{
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);
else
{
_image.Source = _fileName;
- _button.Image = _fileName;
+ _button.ImageSource = _fileName;
_imageButton.Source = _fileName;
_listView.ItemsSource = new string[] { _fileName };
Device.BeginInvokeOnMainThread(() => button.Text = _disappearText);
--- /dev/null
+<?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
--- /dev/null
+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
void BtnSetBkgndImg_Clicked(object sender, System.EventArgs e)
{
- BackgroundImage = "test.jpg";
+ BackgroundImageSource = "test.jpg";
}
void BtnSetBkgndColorDefault_Clicked(object sender, System.EventArgs e)
void BtnSetBkgndImgNull_Clicked(object sender, System.EventArgs e)
{
- BackgroundImage = null;
+ BackgroundImageSource = null;
}
}
#endif
var master = new ContentPage {
Title = "Master",
- Icon = "bank.png",
+ IconImageSource = "bank.png",
Content = listView
};
}
};
- 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);
}
<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
SetMainPage(CreateDefaultMainPage());
//TestMainPageSwitches();
+
+ //SetMainPage(new ImageSourcesGallery());
}
protected override void OnStart()
{
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
{
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();
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()); });
{
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",
};
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());
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;
Children.Add(new NavigationPage(new Page())
{
Title = "Rubriques",
- Icon = "coffee.png",
+ IconImageSource = "coffee.png",
BarBackgroundColor = Color.Blue,
BarTextColor = Color.Aqua
});
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" }
}
)
;
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();
await Navigation.PushModalAsync (new TabbedPage {
ItemTemplate = new DataTemplate (() => {
var page = new ContentPage();
- page.SetBinding (BackgroundImageProperty, ".");
+ page.SetBinding (BackgroundImageSourceProperty, ".");
return page;
}),
await Navigation.PushModalAsync (new CarouselPage {
ItemTemplate = new DataTemplate (() => {
var page = new ContentPage();
- page.SetBinding (BackgroundImageProperty, ".");
+ page.SetBinding (BackgroundImageSourceProperty, ".");
return page;
}),
FontSize = 42
}})
{
- BackgroundImage = "oasis.jpg"
+ BackgroundImageSource = "oasis.jpg"
}
);
};
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" }
});
};
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" }
});
};
await Navigation.PushModalAsync (new MasterDetailPage {
Master = new ContentPage { Title = "Master" },
Detail = new ContentPage(),
- BackgroundImage = "crimson.jpg",
+ BackgroundImageSource = "crimson.jpg",
});
};
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;
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();
--- /dev/null
+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
+ }),
+ }
+ }
+ };
+ }
+ }
+ }
+}
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();
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)),
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);
btnGo.Clicked += (sender, e) =>
{
tp.CurrentPage.Title = "Tile changed";
- tp.CurrentPage.Icon = null;
+ tp.CurrentPage.IconImageSource = null;
};
btnGo1.Clicked += (sender, e) =>
};
- 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()
return new Button
{
Text = "Click Me On Mac",
- Image = "bank.png",
+ ImageSource = "bank.png",
Font = Font.OfSize("Helvetica", 14),
ContentLayout = layout,
BackgroundColor = Color.Black,
ItemTemplate = new DataTemplate (() => {
var page = new ContentPage();
page.SetBinding (TitleProperty, "Title");
- page.SetBinding (IconProperty, "Icon");
+ page.SetBinding (IconImageSourceProperty, "Icon");
var layout = new StackLayout();
{
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;
}
}
public BaseView()
{
SetBinding(Page.TitleProperty, new Binding(HBaseViewModel.TitlePropertyName));
- SetBinding(Page.IconProperty, new Binding(HBaseViewModel.IconPropertyName));
+ SetBinding(Page.IconImageSourceProperty, new Binding(HBaseViewModel.IconPropertyName));
}
}
};
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))
<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">
{ 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) },
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);
}
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);
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),
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;
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); }
}
protected override void OnBindingContextChanged()
{
- FileImageSource image = Image;
+ ImageSource image = ImageSource;
if (image != null)
SetInheritedBindingContext(image, BindingContext);
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;
{
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); }
);
}
+ 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);
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),
{
}
+ public virtual bool IsEmpty => false;
+
protected CancellationTokenSource CancellationTokenSource
{
get { return _cancellationTokenSource; }
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
}
}
+ 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
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;
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);
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);
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)
page.SetValue(HasNavigationBarProperty, value);
}
- public static void SetTitleIcon(BindableObject bindable, FileImageSource value)
+ public static void SetTitleIcon(BindableObject bindable, ImageSource value)
{
bindable.SetValue(TitleIconProperty, value);
}
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());
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;
_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); }
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));
[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))]
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));
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); }
}
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];
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); }
throw new ArgumentNullException("activated");
Text = name;
- Icon = icon;
+ IconImageSource = icon;
Clicked += (s, e) => activated();
Order = order;
Priority = priority;
Store.CreateDirectoryAsync(CacheName).Wait();
}
+ public override bool IsEmpty => Uri == null;
+
public TimeSpan CacheValidity
{
get { return _cacheValidity; }
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;
// ITabStop
AView ITabStop.TabStop => this;
+
+ // IButtonLayoutRenderer
+ AppCompatButton IButtonLayoutRenderer.View => this;
}
}
#endif
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;
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;
- }
}
}
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);
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()
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();
}
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)
}
menuItem.SetIcon(iconDrawable);
- iconDrawable.Dispose();
}
- }
+ });
}
void UpdateToolbar()
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();
_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()
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);
+ });
}
}
}
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);
+ });
}
}
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()
bool _borderAdjustsPadding;
bool _maintainLegacyMeasurements;
- public ButtonLayoutManager(IButtonLayoutRenderer renderer) : this(renderer, false, false, false, true)
+ public ButtonLayoutManager(IButtonLayoutRenderer renderer)
+ : this(renderer, false, false, false, true)
{
}
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;
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();
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:
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);
+ });
}
}
}
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;
-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
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,
(imageView as IImageRendererController)?.SkipInvalidate();
imageView.SetImageResource(global::Android.Resource.Color.Transparent);
- bool setByImageViewHandler = false;
- Bitmap bitmap = null;
-
try
{
if (newImageSource != null)
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();
}
}
}
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;
BorderBackgroundManager _backgroundTracker;
ButtonLayoutManager _buttonLayoutManager;
IPlatformElementConfiguration<PlatformConfiguration.Android, Button> _platformElementConfiguration;
- private Button _button;
+ Button _button;
public event EventHandler<VisualElementChangedEventArgs> ElementChanged;
public event EventHandler<PropertyChangedEventArgs> ElementPropertyChanged;
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;
- }
}
}
var imageController = (IImageController)renderer.Element;
if (e.PropertyName == Image.SourceProperty.PropertyName ||
- e.PropertyName == Button.ImageProperty.PropertyName)
+ e.PropertyName == Button.ImageSourceProperty.PropertyName)
{
try
{
-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
+}
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));
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;
void GetNewMasterDetailToggle()
{
- int icon = ResourceManager.GetDrawableByName(CurrentMasterDetailPage.Master.Icon);
var drawer = GetRenderer(CurrentMasterDetailPage) as MasterDetailRenderer;
if (drawer == null)
return;
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,
_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();
}
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)));
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;
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;
AutoPackage = false;
_visualElementRenderer = this;
_backgroundTracker = new BorderBackgroundManager(this);
+
}
AButton NativeButton
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();
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
// (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()
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);
}
}
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);
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()
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);
{
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()
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++;
}
{
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
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);
{
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)
{
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)
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;
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)
{
// 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);
{
}
- 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,
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))
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);
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;
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)
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();
{
UpdateMinimumTrackColor();
UpdateMaximumTrackColor();
- if (!string.IsNullOrEmpty(Element.ThumbImage))
+ var thumbImage = Element.ThumbImageSource;
+ if (thumbImage != null && !thumbImage.IsEmpty)
{
UpdateThumbImage();
}
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)
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;
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)
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
+using Xamarin.Forms.Platform.GTK.Extensions;
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) =>
{
{
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;
}
detailColor);
}
- protected override async void CellPropertyChanged(object sender, PropertyChangedEventArgs args)
+ protected override void CellPropertyChanged(object sender, PropertyChangedEventArgs args)
{
base.CellPropertyChanged(sender, args);
}
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;
+ });
}
}
}
} 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)
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();
using Gdk;
using Gtk;
+using Xamarin.Forms.Platform.GTK.Extensions;
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++)
{
_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)
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
{
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);
+ }
+ }
}
}
{
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)
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()
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();
}
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)
UpdateToolbarItems();
else if (e.PropertyName == MenuItem.TextProperty.PropertyName)
UpdateToolbarItems();
- else if (e.PropertyName == MenuItem.IconProperty.PropertyName)
+ else if (e.PropertyName == MenuItem.IconImageSourceProperty.PropertyName)
UpdateToolbarItems();
}
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);
--- /dev/null
+using Control = Gtk.Widget;
+
+namespace Xamarin.Forms.Platform.GTK
+{
+ public interface IVisualNativeElementRenderer : IVisualElementRenderer
+ {
+ Control Control { get; }
+ }
+}
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();
}
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();
}
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;
+ });
}
}
}
protected override void UpdateBackgroundImage()
{
- Widget?.SetBackgroundImage(Page.BackgroundImage);
+ Widget?.SetBackgroundImage(Page.BackgroundImageSource);
}
private void Init()
using System.IO;
using System.Threading;
using System.Threading.Tasks;
+using Xamarin.Forms.Platform.GTK.Extensions;
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()
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();
}
}
}
- 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)
{
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;
}
}
{
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();
}
protected override void UpdateBackgroundImage()
{
- Widget?.SetBackgroundImage(Page.BackgroundImage);
+ Widget?.SetBackgroundImage(Page.BackgroundImageSource);
}
protected override void Dispose(bool disposing)
Widget.InsertPage(
pageRenderer.Container,
page.Title,
- page.Icon?.ToPixbuf(new Size(DefaultIconWidth, DefaultIconHeight)),
+ page.IconImageSource?.ToPixbuf(new Size(DefaultIconWidth, DefaultIconHeight)),
index);
Widget.ShowAll();
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());
}
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
{
public TNativeElement Control { get; set; }
+ Control IVisualNativeElementRenderer.Control => Control;
+
public TElement Element { get; set; }
public Container Container => this;
<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" />
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;
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
-using AppKit;
+using System;
+using System.Threading;
+using System.Threading.Tasks;
+using AppKit;
+using Xamarin.Forms.Internals;
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
using System;
using System.Linq;
using AppKit;
+using Xamarin.Forms.Platform.MacOS;
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;
}
{
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;
+ });
}
}
}
var tbI = new ToolbarItem
{
Text = item.Title,
- Icon = item.Icon,
+ IconImageSource = item.IconImageSource,
Command = new Command(() => tabbedPage.SelectedItem = item)
};
items.Add(tbI);
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();
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;
UpdateBorder();
else if (e.PropertyName == VisualElement.BackgroundColorProperty.PropertyName)
UpdateBackgroundVisibility();
- else if (e.PropertyName == Button.ImageProperty.PropertyName)
+ else if (e.PropertyName == Button.ImageSourceProperty.PropertyName)
UpdateImage();
}
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()
UpdateCurrentPage();
else if (e.PropertyName == VisualElement.BackgroundColorProperty.PropertyName)
UpdateBackground();
- else if (e.PropertyName == Page.BackgroundImageProperty.PropertyName)
+ else if (e.PropertyName == Page.BackgroundImageSourceProperty.PropertyName)
UpdateBackground();
}
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)
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()
{
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();
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()
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;
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();
+ });
}
}
--- /dev/null
+namespace Xamarin.Forms.Platform.Tizen
+{
+ internal static class ImageExtensions
+ {
+ internal static bool IsNullOrEmpty(this ImageSource imageSource) =>
+ imageSource == null || imageSource.IsEmpty;
+ }
+}
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;
// 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))
{
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);
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
{
/// </summary>
public PageRenderer()
{
- RegisterPropertyHandler(Page.BackgroundImageProperty, UpdateBackgroundImage);
+ RegisterPropertyHandler(Page.BackgroundImageSourceProperty, UpdateBackgroundImage);
}
protected override void OnElementChanged(ElementChangedEventArgs<Page> e)
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)
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);
return res;
}
+
+ internal static string GetPath(ImageSource icon)
+ {
+ throw new NotImplementedException();
+ }
}
}
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();
}
UpdateBackground();
}
- void UpdateBackground()
+ async void UpdateBackground()
{
if (Element == null)
return;
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
{
{
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();
}
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)
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
{
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)
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;
}
}
}
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())
{
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
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;
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);
+ }
}
}
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
{
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,
}
}
- public BitmapImage ThumbImage
+ public WImageSource ThumbImage
{
- get { return (BitmapImage)GetValue(ThumbImageProperty); }
+ get { return (WImageSource)GetValue(ThumbImageProperty); }
set { SetValue(ThumbImageProperty, value); }
}
--- /dev/null
+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));
+ }
+}
_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);
}
using System;
using System.Threading.Tasks;
+using Xamarin.Forms.Internals;
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)
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);
}
}
_measured = true;
- return Control.Source.GetDesiredSize();
+ return new SizeRequest(Control.Source.GetImageSourceSize());
}
protected override void Dispose(bool disposing)
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)
if (_detail == null)
return;
- Control.DetailTitleIcon = await NavigationPage.GetTitleIcon(GetCurrentPage()).ToWindowsImageSource();
+ Control.DetailTitleIcon = await NavigationPage.GetTitleIcon(GetCurrentPage()).ToWindowsImageSourceAsync();
Control.InvalidateMeasure();
}
ImageSource source = NavigationPage.GetTitleIcon(_currentPage);
- _titleIcon = await source.ToWindowsImageSource();
+ _titleIcon = await source.ToWindowsImageSourceAsync();
_container.TitleIcon = _titleIcon;
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)
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);
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);
<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">
UpdateMaximumTrackColor();
else if (e.PropertyName == Slider.ThumbColorProperty.PropertyName)
UpdateThumbColor();
- else if (e.PropertyName == Slider.ThumbImageProperty.PropertyName)
+ else if (e.PropertyName == Slider.ThumbImageSourceProperty.PropertyName)
UpdateThumbImage();
}
() => 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)
{
return;
}
- Control.ThumbImage = new BitmapImage(new Uri($"ms-appx:///{thumbImage.File}"));
+ Control.ThumbImage = await thumbImage.ToWindowsImageSourceAsync();
}
protected override void UpdateBackgroundColor()
if (Control == null || Element == null)
return;
- if (!Element.IsSet(Specifics.HeaderIconsEnabledProperty))
- return;
-
bool headerIconsEnabled = Element.OnThisPlatform().GetHeaderIconsEnabled();
bool invalidateMeasure = false;
<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" />
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
{
{
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();
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
{
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;
+ }
}
}
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;
{
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();
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,
if (string.IsNullOrEmpty(text))
{
Control.Content = image;
+ Element?.InvalidateMeasureNonVirtual(InvalidationTrigger.RendererReady);
return;
}
container.Children.Add(textBlock);
Control.Content = container;
+ Element?.InvalidateMeasureNonVirtual(InvalidationTrigger.RendererReady);
}
void UpdateFont()
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);
}
}
{
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();
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()
{
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()
};
</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"
#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;
_forceName = forceName;
_item = item;
- if (!string.IsNullOrEmpty(item.Icon?.File) && !forceName)
+ if (item.IconImageSource != null && !item.IconImageSource.IsEmpty && !forceName)
UpdateIconAndStyle();
else
UpdateTextAndStyle();
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();
async void UpdateIconAndStyle()
{
- Image = await _item.Icon.GetNativeImageAsync();
+ Image = await _item.IconImageSource.GetNativeImageAsync();
Style = UIBarButtonItemStyle.Plain;
}
{
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();
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;
}
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();
UpdateCurrentPage();
else if (e.PropertyName == VisualElement.BackgroundColorProperty.PropertyName)
UpdateBackground();
- else if (e.PropertyName == Page.BackgroundImageProperty.PropertyName)
+ else if (e.PropertyName == Page.BackgroundImageSourceProperty.PropertyName)
UpdateBackground();
}
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)
using System.Threading.Tasks;
using Foundation;
using UIKit;
+using Xamarin.Forms.Internals;
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);
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();
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
+}
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;
}
}
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;
}
}
- 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;
}
{
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();
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()
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();
}
UpdatePanGesture();
else if (e.PropertyName == VisualElement.BackgroundColorProperty.PropertyName)
UpdateBackground();
- else if (e.PropertyName == Page.BackgroundImageProperty.PropertyName)
+ else if (e.PropertyName == Page.BackgroundImageSourceProperty.PropertyName)
UpdateBackground();
}
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()
((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)
{
UpdateMinimumTrackColor();
UpdateMaximumTrackColor();
- if (!string.IsNullOrEmpty(Element.ThumbImage))
+ var thumbImage = Element.ThumbImageSource;
+ if (thumbImage != null && !thumbImage.IsEmpty)
{
UpdateThumbImage();
}
}
}
- 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)
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();
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;
/// </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
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);
}
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()
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)]