Проблемы Xamarin Forms с управлением изображениями. Изображение не отображается - PullRequest
1 голос
/ 28 мая 2020

В настоящее время я работаю над списком предварительного просмотра изображений, которые были сделаны на самом мобильном устройстве. Позже эти изображения будут сохранены в базе данных. Однако в первой итерации я тестировал список с изображениями из Интернета. Я использую формы xamarin, цель - android. Это изображение страницы на устройстве Я не могу точно определить проблему. Я не получаю исключений во время выполнения. Возможно, возникла проблема с привязкой.

[Обновлен исходный код и вычищен]

Вот вид:

<?xml version="1.0" encoding="utf-8" ?>
<ui:BasePage
    x:Class="AssetManagement.Mobile.Core.UI.OrderItemImageDocumentationPage"
    xmlns="http://xamarin.com/schemas/2014/forms"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    xmlns:actionMenu="clr-namespace:Client.ApplicationDataModel.UI.Controls.ActionMenu;assembly=Client.ApplicationDataModel.UI"
    xmlns:controls="clr-namespace:AssetManagement.Mobile.Core.Controls"
    xmlns:controls1="clr-namespace:UI.XF.Controls;assembly=UI"
    xmlns:res="clr-namespace:AssetManagement.Mobile.Core.Resources"
    xmlns:ui="clr-namespace:AssetManagement.Mobile.Core.UI"
    xmlns:valueconverter="clr-namespace:AssetManagement.Mobile.Core.Classes.ValueConverter"
    xmlns:viewmodel="clr-namespace:AssetManagement.Mobile.Core.ViewModels"
    Title="Bild Dokumentation" 
    x:TypeArguments="viewmodel:OrderItemImageDocuViewModel"><!--{res:Translate OrderItemImageDocumentary}-->
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="*" />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto" />
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="Auto" />
        </Grid.ColumnDefinitions>
        <StackLayout Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="3">
            <ListView ItemsSource="{Binding OrderItemImages}"
          HasUnevenRows="true"
          ItemSelected="OnListViewItemSelected"
          ItemTapped="OnListViewItemTapped">
                <ListView.ItemTemplate>
                    <DataTemplate>
                        <ViewCell>
                            <Grid Padding="10">
                                <Grid.RowDefinitions>
                                    <RowDefinition Height="Auto" />
                                    <RowDefinition Height="*" />
                                </Grid.RowDefinitions>
                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition Width="Auto" />
                                    <ColumnDefinition Width="*" />
                                </Grid.ColumnDefinitions>
                           <Image Grid.RowSpan="2"
                           Source="{Binding ImageData}"
                           Aspect="AspectFit"
                           HeightRequest="200"
                           WidthRequest="200" />
                                <Label Grid.Column="1"
                           Text="{Binding Title}"
                           FontAttributes="Bold" />
                                <Label Grid.Row="1"
                           Grid.Column="1"
                           Text="test"
                           VerticalOptions="End" />
                            </Grid>
                        </ViewCell>
                    </DataTemplate>
                </ListView.ItemTemplate>
            </ListView>
        </StackLayout>
        <StackLayout Grid.Row="1" Grid.ColumnSpan="3" Grid.Column="0" Orientation="Horizontal">
            <Button x:Name="BtnCancel"
                        AutomationId="BtnCancel"
                        Text="Cancel"
                        Clicked="BtnCancel_OnClicked"
                        Style="{StaticResource DefaultButtonStyle}" />
            <Button x:Name="BtnSave"
                        AutomationId="BtnSave"
                        Text="Save"
                        Clicked="BtnSave_OnClicked"
                        Style="{StaticResource DefaultButtonStyle}" />
        </StackLayout>
    </Grid>



</ui:BasePage>

