none
Aus XSD dynamische GUI generieren RRS feed

  • Frage

  • Moin Leute,

    da ich nun schon unzählige Foren durchsucht und nichts passendes gefunden habe, schreibe ich mal selsbt einen Beitrag.

    Ich habe das Problem, dass ich mehrer XSD's habe und nun ein Programm entwerfen muss, welches eine GUI aus einer XSD generiert (mit Textboxen, Dropdown's, etc.) in dem ich dann Werte eintragen kann und dann daraus ein XML Dokument erstellen kann.

    Hat einer eine Idee/einen Ansatz wie ich hier vorgehen kann?

    Wenn es hilft kann ich auch den Code einer XSD posten.

    MfG Zaro


    • Bearbeitet Zarokar Montag, 23. Oktober 2017 11:37
    Montag, 23. Oktober 2017 11:29

Antworten

  • Nur kurz als Info, habe mein Problem nun selbst gelöst:

    Ich habe in der XSD den Elementen einen eigenen type gegeben, jenachdem was sie später werden sollen (textbox, combobox, etc). Anschließend lasse ich mir mit xsd.exe eine Klasse generieren in der die types jeweils zu einer propertie werden. Danach durchlaufe ich die Klasse mit Reflection und speicher mir die Methodennamen in eine list. Nun brauche ich nur noch die list durchlaufen und mit einem switch jeweils nur noch die richtigen Elemente generieren.

    Grüße Zaro


     Hier noch der Code der XSD:
    <?xml version="1.0" encoding="utf-8"?>
    <xs:schema targetNamespace="http://tempuri.org/XMLSchema.xsd"
        elementFormDefault="qualified"
        xmlns="http://tempuri.org/XMLSchema.xsd"
        xmlns:mstns="http://tempuri.org/XMLSchema.xsd"
        xmlns:xs="http://www.w3.org/2001/XMLSchema">
    
      <xs:complexType name="type_textbox">
        <xs:attribute name="value" type="xs:string"></xs:attribute>
      </xs:complexType>
    
      <xs:complexType name="type_button">
        <xs:attribute name="value" type="xs:int"></xs:attribute>
      </xs:complexType>
    
      <xs:complexType name="root">
        <xs:sequence>
          <xs:element name ="one" type="mstns:type_textbox"></xs:element>
          <xs:element name ="two" type="mstns:type_button"></xs:element>
          <xs:element name ="three" type="mstns:type_textbox"></xs:element>
          <xs:element name ="four" type="mstns:type_textbox"></xs:element>
          <xs:element name ="five" type="mstns:type_button"></xs:element>
          <xs:element name ="six" type="mstns:type_textbox"></xs:element>
          <xs:element name ="seven" type="mstns:type_textbox"></xs:element>
          <xs:choice>
            <xs:element name="alpha" type="xs:string"></xs:element>
            <xs:element name="beta" type="xs:string"></xs:element>
            <xs:element name="gamma" type="xs:string"></xs:element>
          </xs:choice>
        </xs:sequence>
      </xs:complexType>
    
      <xs:element name="root_element" type="mstns:root"></xs:element>
    </xs:schema>

    und der code des Programms:
    using System;
    using System.Collections.Generic;
    using System.Windows.Forms;
    using System.Reflection;
    
    namespace Reflection_test_Form_generieren
    {
        public partial class Form1 : Form
        {
            List<string> properties = new List<string>();
            int location_y = 10, location_x = 10, counter = 0;
    
            public Form1()
            {
                InitializeComponent();
            }
    
            private void button1_Click(object sender, EventArgs e)
            {
                Type type = typeof(root);
    
                // Enum
                string[] enumNames = Enum.GetNames(typeof(ItemChoiceType));
    
                // get all properties of TestClass
                PropertyInfo[] propertyInfos;
                propertyInfos = type.GetProperties();
    
                foreach (PropertyInfo propertyInfo in propertyInfos)
                {
                    properties.Add(propertyInfo.PropertyType.ToString());
                }
    
                listBox1.DataSource = properties;
    
                foreach (string item in properties)
                {
    
                    switch (item)
                    {
                        case "type_textbox":
                            TextBox textBox = new TextBox();
                            textBox.Location = new System.Drawing.Point(location_x, location_y);
                            textBox.Name = "textBox" + counter;
                            textBox.Size = new System.Drawing.Size(145, 25);
                            counter++;
                            location_y += 35;
                            panel1.Controls.Add(textBox);
                            break;
                        case "type_button":
                            Button button = new Button();;
                            button.Location = new System.Drawing.Point(location_x, location_y);
                            button.Name = "button" + counter;
                            button.Size = new System.Drawing.Size(145, 25);
                            button.Text = "Test";
                            counter++;
                            location_y += 35;
                            panel1.Controls.Add(button);
                            break;
                        case "ItemChoiceType":
                            ComboBox comboBox = new ComboBox();
                            comboBox.DataSource = enumNames;
                            comboBox.Location = new System.Drawing.Point(location_x, location_y);
                            comboBox.Name = "comboBox" + counter;
                            comboBox.Size = new System.Drawing.Size(145, 25);
                            comboBox.DropDownStyle = ComboBoxStyle.DropDownList;
                            counter++;
                            location_y += 35;
                            panel1.Controls.Add(comboBox);
                            break;
                        default:
                            break;
                    }
                }
            }
        }
    }



    • Als Antwort markiert Zarokar Donnerstag, 26. Oktober 2017 13:18
    • Bearbeitet Zarokar Donnerstag, 26. Oktober 2017 13:51
    Donnerstag, 26. Oktober 2017 13:18

