Comment puis-je travailler avec des images dans une bibliothèque de classe portable ciblant Windows Store Apps et WP7,WP8,WPF?
je travaille sur un premier PCL qui cible : WSA (Windows Store Application), WPF,WP7,WP8. Nous pouvons dire que c'est un type d'application rolerdex, vous avez des contacts , ils ont des coordonnées et des images. (ce n'est pas le cas, mais je ne peux pas donner de détails sur l'application, donc j'utilise un exemple très simple à la place). Voici quelques unes de mes questions :)
- dois-je avoir les images dans le PCL?
si oui:
- comment référencer l'image pour l'utiliser dans WSA?
- comment résoudre au mieux la mise à l'échelle avec les qualificatifs scale etc. lorsque utilisées dans les différents projets?
Je n'utilise pas de base de données et les images ne sont pas téléchargées à partir d'un service externe - je voudrais garder les images (pas beaucoup vraiment) localement, dans l'application ou dans le PCL.
EDIT: Je veux juste Afficher des images. C'est tout. C'est un statique rolerdex, tu ne peux pas ajouter de nouvelles personnes. Je veux juste afficher 5 nombre de personnes et de leur image (dans le PCL). Comment référencer les images si C'est une application Windows Store?
j'ai un binding et le DataContext est défini à un ViewModel dans la PCL. Le ViewModel regroupe les données à afficher à partir des modèles. La propriété contre laquelle je me suis engagé est MyImage. En ignorant les autres plateformes, à quoi ressemblerait L'Uri? Tout le reste fonctionne bien.
je veux vraiment de l'aide avec ces trois questions, bien que j'apprécie vraiment toutes les réponses!!!
7 réponses
Pour beaucoup de cas, les images sont spécifiques à la plateforme. Ils doivent tenir compte de la taille et des DPI de l'appareil lui-même, et devrait s'adapter à l'apparence et à la sensation de l'application. Pour ces situations, j'aurais la Vue elle-même décider quelles images à montrer à l'utilisateur, probablement basé sur une sorte d'état/mode fournie par le ViewModel.
cependant, ce sont des cas où les images doivent provenir du modèle de vue, par exemple, dans le cas de l'expéditeur les vignettes qui s'affichent dans les applications de messagerie. Dans ces cas, J'ai le modèle de vue qui renvoie une sorte de concept plate-forme-agnostique d'une image (comme byte[]), et puis les projets spécifiques à la plate-forme le convertissent en quelque chose que leur pile D'UI comprend (dans XAML, ce serait une source ImageSource).
le code ressemblerait à quelque chose comme ceci:
Portables du projet :
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();
}
}
}
}
Note: vous devrez supprimer ou ajouter GetTypeInfo() en fonction des plates-formes que vous ciblez.
ici, nous lisons à partir d'une ressource intégrée (propriétés -> Build Action -> Embedded Resource), mais vous pouvez imaginer cela venant du réseau, ou ailleurs.
Windows Store app project: Dans L'application Windows Store, vous auriez un convertisseur de valeur pour convertir de 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();
}
}
}
dans le code derrière la vue, réglez le DataContext:
DataContext = new ViewModel();
puis dans la vue elle-même liant au modèle de vue.Propriété de l'Image, et régler le convertisseur:
<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>
sont en effet assez problématiques lorsque vous avez besoin de les dimensionner sur différentes plateformes avec différentes densités de pixels et différentes tailles d'écran.
couplé à cela, il ya souvent des problèmes avec les bibliothèques de manipulation d'image ne sont pas portables - surtout quand ils utilisent l'accélération matérielle sur chaque plate-forme.
en supposant que votre application rolodex va en quelque sorte permettre aux utilisateurs de capturer des images, et puis pour les télécharger dans une base de données/un service partagé pour les visionner plus tard, voici comment je pourrais aborder le problème. Ce n'est pas la seule solution il n'y a pas de "bonne façon" ici!
** la Capture et le transfert d'images **
-
pour capturer l'image (soit à partir d'un dossier ou d'un appareil photo) je devrais utiliser un crochet natif pour chaque plate - forme- donc pas PCL pour cette partie
-
si je nécessaire pour faire un traitement sur le périphérique de l'image (par exemple redimensionner ou ajouter une vignette), puis encore, cela serait probablement fait différemment sur chaque plate - forme-donc pas PCL.
-
une fois que vous avez la photo (par exemple comme un JPEG encodé dans un MemoryStream) et que vous voulez la télécharger sur un serveur, alors je le ferais probablement en utilisant les gestionnaires asynchrones HttpWebRequest (ce sont les anciennes méthodes, rien à voir avec async/wait) dans le code PCL commun
-
Ce qui est en cours d'exécution sur le serveur.... Eh bien, ce n'est presque certainement pas le code PCL - et je pourrais utiliser des méthodes là - bas pour redimensionner l'image en tailles prêtes à l'emploi-par exemple des vignettes de tailles différentes
* * affichage des images * *
-
quand j'ai besoin d'afficher l'image de quelqu'un à partir de la base de données, alors je demanderais probablement au serveur de retourner une liste des URLs des vignettes disponibles - c'est le code du serveur donc ne serait pas PCL
-
le code app qui demande la liste des contacts ou les détails de contact - qui serait probablement le code PCL - et utiliserait probablement HttpWebRequest à nouveau.
-
le code de vue qui prend le contact et le rend sur l'écran? Ce serait probablement XAML - et j'utiliserais simplement le contrôle d'Image natif sur chaque plate-forme pour consommer et rendre vignette adaptée à la situation.
* * si vous stockiez les images localement * *
-
si vous stockiez les images localement au lieu d'utiliser un serveur central, vous aurez probablement besoin d'utiliser un code non-PCL pour cela aussi. Chaque plate - forme a le même type de base de méthodes: LoadFile, SaveFile, etc-et chacun fournira des mécanismes pour créer, énumérer, lire et écrire des dossiers et des fichiers, mais chaque plate-forme le fait via une API différente du système de fichiers (par exemple Système.IO in WPF, IsolatedStorage in WP7 Silverlight, etc.).
-
une fois que vous avez vos fichiers dans une structure(ish) commune, alors le code de contrôle PCL sera en mesure de traiter chaque fichier comme une simple paire de chaînes - le dossier dans lequel il se trouve et le nom du fichier...
-
... et dans votre couche UI (par exemple XAML) vous pourrez probablement faire référence ces fichiers d'image directement - probablement peut être fait en utilisant un ValueConverter spécifique pour générer le bon nom de fichier ou filestream sur chaque plate - forme-par exemple, dans wp7 vous pouvez utiliser le convertisseur de Windows Phone 7 Silverlight image de liaison de L'IsolatedStorage
donc, mon résumé est:
- j'utiliserais le code PCL partout où je pourrais
- mais en la réalité est que le code PCL ne sera que dans le contrôle et la mise en réseau - pas dans la collection d'image, le traitement d'image ou le rendu d'image
D'autres choses qui pourraient aider:
- actuellement, je trouve que c'est assez difficile à mélanger .Net4.5 code async / wait avec code "normal" - donc même partager le code réseau peut être assez difficile à faire - vous pourriez réellement gagner du temps si vous écrivez un code séparé pour tout : (
- pour aider à partager le code, je voudrais certainement essayer d'utiliser une certaine forme de IoC ou de DI pour essayer d'injecter une mise en œuvre spécifique du code spécifique à la plate - forme là où il est nécessaire (c'est ce que je fais beaucoup dans MvvmCross-et c'est ce dont @dsplaisted parle dans le lieu de service dans http://blogs.msdn.com/b/dsplaisted/archive/2012/08/27/how-to-make-portable-class-libraries-work-for-you.aspx
j'ai tendance à être d'accord que la gestion des images devrait probablement être la plate-forme. En règle générale, tout ce qui concerne une vue ne doit pas être inclus dans une LPC. Les réponses ci-dessus ont quelques grands détails techniques que je ne vais pas me donner la peine de répéter, mais a voulu poster un lien à un diaporama que j'ai mis en place pour discuter des principes de L'utilisation de PCL. http://prezi.com/ipyzhxvxjvp-/sharing-is-caring-code-reuse-in-xaml-applications/
espérons que cela donne quelques conseils généraux sur les stratégies globales de conception et renforce l'information dans les réponses précédentes.
la plupart des gens ont déjà dit et la réponse est aussi "pas possible". Les éléments D'interface utilisateur dans PCL vont à l'encontre de la philosophie de PCL, qui devrait être utilisable comme c'est à travers les plates-formes que vous ciblez.
Voici ce que MSDN est-à-dire sur la PCL - " la Bibliothèque de classes Portable de projet ne contiennent pas de composants de l'INTERFACE utilisateur en raison de différences de comportement entre l'Isu de différents appareils " (de http://msdn.microsoft.com/en-us/library/gg597391.aspx )
espérons que cette aide
mon premier instinct est de dire non vous ne devriez pas avoir d'images dans votre PCL compte tenu de ce que vous avez décrit.
mais si j'allais le faire les images peuvent être stockées via des ressources dans les différentes bibliothèques et vous pouvez stocker une image différente pour chaque plate-forme là-dedans et puis faire une inspection de L'environnement pour déterminer quelle image sortir. Mais cette approche ne devrait vraiment être tentée que si vous avez besoin d'échelle.
par échelle je veux dire que vous êtes ouvert se procurer cette bibliothèque où des milliers de programmes vont l'utiliser. Si cela est pour votre propre utilisation interne pour 3 ou 4 applications, je dirais que ne vous embêtez pas sauver votre auto le mal de tête. Il suffit de passer l'image dans la bibliothèque partagée ou de la configurer via une configuration et de l'utiliser.
ou tout simplement ne pas gérer les images via le PCL. Parce que la manipulation d'image change et est différente sur toutes les plateformes, surtout celles que vous avez mentionnées. Et tu vas tomber sur un insecte bizarre où il juste ne fonctionne pas de la même façon que sur les autres plates-formes.
je mettrais probablement les fichiers image réels dans chaque application. Je ne pense pas que vous obtenez beaucoup de valeur en essayant de les intégrer dans la PCL.
dans vos modèles de vue portables, vous pouvez référencer l'image via un Uri. Malheureusement, cette Uri doit être différente sur chaque plate-forme. Pour Windows Store apps il doit être quelque chose comme ms-appx:////Assets/image.png
où Pour Windows Phone je pense qu'il sera juste /Assets/image.png
.
donc vous aurez besoin d'un peu de code pour calculer le bon format d'Uri. Il pourrait s'agir d'un service spécifique à une plate-forme avec une interface portable que les Modèles de vue appelleraient. Vous pourriez également être en mesure de créer un convertisseur de liaison qui ferait n'importe quelle conversion dont vous aviez besoin.
il y a certainement d'autres façons de faire cela-- c'est exactement ce que j'ai choisi d'après les informations contenues dans votre question.
vous pouvez mettre l'image sur le modèle de vue comme le type" objet " et utiliser une interface (qui est injecté) pour créer le bitmap.
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;
}
}
}
dans la version WPF, vous pouvez faire ceci
class BitMapCreator : IBitMapCreator
{
public object Create(string path)
{
return BitmapFrame.Create(new Uri(path));
}
}
en utilisant cette méthode, vous pouvez lier les données directement à l'image et n'avez pas besoin d'un convertisseur.