0

Einfache XML-Serialisierung in C#

C# XML SerialisierungHeute möchte ich euch zeigen, wie man eine XML-Serialisierung in C# durchführen kann. Serialisierung selbst, bedeutet, dass man ein Objekt in eine andere, transportable Form umwandelt. Mittels XML-Serialisierung ist es uns zum Beispiel nötig, ein Objekt einer Klasse in Form einer XML-Datei abzuspeichern und auch wieder herzustellen.
Das kann Sinn machen, wenn man ein Objekt in seinem Zustand nach dem Schließen und erneuten Öffnen einer Anwendung wiederherstellen oder wenn man ein Objekt beispielsweise per HTTP übertragen möchte.

Für unser Beispiel habe ich folgende Klasse Blog erstellt:

public class Blog
{
    public string User { get; set; }
    public string Pass { get; set; }
    public string Subdomain { get; set; }
    public string BaseUrl { get; set; }
}

Die Methode zum Serialisieren sieht wie folgt aus:

public void SerializeBlogToXML(Blog blogObj)
{
    //Erstelle einen XML-Serialisierer für Objekte vom Typ Blog
    XmlSerializer serializer = new XmlSerializer(typeof(Blog));

    //Erstelle einen FileStream auf die Datei, in die unserer
    //Blog-Objekt in XML-Form gespeichert werden soll.
    FileStream file = new FileStream(Application.StartupPath
                                     + "\\blog.xml",
                                     FileMode.Create);
    //Serialisiere das übergebene Blog-Objekt (blogObj)
    //und schreibe es in den FileStream.
    serializer.Serialize(file, blogObj);

    //Schließe die XML-Datei.
    file.Close();
}

Nicht vergessen die passenden Using-Anweisungen zu schreiben!

using System.Xml.Serialization;
using System.IO;

Ohne diese würde die oben geschriebene Methode SerializeBlogToXML nicht ohne weitere Anpassungen laufen.

Das war es auch schon. Wenn man von meinen Kommentaren absieht, dann reichen ganze 4 Zeilen aus, um ein Objekt als XML-Datei abzuspeichern.

Ein kleines Beispiel zur Verwendung könnte zum Beispiel so aussehen:

private void buttonSerialisieren_Click(object sender, EventArgs e)
{
    //Blog-Objekt erstellen und mit Werten befüllen
    Blog blogObject = new Blog();
    blogObject.User = "maxmustermann";
    blogObject.Pass = "superpasswort";
    blogObject.Url = "www.code-bude.net";

    //Blog-Objekt serialisieren
    SerializeBlogToXML(blogObject);
}

Wenn alles geklappt hat, dürfte sich nun im Ausführungsverzeichnis eures Projektes eine Datei namens Blog.xml befinden. Diese sollte folgenden Inhalt haben:

<?xml version="1.0"?>
<Blog xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <User>maxmustermann</User>
  <Pass>superpasswort</Pass>
  <Url>www.code-bude.net</Url>
</Blog>

Das einzige was jetzt noch fehlt, ist die Konvertierung eines nach XML serialisierten Objekts. Das geht sogar noch ein bisschen leichter, als das umwandeln in’s XML-Format.

public Blog DeserializeXmlToBlog()
{
    XmlSerializer serializer = new XmlSerializer(typeof(Blog));
    FileStream file = new FileStream(Application.StartupPath
                                        + "\\blog.xml",
                                        FileMode.Open);
    //Die Deserialize()-Methode gibt ein Object zurück. => casten!
    Blog blogList = serializer.Deserialize(file) as Blog;
    file.Close();
    return blogList;
}

Zum Abschluss noch mal ein Beispiel, in dem Serialisiert und Deserialisiert wird.

private void buttonSerialisieren_Click(object sender, EventArgs e)
{
    Blog blogObject = new Blog();
    blogObject.User = "maxmustermann";
    blogObject.Pass = "superpasswort";
    blogObject.Url = "www.code-bude.net";

    SerializeBlogToXML(blogObject);
    Blog blogFromXml = DeserializeXmlToBlog();
    MessageBox.Show(blogFromXml.Url);
}

Ich hoffe, ich habe das ganze verständlich genug beschrieben. Solltet ihr dennoch Fragen haben, schreibt mir einfach einen Kommentar.

Wer keine Lust hat, den Code von Hand zu tippen bzw. zu kopieren, der kann sich das Beispiel auch als Visual Studio 2010 Projekt herunterladen.

Viele Grüße,
Raffi

0

Darstellungsfehler von Koreanischen und anderen ausländischen Zeichensätzen in C# / Visual Studio beheben

