2010-02-13 6 views
4

J'ai un programme simple qui crée une série d'images PNG basées sur une gamme de nombres, à savoir; 1 à 10. Je parcourt chaque numéro et crée une image png de ce nombre, de différentes tailles. Voici le vide que j'utilise pour créer les images.Comment devrais-je traduire cette méthode de Winforms en WPF?

private void CreatePNG(int number, string location, int width, int height) 
     { 
      string filename = number.ToString() + "-" + width.ToString() + "x" + height.ToString() + ".png";    
      Bitmap b = new Bitmap(width, height); 

      Graphics g = Graphics.FromImage((System.Drawing.Image)b); 
      g.FillRectangle(Brushes.White, 0f, 0f, width, height); 

      StringFormat f = new StringFormat(); 
      f.Alignment = StringAlignment.Center; 
      f.LineAlignment = StringAlignment.Center; 
      g.DrawString(number.ToString(), new Font("Helvetica", 55), Brushes.Black, new RectangleF(0, 0, width, height), f); 
      b.Save(location + "\\" + filename, ImageFormat.Png);  
     } 

Ce que je voudrais faire est traduire ce vide pour travailler avec WPF. Je n'ai actuellement aucune expérience avec WPF, d'où ma question noobie.

Le cadre cible est 4.0

L'aide est très appréciée.

+1

Ce code fonctionnera toujours correctement dans une application WPF - il vous suffit d'ajouter une référence à l'assembly System.Drawing. – itowlson

Répondre

9

System.Drawing est une partie de WinForms PAS WPF

D'abord, je veux dissiper un malentendu.

System.Drawing, qui est basé sur GDI + de Win32, est vraiment un composant de WinForms. WPF n'est pas construit dessus, Silverlight et d'autres ports de WPF vers d'autres plateformes ne l'incluront probablement jamais, et il y a beaucoup d'incompatibilités entre les conventions utilisées par System.Drawing (WinForms) et celles utilisées par System.Windows.Media (WPF) . Par exemple, ils utilisent différentes unités de mesure (pixels contre 96dpi fixes), différents types de coordonnées (int vs double), différentes règles pour le dessin au trait, différentes rotations, brushesm différents, mode immédiat vs conservé, etc.

bibliothèques WPF System.Windows.Media sont beaucoup plus puissants que la bibliothèque System.Drawing de WinForms (GDI +). WPF inclut beaucoup plus de transformations, un meilleur support d'opacité, 3D, et d'autres fonctionnalités qui permettent des effets très difficiles avec System.Drawing (GDI +).

Mais le code de la question fonctionnera-t-il de toute façon avec WPF?

Oui, il le fera. Tant que vous exécutez WPF et non un clone comme Silverlight, vous pouvez toujours accéder aux anciennes bibliothèques WinForms. Vous pouvez donc continuer à utiliser les appels System.Drawing pour dessiner votre silhouette. Mais vous ne pouvez pas prendre le bitmap qui en résulte et le plopper simplement dans votre application WPF: Les bitmaps sont incompatibles et comme d'habitude, les bitmaps WPF sont plus puissants. Il existe des moyens de convertir l'image bitmap en un bitmap WPF, ou vous pouvez l'enregistrer dans un format de fichier standard comme .png et le recharger.

Étant donné que le code posé dans la question enregistre réellement l'image bitmap dans un fichier .png, il peut effectivement être utilisé sans modification. Mais si de nouvelles fonctionnalités WPF sont souhaitées dans la création de l'image bitmap, ou si vous souhaitez utiliser l'image bitmap sans enregistrer dans un fichier, vous aurez besoin de techniques spéciales. Alors, pourquoi ne voudriez-vous pas utiliser ce code tel quel? Peut-être que vous le feriez: Si vous faites une application rapide et que vous avez déjà écrit le code, et que vous voulez vraiment stocker les fichiers sur le disque, il y a peu de raison de convertir votre code en WPF. Mais si vous souhaitez utiliser de nouvelles fonctionnalités WPF ou incorporer les images directement dans votre interface utilisateur WPF en utilisant la liaison de données ou d'autres techniques dynamiques, vous pouvez convertir votre programme pour utiliser les bibliothèques de WPF au lieu d'utiliser WinForms. Ceci est un appel de jugement basé sur vos besoins.

Votre question a demandé ce qui était nécessaire pour obtenir ce code pour "travailler avec WPF". La réponse est: Rien. Votre code écrit des fichiers .png ordinaires, WPF lit des fichiers .png ordinaires. Donc ça va marcher. La même chose pourrait être dite si votre code était en COBOL ou Java ou tout autre langage primitif appelant une bibliothèque de dessin Unix à partir des années 90. Tant que le code finit par écrire un fichier .png standard (ou un fichier .gif ou .jpg ou ...) sa sortie fonctionnera avec WPF. Tout comme il y a des raisons impérieuses de ne pas laisser votre code COBOL ou Java, il y a des raisons de ne pas laisser votre code à l'aide System.Drawing:

  1. Dépendance à l'égard System.Drawing qui au fil du temps peuvent ou peuvent ne pas être présent partout WPF peut être utilisé.
  2. limites sur ce que vous pouvez dessiner
  3. modèle de dessin différent que le reste de votre code WPF