Соответствующий код:

    [XamlCompilation(XamlCompilationOptions.Compile)]
    public partial class OrderItemImageDocumentationPage : BasePage<OrderItemImageDocuViewModel>
    {
        private IAppConfiguration _appConfig;

        public OrderItemImageDocumentationPage()
        {
            InitializeComponent();
        }

        public OrderItemImageDocumentationPage(OrderItemImageDocuViewModel viewModel, IEventLogService eventLog, ILifetimeScope scope,
            IUserInterfaceService uiService, IAppConfiguration appConfig)
            : base(viewModel, eventLog, scope, uiService)
        {
            InitializeComponent();

            _appConfig = appConfig;
        }

        private void BtnSave_OnClicked(object sender, EventArgs e)
        {
            var test = new OrderItemImageDocData(Title = "test", Xamarin.Forms.ImageSource.FromUri(new Uri(@"https://upload.wikimedia.org/wikipedia/commons/7/7b/Dark_brown.PNG")));
            base.ViewModel.OrderItemImages.Add(test);
            base.ViewModel.OrderItemImages.Last().ImageData = Xamarin.Forms.ImageSource.FromUri(new Uri(@"https://upload.wikimedia.org/wikipedia/commons/7/7b/Dark_brown.PNG"));
        }
    }

Моя текущая модель представления:

    public class OrderItemImageDocuViewModel : ApplicationDataBaseViewModel, INavigationEventHandler
    {
        #region Klassenvariablen

        private readonly int _pagingSize = 20;
        private IAppConfiguration _appConfig;
        private ILifetimeScope _scope;
        private IBarcodeParserService _barcodeParser;
        private IEventLogService _eventLog;
        private IUserDataService _userData;
        private int _itemsToLoadCount;
        private ObservableCollection<OrderItemImageDocData> _orderItemImages = new ObservableCollection<OrderItemImageDocData>();
        private OrderItem _orderItemContext = null;
        #endregion Klassenvariablen

        #region Konstruktor

        public OrderItemImageDocuViewModel(ILifetimeScope scope, IDataRepositoryService dataRepository, IBarcodeParserService barcodeParserService, IEventLogService eventLog, IUserDataService userData, ITranslationService translationService, IAppConfiguration appConfig)
            : base(dataRepository)
        {
            _eventLog = eventLog.Initialize(typeof(OrderItemImageDocuViewModel));
            _scope = scope;
            _appConfig = appConfig;
            _userData = userData;
            _barcodeParser = barcodeParserService;
            TranslationService = translationService;

            _itemsToLoadCount = _pagingSize;

            //DatabasesMissing = !dataRepository.IsDataStoreFileAvailable(DownloadDataFileType.TransactionData);

            //if (!DatabasesMissing)
            //{
            //    IsLoading = true;
            //}
        }

        #endregion Konstruktor

        #region Properties

        [NavigationParameter]
        public Order Order { get; set; }

        public IEventLogService EventLog => _eventLog;

        public bool IsLoading { get; set; }

        public bool DatabasesMissing { get; set; }



        public ITranslationService TranslationService { get; set; }

        public IList<OrderItem> OrderItems { get; set; }

        public IOrderTypeScanHandling ScanHandler { get; set; }

        public ObservableCollection<OrderItemImageDocData> OrderItemImages 
        {
            get 
            {
                return _orderItemImages;
            }
            set 
            {
                _orderItemImages = value;
                base.OnPropertyChanged("OrderItemImages");
            }
        }
        #endregion Properties

        public override async void OnNavigationParametersProvided(NavigationContext context)
        {
            if (!DatabasesMissing)
            {
                IsLoading = true;

                try
                {
                    //await InitializeData();

                    //await LoadDataOnDemand();
                }
                catch (Exception ex)
                {
                    //ex.TrackError();
                }

                IsLoading = false;
            }
        }

    }

