Выберите и отобразите xamarin.form.Image в Windows Phone

Я работаю над приложением для Windows Phone 8.1 в Xamarin с mvvmCross. Мне нужно выбрать несколько изображений из телефонной библиотеки и отобразить их. Я использую FileOpenPicker.SelectMultipleFilesAndContinue для этого. Теперь мне нужно иметь возможность отображать все эти изображения в представлении. Одна проблема заключается в том, что минимальное количество изображений должно быть 20, а изображения могут быть довольно большими. Сначала я попытался превратить их в байтовые массивы и использовал конвертер для их отображения.

 public async void SelectFotosCallback(FileOpenPickerContinuationEventArgs args) {

        if (args.Files.Count > 0) {

            foreach (StorageFile file in args.Files) {

                IRandomAccessStream fileStream = await file.OpenAsync(Windows.Storage.FileAccessMode.Read);

                byte[] bytes = null;
                using (var reader = new DataReader(fileStream.GetInputStreamAt(0))) {
                    bytes = new byte[fileStream.Size];
                    await reader.LoadAsync((uint)fileStream.Size);
                    reader.ReadBytes(bytes);
                }

                callback(bytes);
            }              
        }
        else {

        }
    }

Этот метод, казалось, работал с первой попытки, но как только я попробовал его с 5 изображениями, он перестал работать. Когда это было сделано с обратным вызовом, приложение просто закрылось. Нет сообщения об ошибке или что-нибудь. (Мое предположение - перегрузка памяти.)

После этого я нашел небольшое решение, где я беру массивы байтов и делаю их в Xamarin.Form Images.

public async void SelectFotosCallback(FileOpenPickerContinuationEventArgs args) {
        if (args.Files.Count > 0) {
            foreach (StorageFile file in args.Files) {
                IRandomAccessStream fileStream = await file.OpenAsync(Windows.Storage.FileAccessMode.Read);

                byte[] bytes = null;
                using (var reader = new DataReader(fileStream.GetInputStreamAt(0))) {
                    bytes = new byte[fileStream.Size];
                    await reader.LoadAsync((uint)fileStream.Size);
                    reader.ReadBytes(bytes);
                }
                Image image = new Image();
                image.Source = ImageSource.FromStream(() => new MemoryStream(bytes));
                var iets = image.Source.BindingContext;

                callback(image);
            }              
        }
        else {

        }

Это, казалось, решило проблему перегрузки в памяти. единственная другая проблема сейчас заключается в том, что я не могу найти способ отображения этих изображений.

<GridView ItemsSource="{Binding SelectedImages}">
                    <GridView.ItemTemplate>
                        <DataTemplate>
                            <Grid>
                                <Image Style="{StaticResource imageListImage}" Source="{Binding Source}"/>
                                <Button Style="{StaticResource imageListXButton}">
                                    <Button.Background>
                                        <ImageBrush ImageSource="ms-appx:///Resources/XButton.png"/>
                                    </Button.Background>
                                </Button>
                            </Grid>
                        </DataTemplate>
                    </GridView.ItemTemplate>

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

1 ответ

Решение

После некоторых глубоких раскопок я смог найти ответ. Это было намного проще, чем я думал. Я начал работать с decodepixel из BitmapImage. Используя конвертер, я устанавливаю значения.

public object Convert(object value, Type targetType, object parameter, string language) {

        BitmapImage image = (BitmapImage)value;

        image.DecodePixelType = DecodePixelType.Logical;

        if (image.PixelHeight >= image.PixelWidth) {
            image.DecodePixelHeight = 100;
        }
        else {
            image.DecodePixelWidth = 100;
        }
        return image;
    }

Странная вещь заключалась в том, что иногда она работала. Но по какой-то причине это не сработало на всех изображениях, а иногда даже выбрасывало их. Но после долгих испытаний я наконец нашел то, что искал.

                    BitmapImage bitmap = new BitmapImage();
                    BitmapImage temp = new BitmapImage();

                    bitmap.DecodePixelType = DecodePixelType.Logical;

                    using (IRandomAccessStream fileStream = await file.OpenAsync(Windows.Storage.FileAccessMode.Read)) {
                       IRandomAccessStream secondStream = fileStream.CloneStream();
                        BitmapImage temp = new BitmapImage();
                        temp.SetSource(fileStream);
                        if (temp.PixelHeight >= temp.PixelWidth) {
                            bitmap.DecodePixelHeight = 150;
                        }
                        else {
                            bitmap.DecodePixelWidth = 150;
                        }
                        bitmap.SetSource(secondStream);
                    }

По какой-то причине установка decodepixel после установки источника делает его неудобным, но установка этих значений перед установкой источника фактически обрезает изображение сразу.

Этот метод работает отлично и полностью решает мою проблему

Другие вопросы по тегам