Подтвердить что ты не робот

Как работать с изображениями в переносимой библиотеке классов, ориентированной на приложения Windows Store и WP7, WP8, WPF?

Я работаю над первым PCL, который нацелен: WSA (приложение для хранения Windows), WPF, WP7, WP8. Мы можем сказать, что это приложение типа rolerdex, у вас есть контакты, у них есть контактные данные и изображения. (это не так, но я не могу сообщить подробности о приложении, поэтому я использую очень простой пример). Вот некоторые из моих вопросов:)

  • Должен ли я иметь изображения в PCL?

Если да:

  • Как ссылаться на изображение для использования в WSA?
  • Как лучше всего решать масштабирование с помощью квалификаторов шкалы и т.д. при использовании в разных проектах?

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

EDIT: Я просто хочу отображать изображения. Это. Это статический rolerdex, вы не можете добавлять новых людей. Я просто хочу отобразить 5 человек и их изображение (в PCL). Как ссылаться на изображения, если это приложение для Windows Store?

У меня есть привязка, и DataContext установлен в ViewModel в PCL. ViewModel объединяет данные, которые будут отображаться на моделях. Свойство, с которым я связан, - это MyImage. Игнорируя другие платформы, как выглядел бы Ури? Все остальное отлично работает.

Я просто хочу помочь с этими тремя вопросами, хотя я действительно ценю все ответы!!!

4b9b3361

Ответ 1

Во многих случаях изображения зависят от платформы. Они должны удовлетворять размерам и DPI самого устройства и должны соответствовать требованиям внешнего вида приложения. В этих ситуациях я бы сам сам вид решал, какие изображения показывать пользователю, возможно, на основе какого-то состояния/режима, предоставляемого ViewModel.

Однако это случаи, когда изображения должны появляться из ViewModel, например, в случае миниатюр отправителя, которые отображаются в почтовых приложениях. В этих случаях у меня есть ViewModel, возвращающая какую-то платформо-агностическую концепцию изображения (например, byte []), а затем проекты, специфичные для платформы, преобразуют их во что-то, что понимает их стек пользовательского интерфейса (в XAML это будет ImageSource).

Код выглядит примерно так:

Портативный проект:

using System.IO;
using System.Reflection;

namespace Portable
{
    public class ViewModel
    {
        private byte[] _image = LoadFromResource("Image.png");

        public byte[] Image
        {
            get { return _image; }
        }

        private static byte[] LoadFromResource(string name)
        {
            using (Stream stream = typeof(ViewModel).GetTypeInfo().Assembly.GetManifestResourceStream("Portable." + name))
            {
                MemoryStream buffer = new MemoryStream();
                stream.CopyTo(buffer);

                return buffer.ToArray();
            }
        }
    }
}

Примечание. Вам нужно будет удалить или добавить GetTypeInfo() в зависимости от платформ, на которые вы нацеливаетесь.

Здесь мы читаем из встроенного ресурса (Properties → Build Action → Embedded Resource), но вы можете представить, что это происходит из сети или где-то еще.

Проект приложения Windows Store: В приложении Windows Store у вас будет конвертер значений для преобразования из байта [] → ImageSource:

using System;
using System.IO;
using Windows.Storage.Streams;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Media.Imaging;

namespace App
{
    public class ByteToImageSourceValueConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, string language)
        {
            InMemoryRandomAccessStream s = new InMemoryRandomAccessStream();

            byte[] bytes = (byte[])value;
            Stream stream = s.AsStreamForWrite();
            stream.Write(bytes, 0, bytes.Length);
            stream.Flush();
            stream.Seek(0, SeekOrigin.Begin);


            BitmapImage source = new BitmapImage();
            source.SetSource(s);

            return source;           

        }

        public object ConvertBack(object value, Type targetType, object parameter, string language)
        {
            throw new NotImplementedException();
        }
    }
}

В коде, стоящем за View, установите DataContext:

