2009-12-17 1 views
9

Hier ist das Szenario. Wir verwenden eine große XML-Konfigurationsdatei für eines unserer Serverprodukte. Diese Datei ist ziemlich gut angelegt und wird gegen eine XSD-Datei validiert.Erstellen eines WPF-Editors für eine XML-Datei basierend auf dem Schema

Es ist jetzt Zeit, wenn eine Konfigurations-GUI für die Aufrechterhaltung dieser Datei zu erstellen, und ich möchte in WPF tauchen, es zu tun. Ich könnte für jede Konfigurationssektion ein separates Formular erstellen, jedes Mal, wenn wir eine Option zur Konfigurationsdatei hinzufügen, refactoring und redistribuieren, aber ich hoffe, dass es eine cleverere Methode gibt, dies zu tun.

Da schon habe ich eine stark typisierte xml/XSD Kombination Ich hoffe, mich gibt es eine elegante Methode, eine Benutzeroberfläche für den Aufbau dieses genug, um leicht zu bearbeiten. Ich weiß, dass ich eine xml-> xaml-Transformation schreiben könnte, aber ich hatte gehofft, dass da etwas ist, das das schwere Heben für mich schon erledigt?

Vielen Dank im Voraus ..

Antwort

12

Wie kann ich dies tun würde:

ich durch den Bau einer einfachen Ansicht-Modellklasse beginnen würde, die eine XmlElement um wickelt und setzt sie als Konfigurationsoption. Diese Klasse könnte extrem einfach sein, zum Beispiel:

public class OptionView 
{ 
    private XmlElement XmlElement; 
    public OptionView(XmlElement xmlElement) 
    { 
     XmlElement = xmlElement; 
    } 
    public string Name { get { return XmlElement.Name; } } 
    public string Value 
    { 
     get { return XmlElement.InnerText; } 
     set { XmlElement.InnerText = value; } 
    } 
} 

Jetzt kann ich eine Sammlung von ElementView Objekte aus einem XmlDocument füllen, fügen Sie diese Sammlung an das Fenster des ResourceDictionary und formatieren Sie die Objekte mit einer einfachen DataTemplate, zB:

<DataTemplate x:Key="OptionViewTemplate" DataType={x:Type local:OptionView}> 
    <Grid> 
     <Grid.ColumnDefinitions> 
      <ColumnDefinition SharedSizeGroup="Name"/> 
      <ColumnDefinition SharedSizeGroup="Value"/> 
     </Grid.ColumnDefinitions> 
     <Label Content="{Binding Name}" Grid.Column="0"/> 
     <TextBox Text="{Binding Value}" Grid.Column="1"/> 
    </Grid> 
</DataTemplate> 
... 
<ItemsControl Grid.IsSharedSizeScope="True" 
    ItemsSource="{DynamicResource OptionCollection}"/> 

(Anmerkung:. Später können Sie Lust bekommen, und Subklassen von OptionView zum Beispiel basierend auf definieren, der Datentyp der zugrunde liegenden XmlElement Dann können Sie definieren DataTemplate s für jede Unterklasse, und solange jeder das Element in einem zweispaltigen Raster unter Verwendung dieser SharedSizeGroup darstellt, kann die zweite Spalte eine Datumsauswahl oder Optionsfelder oder alles, was für die Unterklasse geeignet ist, enthalten zur Laufzeit ordentlich angelegt.)

Sobald ich das funktionierte, was nicht lange dauern würde, würde ich beginnen, die OptionView Klasse zu erweitern. Wenn Ihr Schema beispielsweise ein für Menschen lesbares Label für ein Element in einem xs:annotation-Element speichert (und wenn nicht, warum nicht?), Würde ich den Name -Eigenschaftsextrakt aus der -Eigenschaft SchemaInfo machen , anstatt den zugrunde liegenden Elementnamen anzuzeigen.

Offensichtlich würde ich Validierung hinzufügen möchten, also würde ich eine Validierungsmethode hinzufügen, die XmlElement 's SchemaInfo Eigenschaft untersucht und interpretiert. (Wenn Sie davon ausgehen, dass es sich bei den zu überprüfenden Elementen um einfache Inhalte handelt, sollte dies nicht schwierig sein.) Es gibt eine Million Tutorials zur Implementierung der Validierung in WPF-Anwendungen. Daher werde ich hier nicht zu sehr ins Detail gehen.