Ich weiß, der Titel des Posts ist grausam, aber ich wusste das Problem nicht kürzer zu beschreiben. Aber kommen wir nun zur Sache. Im Rahmen der Entwicklung meines Cloud Downloaders stieß ich unter anderem auf folgendes Problem. Koreanische Zeichen wurden nur als blanke Kästchen dargestellt, obwohl Sie im Quelltext korrekt angezeigt wurden. Wer sich jetzt fragt, wo man die koreanischen Zeichen auf einer deutschen Tastatur herbekommt, sollte einfach mal bei Google Translate vorbeischauen. (Der nachfolgende Screenshot veranschaulicht das Problem noch mal. Zum vergrößern bitte das Bild anklicken.)

Koreanische Zeichen falsche Darstellung

Im Netz habe ich nur sehr wenige Lösungen gefunden. Und fast alle waren meiner Meinung nach eher suboptimal. Meistens wird nämlich folgender Weg vorgeschlagen:

Es wird empfohlen die Methode SetCompatibleTextRenderingDefault() mit dem Parameter true aufzurufen. Hierdurch werden Texte mit der auf  GDI+ basierenden Graphics-Methode gerendert, welche zu Zeiten des .Net-Frameworks 1.x genutzt wurde.
Jedoch entstehen hierbei einige “Nachteile”. Zum einen werden die  Abstände bei der Graphics-Methode anders berechnet, sodass ein bestehendes Layout “auseinanderfallen” kann und zum anderen werden nicht alle Controls korrekt gerendert. (Ab .Net 2.0 wurde die auf GDI basierende TextRenderer Klasse eingeführt.)

Bezogen auf unsere Testapplikation sähe das wie folgt aus:

In der Program.cs aktivieren wir das DefaultTextRendering.

 static class Program
    {
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(true);
            Application.Run(new Form1());
        }
    }
}

Und in der Applikation erhalten wir folgendes Ergebnis:
Koreanische Zeichen setcompatibletextrendering(true)
Wie man sieht, wird lediglich das Label korrekt dargestellt. Die Groupbox rendert die Zeichen weiterhin falsch.

Der andere Weg

Eine andere, und meiner Meinung nach eine bessere Lösung, ist der Weg über das Ändern der Schriftart/Font-Property. Es gibt ein paar Schriftarten, die wesentlich mehr Zeichensätze enthalten, als die ganzen Standardschriftarten. Eine davon ist zum Beispiel Arial Unicode MS, welche mit dem Microsoft Office mitgeliefert wird, aber auch auf MacOSX und auch einzeln verfügbar ist.
Setzt man nun diese Schriftart für alle seine Controls, erhält man folgendes Ergebnis:

namespace KoreanCharacters
{
    public partial class Form1 : Form
    {
        // [...]

        private void Form1_Load(object sender, EventArgs e)
        {
            this.Font = new Font("Arial Unicode MS", 8.25f);
            foreach (Control con in GetAllControls(this))
                if (con.Font != null)
                    con.Font = new Font("Arial Unicode MS", 8.25f);

            this.Text = "안녕하세요";
            label1.Text = "안녕하세요";
            groupBox1.Text = "안녕하세요";
        }

        private static List<Control> GetAllControls(Control controlBase)
        {
            List<Control> controls = new List<Control>();
            foreach (Control con in controlBase.Controls)
            {
                controls.Add(con);
                List<Control> subControls = GetAllControls(con);
                controls.AddRange(subControls);
            }
            return controls;
        }
    }
}

Wie man sieht, wird nun auch der Text der Groupbox korrekt dargestellt. Sprich es werden sämtliche Controls, mit Ausnahme des Form-Text, korrekt dargestellt. Deshalb beschrieb ich diese Möglichkeit weiter oben auch nur als “bessere” und nicht als “perfekte” Lösung. Warum der Titel des Forms nicht korrekt gerendert wird, kann ich mir auch nicht erklären.

 

Ich hoffe ich konnte dem ein oder anderen von euch helfen. Standet ihr auch schon vor diesem Problem? Und wie habt ihr es gelöst? Kennt ihr vielleicht sogar eine bessere Lösung? Ich freue mich über jeden Kommentar!

Viele Grüße,
Raffi 

5

Webcam benutzen in C#

Wie steuert man am besten und einfachsten eine Webcam unter Benutzung von C#.Net an? Recherchiert man im Internet, wird man, sofern man überhaupt fündig wird, leider oftmals mit sehr langen Artikeln und unübersichtlichen Snippets konfrontiert. Doch das muss gar nicht sein, denn mit Hilfe der AForge.NET Library geht das ganz einfach. Und wie das genau geht, möchte ich euch im Folgenden Artikel zeigen.