Alle Antworten

  • Hallo Zarokar,

    XSD steht für XML Schema Definition, eine Beschreibung wie ein XML Dokument konform zu diesem Schema auszusehen hat. Eine XSD beschreibt keine Benutzeroberfläche und hat damit auch gar nichts zu tun, darum findest Du dazu auch nichts in Foren.

    Hat einer eine Idee/einen Ansatz wie ich hier vorgehen kann?

    Natürlich kann man alles machen... . Für eine XSD bedeutet dies, dass dein Ergebnis genauso beliebig kompliziert sein müsste, wie es eine XSD sein kann. Du müsstest dich also mit jeder Feinheit der XSD Spezifikation auseinander setzen und dir eine GUI Ausprägungen dazu Überlegen, welche deinen Anwendern genehm sein könnten.


    - Gruß Florian

    Dienstag, 24. Oktober 2017 07:31
  • Hey,

    das ist keine triviale Aufgabe. Du müsstest alle einfachen Datentypen auf Standard-Controls abbilden, d.h. ein String wird durch eine TextBox dargestellt, ein Date durch einen DatePicker etc.

    Die komplexen Typen sind dann Anordnungen der einfachen Controls (oder anderer komplexer Typen), die könnte man vielleicht durch User Controls oder Templates erstellen. Und weil man ja meistens viele Instanzen der komplexen Typen hat, wäre ein Button zum Hinzufügen nicht schlecht.

    Wahrscheinlich würde ich damit starten, mein Data Model aus der XSD zu generieren, um die XSD-Attribute in C# abbilden zu können, und danach für jede Klasse das GUI generieren.

    Beste Grüße


    Vergiss nicht, die Antwort auf deine Frage zu markieren und hilfreiche Beiträge zu bewerten, damit auch andere schnell die Lösung für ihr Problem finden können - und wir nebenbei noch ein paar Punkte verdienen. :)

    Dienstag, 24. Oktober 2017 19:46
  • Hallo Flogex,

    danke, das hat mir schonmal um einiges weiter geholfen :)

    Grüße

    Mittwoch, 25. Oktober 2017 13:20
  • Nur kurz als Info, habe mein Problem nun selbst gelöst:

    Ich habe in der XSD den Elementen einen eigenen type gegeben, jenachdem was sie später werden sollen (textbox, combobox, etc). Anschließend lasse ich mir mit xsd.exe eine Klasse generieren in der die types jeweils zu einer propertie werden. Danach durchlaufe ich die Klasse mit Reflection und speicher mir die Methodennamen in eine list. Nun brauche ich nur noch die list durchlaufen und mit einem switch jeweils nur noch die richtigen Elemente generieren.

    Grüße Zaro


     Hier noch der Code der XSD:
    <?xml version="1.0" encoding="utf-8"?>
    <xs:schema targetNamespace="http://tempuri.org/XMLSchema.xsd"
        elementFormDefault="qualified"
        xmlns="http://tempuri.org/XMLSchema.xsd"
        xmlns:mstns="http://tempuri.org/XMLSchema.xsd"
        xmlns:xs="http://www.w3.org/2001/XMLSchema">
    
      <xs:complexType name="type_textbox">
        <xs:attribute name="value" type="xs:string"></xs:attribute>
      </xs:complexType>
    
      <xs:complexType name="type_button">
        <xs:attribute name="value" type="xs:int"></xs:attribute>
      </xs:complexType>
    
      <xs:complexType name="root">
        <xs:sequence>
          <xs:element name ="one" type="mstns:type_textbox"></xs:element>
          <xs:element name ="two" type="mstns:type_button"></xs:element>
          <xs:element name ="three" type="mstns:type_textbox"></xs:element>
          <xs:element name ="four" type="mstns:type_textbox"></xs:element>
          <xs:element name ="five" type="mstns:type_button"></xs:element>
          <xs:element name ="six" type="mstns:type_textbox"></xs:element>
          <xs:element name ="seven" type="mstns:type_textbox"></xs:element>
          <xs:choice>
            <xs:element name="alpha" type="xs:string"></xs:element>
            <xs:element name="beta" type="xs:string"></xs:element>
            <xs:element name="gamma" type="xs:string"></xs:element>
          </xs:choice>
        </xs:sequence>
      </xs:complexType>
    
      <xs:element name="root_element" type="mstns:root"></xs:element>
    </xs:schema>

    und der code des Programms:
    using System;
    using System.Collections.Generic;
    using System.Windows.Forms;
    using System.Reflection;
    
    namespace Reflection_test_Form_generieren
    {
        public partial class Form1 : Form
        {
            List<string> properties = new List<string>();
            int location_y = 10, location_x = 10, counter = 0;
    
            public Form1()
            {
                InitializeComponent();
            }
    
            private void button1_Click(object sender, EventArgs e)
            {
                Type type = typeof(root);
    
                // Enum
                string[] enumNames = Enum.GetNames(typeof(ItemChoiceType));
    
                // get all properties of TestClass
                PropertyInfo[] propertyInfos;
                propertyInfos = type.GetProperties();
    
                foreach (PropertyInfo propertyInfo in propertyInfos)
                {
                    properties.Add(propertyInfo.PropertyType.ToString());
                }
    
                listBox1.DataSource = properties;
    
                foreach (string item in properties)
                {
    
                    switch (item)
                    {
                        case "type_textbox":
                            TextBox textBox = new TextBox();
                            textBox.Location = new System.Drawing.Point(location_x, location_y);
                            textBox.Name = "textBox" + counter;
                            textBox.Size = new System.Drawing.Size(145, 25);
                            counter++;
                            location_y += 35;
                            panel1.Controls.Add(textBox);
                            break;
                        case "type_button":
                            Button button = new Button();;
                            button.Location = new System.Drawing.Point(location_x, location_y);
                            button.Name = "button" + counter;
                            button.Size = new System.Drawing.Size(145, 25);
                            button.Text = "Test";
                            counter++;
                            location_y += 35;
                            panel1.Controls.Add(button);
                            break;
                        case "ItemChoiceType":
                            ComboBox comboBox = new ComboBox();
                            comboBox.DataSource = enumNames;
                            comboBox.Location = new System.Drawing.Point(location_x, location_y);
                            comboBox.Name = "comboBox" + counter;
                            comboBox.Size = new System.Drawing.Size(145, 25);
                            comboBox.DropDownStyle = ComboBoxStyle.DropDownList;
                            counter++;
                            location_y += 35;
                            panel1.Controls.Add(comboBox);
                            break;
                        default:
                            break;
                    }
                }
            }
        }
    }



    • Als Antwort markiert Zarokar Donnerstag, 26. Oktober 2017 13:18
    • Bearbeitet Zarokar Donnerstag, 26. Oktober 2017 13:51
    Donnerstag, 26. Oktober 2017 13:18