J'ai compris comment faire cela sans marcher sur TreeView.DataContext
. La liaison est facile. Codebehind est presque aussi facile, mais avec un peu de chance.
Vous n'obtenez rien si vous liez ou affectez XmlDataProvider
à ItemsSource
. Ce n'est pas un IEnumerable
(bien que ce soit INotifyPropertyChanged
) et il n'y a pas de conversion implicite. Ce que vous voulez est XmlDataProvider.Data
, qui est déclaré comme Object
, mais je vois un type d'exécution de XmlDataCollection
(qui hérite de ReadOnlyObservableCollection<XmlNode>
).
MVVM
Reliure Data
est facile. Je ne sais pas si c'est MVVM pur de mettre XmlDataProvider
dans votre viewmodel, peut-être pas.
viewmodel:
public XmlDataProvider ViewModelXMLDataProp { ... }
XAML
<TreeView
ItemsSource="{Binding ViewModelXMLDataProp.Data}"
...
/>
Fait - qui est, à moins que vous devez utiliser la propriété XPath
du Binding
. Si vous le faites, vous devez utiliser le DataContext
kludge. Vous ne pouvez pas définir à la fois Path
et XPath
sur la même liaison. La propriété XPath de XmlDataProvider
fait la même chose. Si vous pouvez travailler avec ça, vous êtes bon.
Vous penseriez que fonctionnerait, car cela fonctionne lorsque votre XmlDataProvider
est une ressource statique. Lorsque Binding.Source
est un DataSourceProvider
et Path
est non spécifiée, Path
par défaut Data
:
<TreeView
ItemsSource="{Binding Source={StaticResource MyXmlDataProviderResource}}"
...
/>
... mais cela fonctionne parce que vous donnez une ressource statique. Ce qui suit se lie réellement à la chaîne "ViewModelXMLDataProp"
plutôt que de rechercher le DataContext
pour une propriété de ce nom. Ce n'est pas bon.
<TreeView
ItemsSource="{Binding Source=ViewModelXMLDataProp}"
...
/>
Peut-être que vous pourriez écrire un MarkupExtension
qui ferait ce travail, mais il n'y a pas besoin.
Codebehind
Vous devriez apprendre et à utiliser MVVM, mais les choses se passent pour beaucoup de raisons et vous ne suis pas venu ici pour un sermon.
Codebehind est un peu plus compliqué. TreeView.ItemsSource
ne nécessite rien de plus que l'objet que vous lui donnez doit implémenter System.Collections.IEnumerable
, alors lancez provider.Data
à System.Collections.IEnumerable
et ne vous inquiétez pas de savoir quel est le type d'exécution exact.
Maintenant, voici le gotcha: XmlDataProvider.Data
est rempli de manière asynchrone.
protected void LoadXML(String path)
{
var provider =
new XmlDataProvider()
{
Source = new Uri(path, UriKind.Absolute),
XPath = "./*"
};
// FAIL: provider.Data is still null
treeView.ItemsSource = (IEnumerable)provider.Data;
}
Je trouve cela un problème, même lorsque je crée un XmlDocument
, appelez XmlDocument.Load()
, et affecter le document à XmlDataProvider.Document
. Un Binding
restera toujours en attente lorsque la propriété Data
sera définie, et il mettra à jour ItemsSource
ensuite. Mais une affectation à ItemsSource
dans votre code derrière le fichier ne fait pas une telle chose.
Contrairement à la croyance populaire omniprésente à Stack Overflow, dans le code suivant il n'y a pas de liaison qui se passe, et en aucun sens n'a rien été lié:
// NOT A BINDING
treeView.ItemsSource = someRandomCollectionOfStuff;
Si personne ne la création d'une instance de System.Windows.Data.Binding
ou x:Bind
, il est pas une liaison. Cette distinction est importante: "Utiliser la valeur actuelle de x
" n'est pas le même concept que "mettre à jour indéfiniment avec les valeurs futures de y.x
chaque fois y
soulève PropertyChanged
".
Vous pouvez créer par programme un Binding
ou même gérer PropertyChanged
, mais ils sont allés de l'avant et vous ont donné une option beaucoup plus simple. Il suffit de gérer l'événement XmlDataProvider.DataChanged
.
protected void LoadXML(String path)
{
var provider =
new XmlDataProvider()
{
Source = new Uri(path, UriKind.Absolute),
XPath = "./*"
};
provider.DataChanged += (s,e)
=> treeView.ItemsSource = (IEnumerable)provider.Data;
}
Et c'est tout. Vous pouvez même conserver ce fournisseur, charger du nouveau code XML et avoir l'événement DataChanged
pour garder l'arborescence à jour. On dirait que c'est un gaspillage d'effort.
Je m'intéresse également à ce sujet. Y a-t-il quelque chose qui manque dans votre réponse? Je ne peux pas obtenir de données à afficher ... Merci. – Number8
Je vous suggère de créer une nouvelle question et de poster votre code afin que nous puissions voir quel est le problème. – Crippeoblade