Alors, comment aurais-je utiliser WPF pour faire le travail au lieu de WinForms?

Vous pouvez faire une image bitmap de tout ce que vous pouvez afficher dans WPF en utilisant trois étapes simples:

  1. Bâtissez votre WPF visuel en utilisant XAML ou code.
  2. Dans le code, la construction d'une RenderTargetBitmap de la taille désirée puis appelez .Render (visuel)
  3. Soit utiliser le bitmap résultant ailleurs dans votre application ou l'enregistrer en utilisant PngBitmapEncoder ou similaire.

Pour votre exemple particulier, je pourrais utiliser un DataTemplate comme ceci:

<DataTempate x:Key="NumberTemplate"> 
    <TextBlock 
    Background="White" 
    HorizontalAlignment="Center" VerticalAlignment="Center" 
    FontFamily="Helvetica" FontSize="55" 
    Text="{Binding}" 
    /> 
</DataTemplate> 

Ensuite, votre code réel pour écrire le fichier serait:

void CreatePng(int number, string location, int width, int height) 
{ 
    WritePng(location + "/" + number + "-" + width + "x" + height + ".png", 
      new ContentPresenter // Invokes a DataTemplate on its content 
      { 
      Content = number.ToString(), 
      Template = NumberTemplate, 
      Width = width, Height = height 
      }); 
} 

Sinon, vous pouvez omettre le modèle et construisez simplement le TextBlock dans le code à la place du ContentPresenter. Mais un modèle rend très facile de changer rapidement de look et d'ajouter des choses fantaisistes comme l'opacité, les pinceaux de dégradé, les effets bitmap, etc. Je vous recommande donc d'utiliser un template sauf si vous êtes absolument sûr que votre look ne changera jamais.

La méthode WritePng() est un enregistreur de fichier .png générique à une seule trame qui encapsule les fonctionnalités avancées de WPF dans une interface simple. Il serait codé quelque chose comme ceci:

void WritePng(string path, UIElement element) 
{ 
    // Create the bitmep specifying the size, pixel format and DPI 
    var bitmap = new RenderTargetBitmap((int)element.Width, (int)element.Height, 
             96, 96, PixelFormats.Pbgra32); 
    bitmap.Render(element); // At this point the bitmap is usable within WPF 

    // Write to a file: WPF can write multiple frames but we need only one 
    var encoder = new PngBitmapEncoder(); 
    encoder.Frames.Add(BitmapFrame.Create(bitmap)); 
    using(Stream stream = File.Create(path)) 
    encoder.Save(stream); // Could be any stream, not just a file 
} 
+0

Merci Ray, ça a éclairci beaucoup de choses pour moi. –

+2

"System.Drawing fait partie de WinForms ... GDI + est vraiment un composant de WinForms." Non, GDI + est une bibliothèque de dessin à usage général, indépendante de WinForms; ce n'est pas vraiment un "composant" de n'importe quoi d'autre dans .NET. Oui, WinForms utilise GDI + mais pas vice versa. En fait GDI + peut être utilisé à partir du bon vieux Win32! Cela dit, votre point de vue selon lequel utiliser GDI + vous laisse avec deux modèles de dessin différents dans votre base de code est juste, et le RenderTargetBitmap est certainement beaucoup plus idiomatique dans un environnement WPF, donc c'est vraiment un nitpick technique - une excellente réponse. – itowlson

+0

@itowlson: Comme d'habitude, vos commentaires sont sur. J'ai édité le texte pour clarifier ceci. Merci! –

0

Cela fonctionnerait très bien dans WPF, je crois. Il utilise System.Drawing, pas System.Windows.Forms.

+0

Je crains que cette réponse soit trompeuse. System.Drawing fait vraiment partie de l'univers WinForms/GDI +. Tout code qui utilise System.Drawing peut uniquement être utilisé dans WPF en enregistrant l'image résultante dans un fichier (comme cela est fait ici) ou en utilisant WindowsFormsIntegration. Si le code dans la question était Java ou Python appelant X-Windows ou les bibliothèques Qt, sa sortie fonctionnerait aussi bien avec WPF et vous pourriez donner une réponse essentiellement identique, qui est "puisque vous écrivez dans un fichier de toute façon vous pouvez continuer à utiliser la technologie WinForms sans changement. " –

+0

C'est probablement vrai, mais je ne connais pas d'autre moyen. Si vous le savez, vous devriez probablement ajouter une réponse. – icktoofay

+0

Vous avez absolument raison.J'ai pris votre suggestion et ajouté une réponse expliquant pourquoi une personne peut ou non vouloir convertir son code pour utiliser WPF pour créer de telles bitmaps, et montrer approximativement comment le faire si une telle conversion est désirée. Prendre plaisir! –

Questions connexes