Como ligar atributo XML a TreeView nós, enquanto ligação de dados XDocument para WPF Treeview
-
04-07-2019 - |
Pergunta
Eu tenho um XML que precisa ser databound a um WPF TreeView . Aqui, o XML pode ter estrutura diferente. O TreeView deve ser suficiente genérico databound para carregar qualquer permutação de hierarquia. No entanto, um XAttribute nos nós (chamado Título ) deve ser databound ao texto cabeçalho do TreeViewItem e não o nome do nó .
XML em ficar vinculado:
<Wizard>
<Section Title="Home">
<Loop Title="Income Loop">
<Page Title="Employer Income"/>
<Page Title="Parttime Job Income"/>
<Page Title="Self employment Income"/>
</Loop>
</Section>
<Section Title="Deductions">
<Loop Title="Deductions Loop">
<Page Title="Travel spending"/>
<Page Title="Charity spending"/>
<Page Title="Dependents"/>
</Loop>
</Section>
</Wizard>
XAML:
<Window x:Class="Wpf.DataBinding.TreeViewer"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Wpf.DataBinding"
Title="TreeViewer" Height="300" Width="300">
<Window.Resources>
<HierarchicalDataTemplate ItemsSource="{Binding Path=Elements}" x:Key="TVTemplate">
<TreeViewItem Header="{Binding Path=Name}"/>
</HierarchicalDataTemplate>
</Window.Resources>
<StackPanel>
<TreeView x:Name="_treeView" Style="{StaticResource TVallExpanded}"
ItemsSource="{Binding Path=Root.Elements}"
ItemTemplate="{StaticResource TVTemplate}" />
</StackPanel>
</Window>
codebehind do XAML que carrega XML para XDocument e liga-o TreeView
public partial class TreeViewer : Window
{
public TreeViewer()
{
InitializeComponent();
XDocument doc = XDocument.Parse(File.ReadAllText(@"C:\MyWizard.xml"));
_treeView.DataContext = doc;
}
}
Assim, na marcação XAML que são vinculativas nome para o cabeceamento de TreeViewItem.
<TreeViewItem Header="{Binding Path=Name}"/>
No entanto, quero vinculá-lo a Título atributo da Seção, Loop e página no XML acima. Eu li que não é possível usar XPath enquanto a ligação XDocument. Mas tem que haver uma maneira de vincular o Título atributo para texto de cabeçalho do TreeViewItem. Eu tentei usar @Title,. [@ Título] etc. Mas nada parecia funcionar.
Esta discussão em MSDN Fóruns tem uma discussão semelhante.
Os ponteiros seria muito útil.
Solução
Hurra !!! Eu descobri como ligar XAttribute. Não é intuitiva e não é facilmente imaginável. Mas aqui é como isso pode ser feito.
<TreeViewItem Header="{Binding Path=Attribute[Title].Value}"/>
É difícil imaginar que o título pode ser directamente utilizado em colchetes.
Outras dicas
Eu acho que tudo o que você precisa fazer é criar um HierarchicalDataTemplate para cada tipo de nó no XML, carregar o xml-lo em um XmlDataProvider , e depois ligam que para o TreeView. A TV funciona com o XDP aos dados de vinculação, e em algum lugar ao longo da linha que descobrir o que HDTs ter definido e combinar seu tipo de dados para os nomes dos nós no XML. Você pode ter alguns problemas com seus XPATHs mudando com os diferentes tipos de dados, mas mantendo os flexível é outra questão.
Por exemplo, eu tenho um aplicativo de teste regex pouco. Ele inclui um sistema de ajuda que é essencialmente todas as diferentes partes regex listadas em uma árvore: Categorias e peças com descrições, dicas de ferramentas, e outras coisas. Os dados sobre as partes é armazenado como uma fonte de dados XML. Desde a sua estática, Acabei de criar um recurso estático com recursos do aplicativo:
<XmlDataProvider
x:Key="rxPartData"
XPath="RegexParts">
<x:XData>
<RegexParts
xmlns="">
<Category
Name="Character class"
ToolTip="Sets of characters used in matching">
<RegexPart
Regex="[%]"
Hint="Positive character group"
ToolTip="Matches any character in the specified group (replace % with one or more characters)" />
<!-- yadda -->
</Category>
</RegexParts>
</x:XData>
</XmlDataProvider>
Em seguida, eu criei HierarchicalDataTemplates para cada tipo de nó nos dados (novamente, tudo isso é em recursos do aplicativo):
<!-- Category data template -->
<HierarchicalDataTemplate
DataType="Category"
ItemsSource="{Binding XPath=*}">
<TextBlock
Focusable="False"
Text="{Binding XPath=@Name}"
ToolTip="{StaticResource CategoryTooltip}"
ToolTipService.InitialShowDelay="0"
ToolTipService.ShowDuration="{x:Static sys:Int32.MaxValue}"
ToolTipService.HasDropShadow="True" />
</HierarchicalDataTemplate>
<!-- RegexPart data template -->
<HierarchicalDataTemplate
DataType="RegexPart"
ItemsSource="{Binding XPath=*}">
<WrapPanel
Focusable="False"
ToolTip="{StaticResource RegexPartTooltip}"
ToolTipService.InitialShowDelay="0"
ToolTipService.ShowDuration="{x:Static sys:Int32.MaxValue}"
ToolTipService.HasDropShadow="True">
<TextBlock
Text="{Binding XPath=@Regex}" />
<TextBlock
Text=" - " />
<TextBlock
Text="{Binding XPath=@Hint}" />
</WrapPanel>
</HierarchicalDataTemplate>
Por fim, eu só ligada a árvore para o XmlDataProvider:
<TreeView
Name="_regexParts"
DockPanel.Dock="Top"
SelectedItemChanged="RegexParts_SelectedItemChanged"
ItemsSource="{Binding Source={StaticResource rxPartData}, XPath=/RegexParts/Category}"
ToolTip="Click the + to expand a category; click a part to insert it">
</TreeView>
E isso é tudo que você precisa fazer. O TreeView eo XmlDataProvider vai cuidar de encontrar e utilizar a correta do HDT para os nós corretos na dados. A parte mais difícil de tudo isso é descobrir seus XPaths para a ligação. Ele pode ficar um pouco complicado, como se os seus caminhos estiverem incorretos, você vai acabar recebendo nada na árvore e não haverá quaisquer erros (existem maneiras para melhorar a comunicação erro na ligação de dados no WPF, mas isso é outra questão) .