Was wird für dieses Tutorial benötigt?

  • Die AForge.Video.dll, sowie die AForge.Video.DirectShow.dll
    Beide Dlls findet ihr auf der AForge Downloadseite im “(libs only)” zip-Archiv.
  • Eine schlichte WinForms-Anwendung, auf der ihr schon mal eine Picturebox anlegt.

Zuerst bindet ihr die beiden oben genannten Dlls als Referenzen ein. (Ich gehe an dieser Stelle einfach mal davon aus, dass ihr irgend eine Version des Microsoft Visual Studios für die Entwicklung nutzt. Bei anderen IDEs dürfte dieser Schritt jedoch ähnlich sein.)
Bevor wir zum Quellcode kommen, müsst ihr nur noch zwei Eventhandler anlegen. Einen für das FormLoad-Event und einen für das FormClosed-Event. (Am einfachsten geht dies direkt über den Designer des Visual Studios.)
Der Rest erklärt sich über den nachfolgenden Quelltext und dessen Kommentare.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
//Anlegen von Using-Direktiven für einfacheren Zugriff auf die
//benötigten Methoden der AForge Library
using AForge.Video;
using AForge.Video.DirectShow;

namespace aforgeWebcamTutorial
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        //Anlegen eines Webcam-Objektes
        VideoCaptureDevice videoSource;

        private void Form1_Load(object sender, EventArgs e)
        {
            //Anlegen einer Liste mit allen Videoquellen. (Hier können neben der gewünschten Webcam
            //auch TV-Karten, etc. auftauchen)
            FilterInfoCollection videosources = new FilterInfoCollection(FilterCategory.VideoInputDevice);

            //Überprüfen, ob mindestens eine Aufnahmequelle vorhanden ist
            if (videosources != null)
            {
                        //Die erste Aufnahmequelle an unser Webcam Objekt binden
                        //(habt ihr mehrere Quellen, muss nicht immer die erste Quelle die
                        //gewünschte Webcam sein!)
                        videoSource = new VideoCaptureDevice(videosources[0].MonikerString);

                        try
                        {
                            //Überprüfen ob die Aufnahmequelle eine Liste mit möglichen Aufnahme-
                            //Auflösungen mitliefert.
                            if (videoSource.VideoCapabilities.Length > 0)
                            {
                                string highestSolution = "0;0";
                                //Das Profil mit der höchsten Auflösung suchen
                                for (int i = 0; i < videoSource.VideoCapabilities.Length; i++)
                                {
                                    if (videoSource.VideoCapabilities[i].FrameSize.Width > Convert.ToInt32(highestSolution.Split(';')[0]))
                                        highestSolution = videoSource.VideoCapabilities[i].FrameSize.Width.ToString() + ";" + i.ToString();
                                }
                                //Dem Webcam Objekt ermittelte Auflösung übergeben
                                videoSource.DesiredFrameSize = videoSource.VideoCapabilities[Convert.ToInt32(highestSolution.Split(';')[1])].FrameSize;
                            }
                        }
                        catch { }

                        //NewFrame Eventhandler zuweisen anlegen.
                        //(Dieser registriert jeden neuen Frame der Webcam)
                        videoSource.NewFrame += new AForge.Video.NewFrameEventHandler(videoSource_NewFrame);

                        //Das Aufnahmegerät aktivieren
                        videoSource.Start();
            }

        }

        void videoSource_NewFrame(object sender, AForge.Video.NewFrameEventArgs eventArgs)
        {
            //Jedes ankommende Objekt als Bitmap casten und der Picturebox zuweisen
            //(Denkt an das ".Clone()", um Zugriffsverletzungen aus dem Weg zu gehen.)
            pictureBoxVideo.BackgroundImage = (Bitmap)eventArgs.Frame.Clone();
        }

        private void Form1_FormClosed(object sender, FormClosedEventArgs e)
        {
            //Beim Beenden des Programmes die Webcam wieder "freigeben",
            //damit sie von anderen Anwendungen benutzt werden kann.
            if (videoSource != null && videoSource.IsRunning)
            {
                videoSource.SignalToStop();
                videoSource = null;
            }
        }

    }
}

Ich hoffe, dass ihr nun auch im Stande seit, erfolgreich Webcams und andere Videoaufnahmequellen unter C# zu verwenden.
Solltet  ihr noch Fragen, Anregungen oder Kritik haben, so schreibt mir doch einfach einen Kommentar.

Viele Grüße,
Raffi