如何在面向Windows应用商店应用和WP7,WP8,WPF的便携式类库中处理图像?

Iri*_*son 23 wpf portable-class-library microsoft-metro windows-runtime

我正在开发第一个针对以下目标的PCL:WSA(Windows应用商店应用),WPF,WP7,WP8.我们可以说它是一种rolerdex类型的应用程序,你有联系人,他们有联系方式和图像.(它不是,但我无法提供有关应用程序的详细信息,因此我使用的是一个非常简单的示例).以下是我的一些问题:)

  1. 我应该在PCL中有图像吗?

如是:

  1. 如何在WSA中引用图像?
  2. 在不同项目中使用时,如何使用比例限定符等最好地解决缩放问题?

我没有使用数据库而且图像不是从外部服务下载的 - 我想在本地,应用程序或PCL中保存图像(实际上并不多).

编辑:我只是想显示图像.而已.这是一个静态的rolerdex,你不能添加新的人.我只是想显示5个人和他们的形象(在PCL中).如果图像是Windows应用商店应用,如何引用图像?

我有一个绑定,DataContext设置为PCL中的ViewModel.ViewModel聚合要从模型显示的数据.我绑定的属性是MyImage.忽略其他平台,Uri会是什么样子?其他一切都很好.

我真的只想帮助解决这三个问题,尽管我非常感谢所有答案!

Dav*_*ean 23

对于很多情况,图像是特定于平台的.它们需要满足设备本身的尺寸和DPI,并且需要适应应用程序的外观和感觉.对于这些情况,我可能会让View自己决定向用户显示哪些图像,可能是基于ViewModel提供的某种状态/模式.

但是,这些是图像需要来自ViewModel的情况,例如,在邮件应用程序中显示的发件人缩略图的情况下.在这些情况下,我让ViewModel返回某种与平台无关的图像概念(例如byte []),然后让特定于平台的项目将其转换为UI堆栈理解的内容(在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();
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

注意:您需要删除或添加GetTypeInfo(),具体取决于您要定位的平台.

这里我们从嵌入式资源(属性 - >构建操作 - >嵌入式资源)中读取,但您可以想象这来自网络或其他地方.

Windows应用商店应用项目: 在Windows应用商店应用中,您将有一个值转换器从byte [] - > 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();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

在View后面的代码中,设置DataContext:

DataContext = new ViewModel();
Run Code Online (Sandbox Code Playgroud)

然后在View本身绑定到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>
Run Code Online (Sandbox Code Playgroud)


Stu*_*art 13

当您需要在具有不同像素密度和不同屏幕尺寸的不同平台上缩放图像时,图像确实存在问题.

与此相伴,图像处理库经常出现无法移植的问题 - 尤其是当他们在每个平台上使用硬件加速时.


假设你的rolodex应用程序以某种方式允许用户捕获图像,然后将它们上传到某个共享数据库/服务供以后查看,这就是我如何处理问题.这不是唯一的解决方案 - 这里没有"正确的方法"!

**捕获和上传图像**

  1. 为了捕获图片(从文件夹或从相机),我将不得不为每个平台使用本机钩子 - 所以不要PCL这个部分

  2. 如果我然后需要对图像进行一些设备上的处理(例如调整大小或添加缩略图),那么这可能会在每个平台上以不同的方式完成 - 所以不是PCL.

  3. 一旦你有照片(例如在MemoryStream中编码为JPEG)并想将其上传到服务器,那么我可能会使用异步处理程序HttpWebRequest(这些是旧方法,与async/await无关)在常见的PCL代码中

  4. 什么在服务器上运行....好吧,这几乎肯定不是PCL代码 - 我可能会使用那里的方法将图像调整为设备就绪尺寸 - 例如不同尺寸的缩略图

**显示图片**

  1. 当我需要从数据库中显示某人的图像时,我可能会让服务器返回一个可用的缩略图URL列表 - 这是服务器代码所以不是PCL

  2. 应用程序代码实际上要求联系人列表或联系人详细信息 - 可能是PCL代码 - 并且可能会再次使用HttpWebRequest.

  3. 获取联系人并在屏幕上呈现它的View代码?这可能是XAML - 我只是在每个平台上使用本机Image控件来使用和呈现适当的缩略图.

**如果您在本地存储图像**

  1. 如果您在本地存储图像而不是使用中央服务器,那么您可能也需要使用非PCL代码.每个平台都有相同的基本类型的方法:LoadFile,SaveFile等 - 每个平台都提供创建,枚举,读取和写入文件夹和文件的机制,但每个平台都通过与文件系统不同的API(例如System)来实现. WPF中的IO,WP7 Silverlight中的IsolatedStorage等).

  2. 一旦你的文件进入一个公共(ish)结构,那么PCL控制代码就能将每个文件视为一对字符串 - 它所在的文件夹和文件名......

  3. ...在您的UI层(例如XAML)中,您可能可以直接引用这些图像文件 - 可能可以使用特定的ValueConverter在每个平台上生成正确的文件名或文件流 - 例如在wp7中您可以使用来自Windows Phone 7的转换器来自IsolatedStorage的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