2008-12-04 7 views
3

Disons que je simple chunck XML: -XML Binding dans Silverlight sans classes nominales

<root> 
    <item forename="Fred" surname="Flintstone" /> 
    <item forename="Barney" surname="Rubble" /> 
</root> 

Après avoir récupéré ce XML dans Silverlight Je voudrais lier avec XAML de cette ilke: -

<ListBox x:Name="ItemList" Style="{StaticResource Items}"> 
    <ListBox.ItemTemplate> 
     <DataTemplate> 
      <StackPanel Orientation="Horizontal">   
       <TextBox Text="{Binding Forename}" /> 
       <TextBox Text="{Binding Surname}" /> 
      </StackPanel> 
     </DataTemplate> 
    </ListBox.ItemTemplate> 
</ListBox> 

maintenant, je peux lier assez simplement avec LINQ to XML et une classe nominale: -

public class Person { 
    public string Forename {get; set;} 
    public string Surname {get; set;} 
} 

Peut-il être fait sans cette classe?

En d'autres termes, le couplage entre le code et le code XML Silverlight d'entrée est limitée à la seule XAML, un autre code source est agnostique à l'ensemble des attributs de l'élément de l'article.

Édition: L'utilisation de XSD est suggérée mais finalement elle revient à la même chose. XSD-> Classe générée.

Modifier: Une classe anonyme ne fonctionne pas, Silverlight ne peut pas les lier.

Modifier: Cela doit être bidirectionnel, l'utilisateur doit pouvoir modifier les valeurs et ces valeurs se retrouvent dans le fichier XML. (Changé TextBlock originale TextBox dans l'échantillon ci-dessus.)

Répondre

0

Pour autant que je suis au courant de la liaison Silverlight n'a pas les propriétés XPath trouvées dans WPF donc il n'y a aucun moyen agréable de se lier directement à XML. Lorsque j'ai rencontré ce problème, j'ai utilisé xsd.exe avec un schéma pour générer mes classes, puis j'utilise Xml Serialization pour les remplir. Ce n'est pas idéal mais au moins je ne suis pas en train d'écrire et de maintenir les classes et les mappings moi-même.

+0

Merci pour la réponse. XSD étaient les plus proches que j'ai aussi. J'espérais quelque chose de plus flexible. – AnthonyWJones

3

Vous pouvez le faire avec un IValueConverter. Voici un simple:

public class XAttributeConverter : IValueConverter 
{ 
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
    { 
     var xml = value as XElement; 
     var name = parameter as string; 
     return xml.Attribute(name).Value; 
    } 
} 

Ensuite, dans votre XAML vous pouvez référencer le convertisseur de type et de transmettre le nom d'attribut comme paramètre:

<ListBox x:Name="ItemList"> 
    <ListBox.Resources> 
     <local:XAttributeConverter x:Name="xcvt" /> 
    </ListBox.Resources> 
    <ListBox.ItemTemplate> 
     <DataTemplate> 
      <StackPanel Orientation="Horizontal"> 
       <TextBlock Text="{Binding Converter={StaticResource xcvt}, ConverterParameter=forename}" /> 
       <TextBlock Text="{Binding Converter={StaticResource xcvt}, ConverterParameter=surname}" /> 
      </StackPanel> 
     </DataTemplate> 
    </ListBox.ItemTemplate> 
</ListBox> 

C'est lorsque vous liez au XML chargé dans un XElement:

XElement xml = XElement.Parse("<root><item forename='Fred' surname='Flintstone' /><item forename='Barney' surname='Rubble' /></root>"); 

ItemList.ItemsSource = xml.Descendants("item"); 

Pas une syntaxe de liaison super élégant, mais il fonctionne et est plus facile que la cartographie des classes.

+1

C'est le plus proche que j'ai.J'apprécie les efforts que vous avez déployés et je m'excuse pour mes pauvres questions. Le problème que j'ai eu est de faire cette approche dans les deux sens. (Mon Q d'origine contenait TextBlock je voulais dire TextBox). J'ai besoin que cela soit modifiable. – AnthonyWJones

0

Pourriez-vous faire quelque chose de similaire à ce que Bryant suggère avec une requête qui utilise une classe anonyme?

i.e. .:

var data = from c in xml.Descendants("item") 
         select new { Forename = c.Attribute("forename").Value, 
            Surname = c.Attribute("surname").Value }; 
ItemList.ItemsSource = data 

Je pense que cela devrait fonctionner, mais je ne suis pas un endroit où je pourrais le tester. Si ce n'est pas le cas, quelqu'un me fait savoir pourquoi parce que je suis intéressé.

+0

Ok, il me semble qu'il doit y avoir quelque chose de fondamentalement faux avec ceci ou cela aurait été la réponse évidente. Alors, quelle partie de cela ne fonctionne pas? – MojoFilter

+0

Le résultat de la requête linq n'est pas une liste d'objets mais un {System.Linq.Enumerable.WhereSelectEnumerableIterator f__AnonymousType0 >} que je ne pense pas être liable. Essayer quelques réglages pour voir si je peux le faire fonctionner. – Bryant

+0

J'ai également essayé de le convertir en liste en utilisant ToList(), mais de toute façon j'obtiens l'exception: ((System.MethodAccessException) e.ExceptionObject) .Message avec un message de <> f__AnonymousType0'2.get_Forename(). – Bryant