DataContext = new ViewModel();

Затем в самом представлении, привязаном к свойству ViewModel.Image, и установите преобразователь:

<Page.Resources>
    <local:ByteToImageSourceValueConverter x:Name="ImageConverter"/>
</Page.Resources>

<Grid >
    <Image HorizontalAlignment="Left" Height="242" Margin="77,10,0,0" VerticalAlignment="Top" Width="278" Source="{Binding Image, Converter={StaticResource ImageConverter}}"/>

</Grid>

Ответ 2

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

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


Предполагая, что ваше приложение rolodex каким-то образом позволит пользователям записывать изображения, а затем загружать их в какую-то общую базу данных/службу для последующего просмотра, вот как я могу подойти к этой проблеме. Это не единственное решение - здесь нет "одного правильного пути"!

** Захват и загрузка изображений **

  • Для захвата изображения (из папки или из камеры) мне придется использовать собственный крючок для каждой платформы - так что НЕ PCL для этой части

  • Если мне тогда понадобилось сделать некоторую обработку изображения на устройстве (например, изменение размера или добавление миниатюры), то это, вероятно, будет выполняться по-разному на каждой платформе - так что НЕ PCL.

  • Как только у вас есть фотография (например, как JPEG, закодированная в MemoryStream) и вы хотите загрузить ее на сервер, я бы, вероятно, сделал это с помощью асинхронных обработчиков HttpWebRequest (это старые методы, делать с async/await) в общем коде PCL

  • Что работает на сервере... ну, что почти наверняка не является кодом PCL, и я мог бы использовать методы для изменения размера изображения в готовые к установке устройства - например. миниатюры разного размера

** Отображение изображений **

  • Когда мне нужно отобразить какое-то изображение из базы данных, я бы, вероятно, получил сервер, чтобы вернуть список доступных эскизов URL-адресов - это код сервера, поэтому не будет PCL

  • Код приложения, который фактически запрашивает список контактов или контактную информацию, которая, вероятно, будет PCL-кодом, и, вероятно, снова будет использовать HttpWebRequest.

  • Код просмотра, который берет контакт и отображает его на экране? Вероятно, это XAML, и я бы просто использовал собственный элемент управления Image на каждой платформе, чтобы потреблять и отображать соответствующий снимок для этой ситуации.

** Если вы сохраняете изображения локально **

  • Если вы сохраняете изображения локально вместо использования центрального сервера, то вам, вероятно, также понадобится использовать для этого не-PCL-код. Каждая платформа имеет один и тот же базовый тип методов: LoadFile, SaveFile и т.д. - и каждый будет предоставлять механизмы для создания, перечисления, чтения и записи папок и файлов, но каждая платформа делает это с помощью другого API в файловой системе (например, System. IO в WPF, IsolatedStorage в WP7 Silverlight и т.д.).

  • После того, как ваши файлы будут объединены в общую структуру (ish), тогда управляющий код PCL сможет обрабатывать каждый файл как пару строк - папку и имя файла..

  • ... и на вашем уровне пользовательского интерфейса (например, XAML) вы, вероятно, сможете напрямую ссылаться на эти файлы изображений - возможно, это может быть сделано с использованием определенного ValueConverter для генерации правильного имени файла или потока на каждой платформе - например, в wp7 вы можете использовать конвертер из Windows Phone 7 Silverlight, привязывающий изображение от изолированного хранилища


Итак, мое резюме:

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

