2009-12-17 8 views
9

Ecco lo scenario. Utilizziamo un grande file di configurazione XML per uno dei nostri prodotti server. Questo file è abbastanza ben disposto ed è validato rispetto a un file XSD.Creazione di un editor WPF per file XML basato sullo schema

È giunto il momento però di costruire una GUI di configurazione per mantenere questo file e mi piacerebbe tuffarmi in WPF per farlo. Potrei creare un modulo separato per ogni sezione di configurazione, refactoring e ridistribuzione ogni volta che aggiungiamo un'opzione al file di configurazione, ma spero che ci sia un modo più intelligente per farlo.

Poiché ho già una combinazione xml/xsd fortemente tipizzata, spero che ci sia un metodo elegante per costruire un'interfaccia utente per modificarlo abbastanza facilmente. So che potrei scrivere una trasformazione xml-> xaml ma speravo che ci fosse qualcosa fuori là per fare già il sollevamento pesante per me?

Grazie in anticipo ..

risposta

12

Come mi piacerebbe fare questo:

mi piacerebbe iniziare con la costruzione di una semplice classe di visualizzazione-modello che avvolge intorno ad un XmlElement e lo espone come un'opzione di configurazione. Questa classe potrebbe essere estremamente semplice, ad esempio:

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; } 
    } 
} 

ora posso compilare una collezione di ElementView oggetti da un XmlDocument, aggiungere che la raccolta alla finestra del ResourceDictionary, e formattare gli oggetti con un semplice DataTemplate, ad esempio:

<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}"/> 

(Nota:. in seguito, è possibile ottenere l'immaginazione, e definire sottoclassi di OptionView sulla base, per esempio, il tipo di dati del sottostante XmlElement Quindi è possibile definire DataTemplate s per ogni sottoclasse, e fintanto che ognuno presenta l'elemento in una griglia a due colonne usando quello SharedSizeGroup, la seconda colonna può contenere un selettore di date, o pulsanti di opzione, o qualunque sia appropriato per la sottoclasse, e sarà tutto

Una volta che ho funzionato, il che non richiederebbe molto, inizierei ad estendere la classe OptionView. Ad esempio, se lo schema memorizza un'etichetta leggibile da un elemento in un elemento xs:annotation (e se non lo è, perché no?), Farei in modo che la proprietà Name estrae quella dalla proprietà SchemaInfo di XmlElement , invece di esporre il nome dell'elemento sottostante.

Ovviamente vorrei aggiungere la convalida, quindi aggiungerei un metodo di convalida che ha esaminato la proprietà SchemaInfo di e l'ha interpretata. (Supponendo che gli elementi che si stanno convalidando siano contenuti semplici, non dovrebbe essere difficile.) Esiste un milione di tutorial su come implementare la convalida nelle applicazioni WPF, quindi non tratterò qui troppi dettagli.

se ci sono tonnellate di opzioni di configurazione e si dispone di un modo intelligente di raggruppandole in categorie, mi piacerebbe costruire una classe di livello superiore che ha esposto (almeno) due proprietà - Una stringa CategoryName proprietà e una raccolta OptionsViews - aumento di popolazione dal documento XML e aggiungerlo alla finestra ResourceDictionary. All'interno della finestra, mi legano ad un TabControl, ad es .:

<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> 

O per un certo controllo elemento il cui elemento contenitore modello crea un Expander. O qualcosa. (Tutto il codice è garantito non testato!La maggior parte è stata copiata da progetti di lavoro, però.)

Se non hai mai fatto nulla con WPF, questo è un buon progetto per iniziare. Ti esporrà ai fondamenti dell'associazione di dati e controlli e convalida di elementi, e il risultato finale sarà qualcosa che è utile e probabilmente sembra abbastanza buono.

E noterete che mentre il markup coinvolto nella creazione dei template è piuttosto dettagliato, ci sono solo due template. L'unico codice nell'applicazione (finora) è il codice che espone i XmlElement all'interfaccia utente.

+0

Alcuni brainfood utile lì Robert, grazie. –

4

Qui, ne abbiamo creato uno per le vostre esigenze. questo strumento è stato completamente creato tenendo presente WPF.

http://wpfxmleditor.codeplex.com/

+0

Hai intenzione di fare una versione per il tuo editor? Attualmente è solo fonte e non c'è alcuna indicazione dello stato del codice (cioè è per lo più completo? Alpha, beta, stabile?) – jlafay

+0

mi dispiace per la risposta in ritardo, non ho alcun piano per il rilascio, è possibile scaricare e compilare esso. – Gomes

0

Per presentare semplici configurazioni xml (se non sono richiesti editor personalizzati per i valori) è possibile collegare direttamente XElement a una vista utilizzando HierarchicalDataTemplate.

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> 

vista del modello:

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.

Problemi correlati