Это класс, в котором в настоящее время хранятся данные изображения. Это просто быстрый и грязный заполнитель. Поскольку дизайнер vs довольно плохой и не работает, мне нужен был какой-то класс, который просто предоставляет данные изображения, чтобы я мог создать страницу пользовательского интерфейса так, как я хочу.

    public class OrderItemImageDocData : INotifyPropertyChanged
    {
        #region Events
        public event PropertyChangedEventHandler PropertyChanged;
        #endregion
        #region Fields
        private string _title = string.Empty;
        private ImageSource _imageData;
        #endregion

        #region Constr
        public OrderItemImageDocData()
        {

        }
        public OrderItemImageDocData(string title, ImageSource imgData) 
        {
            _title = title;
            ImageData = imgData;
        }
        #endregion

        #region Properties
        public string Title 
        {
            get 
            {
                return _title; 
            }
            set 
            {
                _title = value;
                if (PropertyChanged != null)
                    PropertyChanged(this, new PropertyChangedEventArgs("Title"));
            }
        }
        public ImageSource ImageData
        {
            get
            {
                return _imageData;
            }
            set
            {
                _imageData = value;
                if (PropertyChanged != null)
                    PropertyChanged(this, new PropertyChangedEventArgs("ImageData"));
            }
        }
        #endregion
    }

Разрешения, которые у меня есть в моем android файл manifest.

    <uses-permission android:name="android.permission.FLASHLIGHT" />
    <uses-permission android:name="android.permission.CAMERA" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.VIBRATE" />

[Обновление] Я не уверен, почему не заметил этого раньше. Вероятно, потому что во время отладки он не выдал исключение. Однако должно быть исключение во время выполнения. Результат vs windows показывает это всякий раз, когда я пытаюсь добавить новый элемент представления списка (и это для нового изображения):

05-28 08:09:43.563 D/skia    ( 7653): --- SkImageDecoder::Factory returned null
05-28 08:09:43.619 W/art     ( 7653): JNI RegisterNativeMethods: attempt to register 0 native methods for md51558244f76c53b6aeda52c8a337f2c37.CellRenderer_RendererHolder
[0:] ImageLoaderSourceHandler: Could not retrieve image or image data was invalid: Uri: https://upload.wikimedia.org/wikipedia/commons/7/7b/Dark_brown.PNG
05-28 08:09:43.703 I/Choreographer( 7653): Skipped 38 frames!  The application may be doing too much work on its main thread.
Thread finished: <Thread Pool> #2

Однако информация довольно скудная. Пробовал несколько разных изображений с одинаковым результатом.

Последнее обновление : К сожалению, я не могу опубликовать решение этой проблемы, если у других есть похожие проблемы, попробуйте ответы от Михаила Дучева. Он получил несколько хороших указателей. Однако я переключаюсь с uri на источник потока, поскольку загружаю изображения из базы данных. По-видимому, это исключение времени выполнения возникает у меня только при использовании uri ImageSource.

Ответы [ 2 ]

1 голос
/ 28 мая 2020

Однако на первой итерации я тестировал список с изображениями из Интернета. Я использую формы xamarin, и целью является android.

Из опубликованного кода изображение привязано к свойству AssetImage . Свойство имеет тип Image, привязка значения к источнику изображения не работает. Попробуйте изменить тип на строка .

Проверьте код:

public class OrderItemImageDocData : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    ...
    private string _assetImage;
    public string AssetImage
    {
        get
        {
            return _assetImage;
        }
        set
        {
            _assetImage = value;
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs("AssetImage"));
        }
    }
}

Чтобы загружать изображения из Интернета, не забудьте добавить разрешение Inte rnet.

1 голос
/ 28 мая 2020

Вы правы, что проблема в привязке. Класс Xamarin Image ожидает, что связываемое свойство Source будет экземпляром ImageSource. From Изображения в Xamarin.Forms docs:

Source - экземпляр ImageSource, File, Uri или Resource, который устанавливает изображение для отображения.

В настоящее время вы устанавливаете источник ваших изображений типа Image, который ничего не сообщает пользовательскому интерфейсу и его привязке.

Что вам нужно для этого, измените это:

Source="{Binding AssetImage}"

на это:

 Source="{Binding ImageData}"
...