23

私は、WSA(Windowsストアアプリケーション)、WPF、WP7、WP8を対象とする最初のPCLに取り組んでいます。これはrolerdexのようなアプリケーションであり、連絡先があり、連絡先の詳細と画像があります。(そうではありませんが、アプリケーションの詳細を説明できないため、代わりに非常に単純な例を使用しています)。ここに私の質問のいくつかがあります:)

  1. PCLに画像を含める必要がありますか?

そうであれば:

  1. WSAで使用するために画像をどのように参照しますか?
  2. 異なるプロジェクトで使用する場合、スケール修飾子などを使用してスケーリングを解決するにはどうすればよいですか?

私はデータベースを使用しておらず、画像は外部サービスからダウンロードされていません-画像をローカル、アプリ、またはPCLに保持したいと思います。

編集:画像を表示したいだけです。それでおしまい。これは静的なrolerdexであり、新しい人を追加することはできません。5人の人数とその画像(PCL)を表示したいだけです。Windowsストアアプリケーションの場合、画像を参照するにはどうすればよいですか?

バインディングがあり、DataContextがPCLのViewModelに設定されています。ViewModelは、モデルから表示されるデータを集約します。私がバインドしたプロパティはMyImageです。他のプラットフォームを無視すると、URIはどのようになりますか?他のすべては正常に動作します。

私は本当にこれらの3つの質問について助けが欲しいのですが、私はすべての答えに本当に感謝しています!!!

4

7 に答える 7

23

多くの場合、イメージはプラットフォーム固有です。デバイス自体のサイズとDPIに対応する必要があり、アプリケーションのルックアンドフィールに適合させる必要があります。このような状況では、おそらくViewModelによって提供されるある種の状態/モードに基づいて、View自体にユーザーに表示する画像を決定させます。

ただし、これらは、たとえばメールアプリケーションに表示される送信者のサムネイルの場合など、画像を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();
            }
        }
    }
}

注:ターゲットとするプラットフォームに応じて、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();
        }
    }
}

ビューの背後にあるコードで、DataContextを設定します。

DataContext = new ViewModel();

次に、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>
于 2012-09-20T18:31:36.350 に答える
14

異なるピクセル密度と異なる画面サイズの異なるプラットフォーム間で画像を拡大縮小する必要がある場合、画像は確かに非常に問題があります。

これと相まって、画像操作ライブラリが移植できないという問題がしばしば発生します。特に、各プラットフォームでハードウェアアクセラレーションを使用している場合はそうです。


あなたのローロデックスアプリがどういうわけかユーザーが画像をキャプチャし、後で表示するためにそれらを共有データベース/サービスにアップロードできるようになると仮定すると、これが私が問題に取り組む方法です。これが唯一の解決策ではありません。ここには「正しい方法」はありません。

**画像のキャプチャとアップロード**

  1. (フォルダーまたはカメラから)写真をキャプチャするには、プラットフォームごとにネイティブフックを使用する必要があります。したがって、この部分のPCLではありません。

  2. 次に、デバイス上で画像の処理(たとえば、サイズ変更やサムネイルの追加)を行う必要がある場合、これもプラットフォームごとに異なる方法で行われる可能性があります。PCLではありません。

  3. 写真を(たとえば、MemoryStreamにエンコードされたJPEGとして)取得し、それをサーバーにアップロードしたい場合は、非同期ハンドラーHttpWebRequestを使用してこれを実行します(これらは古いメソッドであり、async / awaitとは関係ありません)一般的なPCLコード

  4. サーバー上で実行されているもの....まあ、それはほぼ確実にPCLコードではありません-そして私はそこでメソッドを使用して画像をデバイス対応サイズにサイズ変更するかもしれません-例えば異なるサイズのサムネイル

**画像を表示しています**

  1. データベースから誰かの画像を表示する必要がある場合、おそらくサーバーに利用可能なサムネイルURLのリストを返してもらうでしょう-これはサーバーコードなので、PCLではありません

  2. 連絡先のリストまたは連絡先の詳細を実際に要求するアプリコード(おそらくPCLコード)であり、おそらくHttpWebRequestを再度使用します。

  3. 連絡先を取得して画面に表示するビューコード?それはおそらくXAMLでしょう-そして私は各プラットフォームでネイティブの画像コントロールを使用して、状況に適したサムネイルを消費してレンダリングします。