Некоторые другие вещи, которые могут помочь:

  • В настоящее время мне сложно смешивать .Net4.5 async/await код с "нормальным" кодом - поэтому даже совместное использование сетевого кода может быть довольно сложно сделать - вы можете сэкономить время, если вы напишете отдельный код для всего: (
  • чтобы помочь разделить код, я определенно попытаюсь использовать некоторую форму IoC или DI, чтобы попытаться внедрить определенную реализацию специфичного для платформы кода, где это необходимо (это то, что я делаю много в MvvmCross - и это то, что @dsplaisted рассказывает об обслуживании в http://blogs.msdn.com/b/dsplaisted/archive/2012/08/27/how-to-make-portable-class-libraries-work-for-you.aspx

Ответ 3

Я склонен согласиться с тем, что обработка изображений должна, вероятно, быть специфичной для платформы. Точно так же, как общее правило, все связанные взгляды не должны включаться в PCL. В приведенных выше ответах есть некоторые важные технические детали, которые я не буду повторять, но хотел опубликовать ссылку на слайд-колоду, которую я собрал, чтобы обсудить принципы использования PCL. http://prezi.com/ipyzhxvxjvp-/sharing-is-caring-code-reuse-in-xaml-applications/

Надеюсь, это дает общее руководство по общим стратегиям проектирования и усиливает информацию в предыдущих ответах.

Ответ 4

Большинство людей уже сказали, и ответ также "Невозможно". Элементы пользовательского интерфейса в PCL противоречат философии PCL, которая должна использоваться, как и на всех платформах, на которые вы нацеливаетесь.

Здесь, что MSDN говорит на PCL: "Проект Portable Class Library не содержит компонентов интерфейса из-за поведенческих различий между пользовательскими интерфейсами разных устройств" (от http://msdn.microsoft.com/en-us/library/gg597391.aspx)

надеюсь, что это поможет

Ответ 5

Мой первый инстинкт - сказать нет, у вас не должно быть изображений в вашем PCL, учитывая то, что вы описали.

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

По шкале я имею в виду, что вы открываете источник этой библиотеки, где 1000 программ будут ее использовать. Если это для вашего собственного внутреннего использования для 3 или 4 приложений, я бы сказал, не беспокойтесь, сохраняя свою собственную головную боль. Просто передайте изображение в общую библиотеку или установите его через конфигурацию и сделайте с ней.

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

Ответ 6

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

В ваших портативных ViewModels вы можете ссылаться на изображение через Uri. К сожалению, ури должны быть разными на каждой платформе. Для приложений Windows Store это должно быть что-то вроде ms-appx:////Assets/image.png, где для Windows Phone я думаю, что это будет просто /Assets/image.png.

Итак, вам понадобится код для определения правильного формата Uri. Это может быть специфичный для платформы сервис с портативным интерфейсом, который вызовет ViewModels. Вы также можете создать конвертер привязки, который будет делать любое преобразование, в котором вы нуждаетесь.

Есть, конечно, другие способы сделать это - это именно то, что я выбрал на основе информации в вашем вопросе.

Ответ 7

вы можете поместить изображение на модель представления в качестве типа "объект" и использовать интерфейс (который вводится) для создания растрового изображения.

public interface IBitMapCreator
{
    object Create(string path);
}

public class MyViewModel
{
    private bool _triedToSetThumb;
    private readonly IBitMapCreator _bc;

    public MyViewModel(IBitMapCreator bc, string path)
    {
        _bc = bc;
        SetThumb(path);
    }

    public object Thumb { get; private set; }

    private void SetThumb(string path)
    {
        try
        {
            if (!_triedToSetThumb)
            {
                string ext = Path.GetExtension(path).ToUpper();

                if (
                    ext == ".JPG" ||
                    ext == ".JPEG" ||
                    ext == ".PNG" ||
                    ext == ".GIF" ||
                    ext == ".BMP" ||
                    false
                    )
                {
                    Thumb = _bc.Create(path);
                    OnPropertyChanged(new PropertyChangedEventArgs("Thumb"));
                }
            }
        }
        finally
        {
            _triedToSetThumb = true;
        }
    }

}

в версии WPF, вы можете сделать это

class BitMapCreator : IBitMapCreator
{
    public object Create(string path)
    {
        return BitmapFrame.Create(new Uri(path));
    }
} 

Используя этот метод, вы можете привязать данные к изображению и не нуждаться в конвертере.