Open asneddon opened 7 years ago
I think the main problem is the empty implementation in IconNavigationRenderer (FormsPlugin.Iconize.UWP). You have no access to the Page and/or to the CommandBar/AppBarButtons:
Neither with a ContentPageRenderer nor a NavigationPageRenderer. With the ContentPageRenderer you can only override the whole page. The ToolbarItem itsself has no accompanying renderer.
Quite frustrating...
This is my custom implement of NavigationPageRenderer, maybe it still works on custom ContentPageRenderer
public class ExIconNavigationRenderer : NavigationPageRenderer
{
private CommandBar _commandBar;
public ExIconNavigationRenderer()
{
ElementChanged += ExIconNavigationRenderer_ElementChanged;
}
private void ContainerElement_Loaded(object sender, Windows.UI.Xaml.RoutedEventArgs e)
{
ContainerElement.Loaded -= ContainerElement_Loaded;
_commandBar = typeof(PageControl).GetTypeInfo().GetDeclaredField("_commandBar").GetValue(ContainerElement) as CommandBar;
_commandBar.DataContextChanged += CommandBar_DataContextChanged;
}
private void CommandBar_DataContextChanged(Windows.UI.Xaml.FrameworkElement sender, Windows.UI.Xaml.DataContextChangedEventArgs args)
{
var toolbarItems = (args.NewValue as Xamarin.Forms.Page).ToolbarItems;
foreach (IconToolbarItem item in toolbarItems.Where(item => item is IconToolbarItem && (item as IconToolbarItem).IsVisible))
{
var element = _commandBar.PrimaryCommands.Where(command => command is AppBarButton && (command as AppBarButton).DataContext == item).FirstOrDefault();
if (element == null) continue;
var appBarButton = element as AppBarButton;
var icon = Plugin.Iconize.Iconize.FindIconForKey(item.Icon);
if (icon == null) continue;
appBarButton.Icon = new FontIcon()
{
FontFamily = Plugin.Iconize.Iconize.FindModuleOf(icon).ToFontFamily(),
Glyph = $"{icon.Character}",
Foreground = new SolidColorBrush(item.IconColor.ToWindowsColor()),
};
}
}
private void ExIconNavigationRenderer_ElementChanged(object sender, VisualElementChangedEventArgs e)
{
ElementChanged -= ExIconNavigationRenderer_ElementChanged;
ContainerElement.Loaded += ContainerElement_Loaded;
}
}
And this is my custom implement of IconImageRenderer, It uses Win2D
public class ExIconImageRenderer : IconImageRenderer
{
protected override async void OnElementChanged(ElementChangedEventArgs<Image> e)
{
base.OnElementChanged(e);
if (Control == null || Element == null)
return;
await UpdateImage();
}
protected override async void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
if (Control == null || Element == null)
return;
switch (e.PropertyName)
{
case nameof(IconImage.Icon):
case nameof(IconImage.IconColor):
case nameof(IconImage.IconSize):
await UpdateImage();
break;
}
}
private async Task UpdateImage()
{
var iconImage = Element as IconImage;
var icon = Plugin.Iconize.Iconize.FindIconForKey(iconImage.Icon);
CanvasDevice device = CanvasDevice.GetSharedDevice();
var target = new CanvasRenderTarget(device, Convert.ToSingle(Element.HeightRequest), Convert.ToSingle(Element.HeightRequest), 96 * 4);
using (var session = target.CreateDrawingSession())
using (var format = new CanvasTextFormat { FontSize = Convert.ToSingle(Element.HeightRequest), FontFamily = Plugin.Iconize.Iconize.FindModuleOf(icon).ToFontFamily().Source })
using (var textLayout = new CanvasTextLayout(device, $"{icon.Character}", format, Convert.ToSingle(Element.HeightRequest), Convert.ToSingle(Element.HeightRequest)))
session.DrawTextLayout(textLayout, 0, 0, iconImage.IconColor.ToWindowsColor());
using (var stream = new InMemoryRandomAccessStream())
{
await target.SaveAsync(stream, CanvasBitmapFileFormat.Png);
stream.Seek(0);
BitmapImage result = new BitmapImage();
await result.SetSourceAsync(stream);
Control.Source = result;
}
}
}
Hopes it can help
My _commandBar.PrimaryCommands are always empty. How do you fill the ContentPage.ToolbarItems? With the ContentPage you do not come on the commandBar.
Ok I notice that you still need a IconNavigationPage outside the ContentPage, just like
MainPage = new ExIconNavigationPage(new YourCustomContentPage());
if you just set the MainPage to YourCustomContentPage, it's not gonna work
No change, PrimaryCommands are still empty:
var page = pages[viewModelType];
var detailPage = new >**IconNavigationPage**<(page);
masterPage.ListView.SelectedItem = null;
masterPage.SettingsListView.SelectedItem = null;
foreach (var item in page.ToolbarItems)
{
detailPage.ToolbarItems.Add(item);
}
detailPage.ToolbarItems.Add(new FormsPlugin.Iconize.IconToolbarItem() { Priority = 10, Name = "Search", Command = new Command(() => IsPresented = true) });
[assembly: ExportRenderer(typeof(IconNavigationPage), typeof(AppNavigationPageRenderer))]
[assembly: ExportRenderer(typeof(IconImage), typeof(IconImageRenderer))]
namespace ...{
public class AppNavigationPageRenderer : NavigationPageRenderer
{
...
}
}
@surgien Did you found a solution?
puhh it was long ago...
iirc you have two different command collections.
@surgien Thank you for your feedback. But you have finally removed Iconize, isn't it? Which font are using as glyph for the ToolbarIcon?
native platform fonts: var icon = new FontIcon() { FontFamily = new FontFamily("Segoe MDL2 Assets"), Glyph = toolBarItem.IconGlyph };
*Line 44
I seem to be able to get the text based controls to work (IconButton, IconLabel), but ones that use an ImageSource don't appear to work on UWP Forms projects. They work on iOS and Droid.
I've manually added the missing .tff files to the required .nugget packages folder as noted in another bug.
Looking at the code, there is a call in IconImageRenderer.cs to UpdateImageAsync(), but the body is commented out.
Also, I cant see the implementation of ToImageSourceAsync() anywhere (which is probably why its commented out).
Is there an ETA for this to be implemented? I'm loving this library as a way to get around building icons for both Light and Dark Themes in UWP apps.