**画像をローカルに保存していた場合**

  1. 中央サーバーを使用する代わりにローカルに画像を保存していた場合は、おそらくこれにも非PCLコードを使用する必要があります。各プラットフォームには、LoadFile、SaveFileなどの同じ基本タイプのメソッドがあり、それぞれがフォルダーとファイルを作成、列挙、読み取り、書き込みするメカニズムを提供しますが、各プラットフォームは、ファイルシステム(システムなど)に対して異なるAPIを介してこれを行います。 WPFのIO、WP7 SilverlightのIsolatedStorageなど)。

  2. ファイルをcommon(ish)構造にすると、PCL制御コードは各ファイルを文字列のペア(ファイルが含まれているフォルダーとファイル名)として扱うことができるようになります...

  3. ...そしてUIレイヤー(XAMLなど)では、おそらくこれらの画像ファイルを直接参照できます-おそらく特定のValueConverterを使用して、各プラットフォームで正しいファイル名またはファイルストリームを生成できます-たとえば、wp7ではWindowsPhone7のコンバーター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のサービスの場所
于 2012-09-20T12:27:21.513 に答える
2

画像処理はおそらくプラットフォーム固有である必要があることに同意する傾向があります。原則として、関連するビューはPCLに含めないでください。上記の回答には、繰り返し説明する必要のない優れた技術的詳細が含まれていますが、PCLの使用の原則について説明するためにまとめたスライドデッキへのリンクを投稿したいと思います。http://prezi.com/ipyzhxvxjvp-/sharing-is-caring-code-reuse-in-xaml-applications/

うまくいけば、これは全体的な設計戦略に関するいくつかの一般的なガイダンスを提供し、前の回答の情報を補強します。

于 2012-09-20T12:57:29.640 に答える
2

ほとんどの人はすでに言っており、答えも「不可能」です。PCLのUI要素は、ターゲットとするプラットフォーム間でそのまま使用できるPCLの哲学に反します。

これがMSDNがPCLで言っていることです-「ポータブルクラスライブラリプロジェクトには、異なるデバイスのUI間の動作の違いのため、UIコンポーネントは含まれていません」(http://msdn.microsoft.com/en-us/libraryから) /gg597391.aspx

お役に立てれば

于 2012-09-21T03:26:09.730 に答える
0

私の最初の本能は、あなたが説明したことを考えると、PCLに画像を含めるべきではないと言うことです。

しかし、私がそれを行う場合、画像はさまざまなライブラリのリソースを介して保存でき、プラットフォームごとに異なる画像をそこに保存してから、環境検査を実行して、どの画像を引き出すかを決定できます。ただし、このアプローチは、実際には規模が必要な場合にのみ試行する必要があります。

規模とは、何千ものプログラムが使用するこのライブラリをオープンソーシングしていることを意味します。これが3つまたは4つのアプリの内部使用のためである場合、私はあなた自身の頭痛をわざわざ救わないでください。画像を共有ライブラリに渡すか、設定を介して設定するだけで完了します。

または、PCLを介して画像を管理しないでください。画像操作はプラットフォームごとに異なり、特にあなたが言及したプラットフォームでは異なるためです。そして、他のプラットフォームと同じように機能しないという奇妙なバグに遭遇することになります。

于 2012-09-20T12:46:37.703 に答える
0

私はおそらく実際の画像ファイルを各アプリに入れます。それらをPCLに埋め込もうとしても、あまり価値がないと思います。

ポータブルViewModelでは、URIを介して画像を参照できます。残念ながら、Uriはプラットフォームごとに異なる必要があります。ms-appx:////Assets/image.pngWindows Storeアプリの場合は、WindowsPhoneの場合のようにする必要があります/Assets/image.png

したがって、正しいURI形式を理解するためのコードが必要になります。これは、ViewModelsが呼び出すポータブルインターフェイスを備えたプラットフォーム固有のサービスである可能性があります。また、必要な変換を行うバインディングコンバーターを作成できる場合もあります。

これを行うには確かに他の方法があります-これはあなたの質問の情報に基づいて私が選んだものです。

于 2012-09-20T15:39:00.993 に答える
0

画像を「オブジェクト」タイプとしてビューモデルに配置し、インターフェイス(挿入される)を使用してビットマップを作成できます。

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));
    }
} 

この方法を使用すると、画像に直接データバインドでき、コンバーターは必要ありません。

于 2014-07-08T15:51:48.740 に答える