Wenn es viele Konfigurationsoptionen gibt und Sie sie intelligent in Kategorien einteilen können, würde ich eine höhere Klasse erstellen, die (mindestens) zwei Eigenschaften - eine Zeichenfolge CategoryName Eigenschaft und eine OptionsViews Sammlung - ausfüllt es aus dem XML-Dokument, und fügen Sie es in das Fenster ResourceDictionary. Innerhalb des Fensters ich es an einen TabControl binden würde, z.B .:

<TabControl ItemsSource="{DynamicResource OptionCategories}"> 
    <TabControl.ItemContainerStyle> 
     <Style TargetType="{x:Type CategoryView}"> 
     <Setter Property="Header" Value="{Binding Path=CategoryName}"/> 
     <Setter Property="Content" Value="{Binding Path=OptionsViews}"/> 
     <Setter Property="ContentTemplate" Value="{StaticResource OptionViewTemplate}"/> 
     </Style> 
    </TabControl.ItemContainerStyle> 
</TabControl> 

oder bis zu einem gewissen Punkt Steuerelement, dessen Element Container-Vorlage erstellt eine Expander. Oder so. (Alle Codes garantiert ungeprüft!Das meiste davon wurde jedoch aus den Arbeitsprojekten heraus kopiert.)

Wenn Sie noch nichts mit WPF gemacht haben, ist dies ein ziemlich gutes Projekt. Es wird Ihnen die Grundlagen der Datenbindung und der Elementkontrollen und -validierung zugänglich machen, und das Endergebnis wird etwas sein, das nützlich ist und wahrscheinlich ziemlich gut aussieht.

Und Sie werden feststellen, dass, während das Markup beim Erstellen der Vorlagen ziemlich ausführlich ist, gibt es nur zwei Vorlagen. Der einzige Code in der Anwendung (bisher) ist der Code, der die XmlElement s der Benutzeroberfläche zur Verfügung stellt.

+0

Einige nützliche brainfood es Robert, danke. –

4

Hier gehen Sie, wir haben eine für Ihre Anforderung erstellt. Dieses Tool wurde vollständig erstellt, indem WPF im Hinterkopf behalten wurde.

http://wpfxmleditor.codeplex.com/

+0

Planen Sie eine Freigabe für Ihren Editor? Es ist derzeit nur Quelle und es gibt keinen Hinweis auf den Status des Codes (dh, ist es meist vollständig? Alpha, Beta, stabil?) – jlafay

+0

Ich entschuldige mich für die späte Antwort, ich habe keinen Plan für die Veröffentlichung, können Sie herunterladen und bauen es. – Gomes

0

Um einfache XML-Konfigurationen darzustellen (wenn keine benutzerdefinierten Editoren für Werte erforderlich sind), kann XElement mit HierarchicalDataTemplate direkt an eine Ansicht gebunden werden.

XAML:

<TreeView Grid.IsSharedSizeScope="True" 
      ItemsSource="{Binding Xml.Elements}"> 
    <TreeView.ItemTemplate> 
     <HierarchicalDataTemplate ItemsSource="{Binding Elements}"> 
      <Grid> 
       <Grid.ColumnDefinitions> 
        <ColumnDefinition SharedSizeGroup="Name"/> 
        <ColumnDefinition SharedSizeGroup="Value"/> 
       </Grid.ColumnDefinitions> 
       <Label Content="{Binding Name}" /> 
       <!--Show TextBox only for leaf elements--> 
       <TextBox Grid.Column="1" 
         Text="{Binding Value}" 
         Visibility="{Binding HasElements, 
          Converter={StaticResource reverseBoolToVisibilityConverter}}"/> 
      </Grid> 
     </HierarchicalDataTemplate> 
    </TreeView.ItemTemplate> 
</TreeView> 

Ansicht Modell:

class ConfigViewModel:INotifyPropertyChanged 
{ 
    public XElement Xml { get; private set;} 

    //example of persistence infrastructure 
    public event PropertyChangedEventHandler PropertyChanged = delegate { }; 
    public void Load(string fileName) 
    { 
     Xml = XElement.Load(fileName); 
     PropertyChanged(this, new PropertyChangedEventArgs("Xml")); 
    } 
    public void Save(string fileName) 
    { 
     Xml.Save(fileName); 
    } 
} 

There are some good examples for reversed bool to visibility converter.

Verwandte Themen