Ну, было бы проще, если бы иерархия элемента была больше похожа ...
<node type="forest">
<node type="tree">
...
... а не ваша текущая схема.
As-, вы будете нуждаться в 4 HierarchicalDataTemplate
с, по одному для каждого иерархического элемента, включая корень, и один DataTemplate
для leaf
элементов:
<Window.Resources>
<HierarchicalDataTemplate
DataType="forestPad"
ItemsSource="{Binding XPath=forest}">
<TextBlock
Text="a forestpad" />
</HierarchicalDataTemplate>
<HierarchicalDataTemplate
DataType="forest"
ItemsSource="{Binding XPath=tree}">
<TextBox
Text="{Binding XPath=data}" />
</HierarchicalDataTemplate>
<HierarchicalDataTemplate
DataType="tree"
ItemsSource="{Binding XPath=branch}">
<TextBox
Text="{Binding XPath=data}" />
</HierarchicalDataTemplate>
<HierarchicalDataTemplate
DataType="branch"
ItemsSource="{Binding XPath=leaf}">
<TextBox
Text="{Binding XPath=data}" />
</HierarchicalDataTemplate>
<DataTemplate
DataType="leaf">
<TextBox
Text="{Binding XPath=data}" />
</DataTemplate>
<XmlDataProvider
x:Key="dataxml"
XPath="forestPad" Source="D:\fp.xml">
</XmlDataProvider>
</Window.Resources>
Вместо этого вы можете установить Source
в XmlDataProvider
программно:
dp = this.FindResource("dataxml") as XmlDataProvider;
dp.Source = new Uri(@"D:\fp.xml");
Кроме того, повторное сохранение ваших изменений так же легко, как это:
dp.Document.Save(dp.Source.LocalPath);
TreeView
сам по себе нуждается в Name
и ItemsSource
присоединены к XmlDataProvider
:
<TreeView
Name="treeview"
ItemsSource="{Binding Source={StaticResource dataxml}, XPath=.}">
Я этот пример, я сделал TwoWay
связывания с TextBox
ES на каждом узле, но когда речь идет о редактировании только одного узла на время в отдельном одиночном TextBox
или другом элементе управления, вы привязываете его к выбранному в данный момент элементу TreeView
. Вы также изменили бы вышеуказанные TextBox
es на TextBlock
s, так как нажатие в TextBox
на самом деле не выбирает соответствующий TreeViewItem
.
<TextBox
DataContext="{Binding ElementName=treeview, Path=SelectedItem}"
Text="{Binding XPath=data, UpdateSourceTrigger=PropertyChanged}"/>
Причина вы должны использовать два Binding
сек, что вы не можете использовать Path
и XPath
вместе.
Edit:
Тимоти Ли Рассел спросил о сохранении CDATA к элементам данных. Сначала немного на InnerXml
и InnerText
.
За кулисами, XmlDataProvider
использует XmlDocument
, с его деревом XmlNodes
. Когда строка, такая как «stuff», назначается свойству InnerXml
XmlNode
, эти теги являются действительно тегами. Никакое экранирование не выполняется при получении или настройке InnerXml
, и оно анализируется как XML.
Однако, если вместо этого назначено свойство InnerText
, угловые скобки будут экранированы с объектами & lt; и & gt ;. Обратное происходит, когда значение возвращается. Объекты (например, & lt;) разрешены обратно в символы (например, <).
Поэтому, если строки мы храним в элементах данных содержат XML, объекты были спаслись, и нам нужно отменить, что просто путем извлечения InnerText
перед добавлением раздела CDATA как ребенок узла ...
XmlDocument doc = dp.Document;
XmlNodeList nodes = doc.SelectNodes("//data");
foreach (XmlNode node in nodes) {
string data = node.InnerText;
node.InnerText = "";
XmlCDataSection cdata = doc.CreateCDataSection(data);
node.AppendChild(cdata);
}
doc.Save(dp.Source.LocalPath);
Если узел уже имеет секцию CDATA, и значение не было каким-либо образом изменено, тогда у него все еще есть раздел CDATA, и мы по существу заменяем его тем же. Однако благодаря нашей привязке, если мы изменим значение содержимого элементов данных, он заменяет CDATA в пользу экранированной строки. Затем мы должны их исправить.
Спасибо, Джоэл, что работает. Один вопрос. Я окружаю контент в элементе данных секцией CDATA, чтобы можно было хранить Xml. Есть ли способ контролировать, как XmlDataProvider выписывает элемент данных? – 2008-10-09 22:09:52