2010-06-29 12 views
10

Mi chiedo se sia possibile fare qualcosa. Ho una funzione che legge un file xml e aggiunge controlli a un modulo basato sul contenuto del file. Un nodo XML come questo creerà esso:Posso avere un tipo di "classe" in C#?

<Button Top="300" Left="100">Automatic</Button> 

Ho una funzione che consente di salvare i comandi al file XML se ho aggiunto alcun in modalità di modifica. Funziona, ma mi chiedo se c'è un modo più semplice. Attualmente, ho il codice che assomiglia a questo per creare un'istanza di ogni controllo:

  switch (xmlchild.Name) 
      { 
       // Create a new control whose type is specified. 
       case "Button": 
        c = new Button(); 
        break; 
       case "Label": 
        c = new Label(); 
        break; 
       default: 
        c = null; 
        break; 
      } 

Ma, quando voglio usare più tipi di controlli, ho bisogno di continuare ad aggiungere i casi di commutazione. Posso fare qualcosa che prenderà semplicemente il testo e aggiungerà un controllo di quel tipo? Gradirò ogni feedback!

Grazie!

+0

È possibile ad esempio chiamare le classi "MyXml *" dove * è Button, Label ecc. E utilizzare reflection. – simendsjo

+0

se si utilizza WPF è possibile utilizzare le classi XamlReader/Writer –

risposta

2

Se si controlla il contenuto del file XML, quindi sì. È possibile utilizzare:

string fullNameSpace = "System.Windows.Controls."; 
Type controlType = Type.GetType(fullNameSpace + xmlchild.Name); 
if(controlType != null) 
{ 
    // get default constructor... 
    ConstructorInfo ctor = controlType.GetConstructor(Type.EmptyTypes); 
    object control = ctor.Invoke(null); 
} 

si potrebbe anche utilizzare la classe Activator per pulire questo un po ':

object control = Activator.CreateInstance("System.Windows.Presentation", 
              xmlchild.Name); 

In alternativa, se è possibile creare un file XAML valida, è possibile utilizzare XamlReader per ripristinare il albero di controllo.

+0

+1: Grazie per avermi insegnato su Type.EmptyTypes (e anche una buona risposta, ma posso solo upvotare una volta) –

+0

+1 Anche se il codice sopra funzionerà, uno il problema è che il nome del tipo deve essere corretto in modo che lo sviluppatore non possa/non possa sfuggire al controllo del nome del controllo. Alla fine ci sarà un metodo di controllo degli errori con un interruttore simile o un blocco/else. –

+0

@Paul - o un bel grande 'try ... catch (Exception)' ... OK, forse uno più piccolo con un tipo di eccezione più specifico, ma NON DEVE controllarlo prima del tempo. –

1

È possibile utilizzare alcune convenzioni per risparmiare un po 'di codice. Fondamentalmente, usa reflection per creare un'istanza di qualunque controllo tu voglia, passando il codice dall'XML. Qualcosa del tipo:

Activator.CreateInstance(xmlchild.Name, ...) 

Basta inserire i bit giusti e molto codice va via.

1

Sembra che tu stia cercando qualcosa come Generics.

Si potrebbe fare qualcosa nel modo seguente:

public static class ControlFactory 
{ 
    public static T CreateControl<T>() where T : Type, new() 
    { 
     return new T(); 
    } 
} 

Non ho ancora testato questo codice così sarò aggiornarlo come ho test.

1

Vedere la classe di attivatori in primo luogo. Quindi è possibile memorizzare il nome tipo del controllo come attributo nel file xml e utilizzare la classe Activator per creare istanze basate sul valore memorizzato in un attributo dall'elemento xml corrente (type = "fullTypeName").

Inoltre, se si tratta di proprietà, è possibile considerare la riflessione per impostare le proprietà sulle istanze create in base al nome di un attributo (ovvero si dispone di un'istanza di un controllo - creata con la classe Activator - e si assegna il valore dal Top attributo in xml alla proprietà Top dell'istanza creata che è possibile ottenere/impostare utilizzando reflection).

1

È possibile utilizzare Reflection come altri hanno descritto per costruire il controllo direttamente dal suo nome. Tuttavia, questo design è abbastanza fragile e potrebbe anche porre problemi di sicurezza se il file XML è pubblicamente visibile, dal momento che i tipi di controllo arbitrario possono essere costruiti in fase di esecuzione in base al testo nel file. Questo potrebbe non essere un problema per la tua particolare applicazione.

Preferirei un disegno utilizzando Dictionary<string, Func<Control>>, in cui è presente il codice che registra un callback che crea il controllo per ciascun nome.Questo ti dà una certa flessibilità (puoi cambiare dinamicamente i metodi di costruzione dei controlli o combinare i controlli disponibili da più fonti) e può anche sembrare più pulito (l'interruttore viene sostituito con alcune chiamate di "registrazione" e la costruzione effettiva è suddivisa in metodi separati o (nel caso semplice) come espressione lambda). Ciò consente anche la retrocompatibilità se si sostituisce il TextBox nella propria applicazione con MyImprovedTextBox e si desidera che i precedenti file di configurazione utilizzino la versione migliorata.

Problemi correlati