如何在 toolbarItems 的 IconImageSource 属性 中支持流图像?

How can I support a stream image in the IconImageSource property of toolbarItems?

我有一个图像可以转换为流并添加到工具栏项的 IconImageSource 属性中。

** 面临的问题 **

将 ToolbarItems 中的 IconImageSource 属性 设置为流 ImageSource。 在 Android 中,它提出了诸如“无法访问已关闭的流,位于 System.IO.MemoryStream.get_Position()”之类的问题。

它不会在 iOS 和 UWP 平台上的 toolbarItems 中显示任何图像。

我在示例中创建了两个 imageSource 属性:OpenToolItem 和 CloseToolItem。

如何在我的应用程序中将流值分配给 OpenToolItem 和 CloseToolItem 属性?

请参考下面的代码。

我的mainpage.xaml

<?xml version="1.0" encoding="utf-8" ?>
<local:TestingControl  xmlns:local="clr-namespace:TestStreamControl" 
                       xmlns="http://xamarin.com/schemas/2014/forms"
                       xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                       x:Class="TestStreamControl.MainPage" OpenToolItem="https://aka.ms/campus.jpg" 
                       CloseToolItem="https://image.shutterstock.com/image-photo/bright-spring-view-cameo-island-600w-1048185397.jpg">
</local:TestingControl>

我的mainpage.xaml.cs

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;

namespace TestStreamControl
{
    public partial class MainPage : TestingControl
    {
        public MainPage()
        {
            InitializeComponent();
            Assembly assembly = Assembly.GetExecutingAssembly();
            Stream openStream = assembly.GetManifestResourceStream("TestStreamControl.Images.Meow2.jpg");
            var openSource = ImageSource.FromStream(() => openStream);
            OpenToolItem = openSource;

            Stream closeStream = assembly.GetManifestResourceStream("TestStreamControl.Images.lake_water_natural.jpg");
            var closeSource = ImageSource.FromStream(() => closeStream);
            CloseToolItem = closeSource;
        }
    }
}

TestingControl.cs

命名空间 TestStreamControl {

public partial class TestingControl : ContentPage
{
    private ToolbarItem ToolbarItemSource;
    public TestingControl()
    {
        InitializeComponent();
        AddToolbarItem();
    }
    #region Bindable Property
    public static readonly BindableProperty OpenToolItemProperty =
         BindableProperty.Create(nameof(OpenToolItem), typeof(ImageSource), typeof(TestingControl), default(ImageSource), BindingMode.Default, null, OnPropertyChanged);

    public static readonly BindableProperty CloseToolItemProperty =
              BindableProperty.Create(nameof(CloseToolItem), typeof(ImageSource), typeof(TestingControl), default(ImageSource), BindingMode.Default, null, OnPropertyChanged);

    public static readonly BindableProperty ItemStateProperty =
        BindableProperty.Create(nameof(ItemState), typeof(bool), typeof(TestingControl), false, BindingMode.TwoWay, null, OnItemStatePropertyChanged);
    #endregion

    #region Public Properties
    public ImageSource OpenToolItem
    {
        get { return (ImageSource)GetValue(OpenToolItemProperty); }
        set { this.SetValue(OpenToolItemProperty, value); }
    }

    public ImageSource CloseToolItem
    {
        get { return (ImageSource)GetValue(CloseToolItemProperty); }
        set { this.SetValue(CloseToolItemProperty, value); }
    }
    public bool ItemState
    {
        get { return (bool)GetValue(ItemStateProperty); }
        set { this.SetValue(ItemStateProperty, value); }
    }

    #endregion

    #region Property changed events
    private static void OnPropertyChanged(BindableObject bindable, object oldValue, object newValue)
    {
        (bindable as TestingControl).OnSourcePropertyChanged(oldValue, newValue);
    }
    private static void OnItemStatePropertyChanged(BindableObject bindable, object oldValue, object newValue)
    {
        (bindable as TestingControl).OnSourcePropertyChanged(oldValue, newValue);
    }
    private void OnSourcePropertyChanged(object oldValue, object newValue)
    {
        UpdateToolbar();
    }

    #endregion

    private void AddToolbarItem()
    {
        this.ToolbarItemSource = new ToolbarItem
        {
            Text = "Open",
            Priority = int.MaxValue,
            Order = ToolbarItemOrder.Primary,
            IconImageSource = this.GetToolbarItem()
        };
        this.ToolbarItems.Add(this.ToolbarItemSource);
        this.ToolbarItemSource.Clicked += OnToolbarItemClicked;
    }

    private void OnToolbarItemClicked(object sender, EventArgs e)
    {
        if (ItemState)
        {
           message.Text = "Message sent";
        }
        else
        {
           message.Text = "Message Received";
            
        }

        this.ItemState = !this.ItemState;
        UpdateToolbar();
    }

    private ImageSource GetToolbarItem()
    {

        var internalOpenIcon = OpenToolItem ?? (Device.RuntimePlatform == Device.UWP ? "https://aka.ms/campus.jpg" : "https://aka.ms/campus.jpg");
        var internalCloseIcon = CloseToolItem ?? (Device.RuntimePlatform == Device.UWP ? "https://image.shutterstock.com/image-photo/bright-spring-view-cameo-island-600w-1048185397.jpg" : "https://image.shutterstock.com/image-photo/bright-spring-view-cameo-island-600w-1048185397.jpg");
        return this.ItemState ? internalCloseIcon : internalOpenIcon;
    }
    private void UpdateToolbar()
    {

        if (this.ToolbarItemSource != null)
        {
            if (OpenToolItem != null || CloseToolItem != null)
            {
                this.ToolbarItemSource.Text = this.ItemState ? "Close" : "Open";
                this.ToolbarItemSource.IconImageSource = this.GetToolbarItem();
            }
            if (OpenToolItem == null && CloseToolItem == null)
            {
                this.ToolbarItemSource.Text = this.ItemState ? "Close" : "Open";
                this.ToolbarItemSource.IconImageSource = this.GetToolbarItem();
            }
            else
            {
                // this.ToolbarItemSource.Text = this.ItemState ? "Close" : "Open";
                this.ToolbarItemSource.IconImageSource = this.GetToolbarItem();
            }
        }
    }
 }

}

TestingControl.xaml

<?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="TestStreamControl.TestingControl">
    <ContentPage.Content>
        <StackLayout>
            <Label Text="Welcome to Xamarin.Forms!" x:Name="message"
                VerticalOptions="CenterAndExpand" 
                HorizontalOptions="CenterAndExpand" />
        </StackLayout>
    </ContentPage.Content>
</ContentPage>

问题是这些代码行:

Stream openStream = assembly.GetManifestResourceStream("TestStreamControl.Images.Meow2.jpg");
var openSource = ImageSource.FromStream(() => openStream);

GetManifestResourceStream Imagesource.FromStream() 调用之前。这会打开一个流,一次。 (该流在周围方法 MainPage 构造函数的末尾自动关闭。这稍后会导致错误“无法访问已关闭的流”。)

ImageSource 需要打开流的代码每次需要

var openSource = ImageSource.FromStream(() =>
    {
        Stream openStream = assembly.GetManifestResourceStream("TestStreamControl.Images.Meow2.jpg");
        return openStream;
    });

GetManifestResourceStream 调用现在 委托代码中。每次 ToolbarItem 需要流时,该代码都会被调用。