Click here to Skip to main content
15,441,434 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
I have an application which manages audio recordings. In theory, new recording of "My Series" go in a folder "\\Library\My Series" but there are two complications. Firstly, new recordings may come to me with alternate names; for example "Macbeth" might become "William Shakespeare's Macbeth". Secondly, names can contain characters not allowed in folder names - for example "Who Framed Roger Rabbit?". So I have a simple data structure which contains, for each series, the display name for use in the UI, the foldername for use in storage and a list (possibly empty) of aliases, and I have LINQ to retrieve one given another. Here's an example to show the structure of the data file:

<?xml version="1.0" encoding="utf-8"?>
<recordings>
  <series>
    <seriestitle>Series 1</seriestitle>
    <seriesfolder>Series 1</seriesfolder>
    <alias>Series One</alias>
    <alias>Series 1.0</alias>
  </series>
  <series>
    <seriestitle>Series 2:The Return</seriestitle>
    <seriesfolder>Series 2_The Return</seriesfolder>
    <alias>Series Two</alias>
  </series>
  <series>Example with title as text of Series node -> This is series three
    <seriestitle>Series 3 - Why?</seriestitle>
    <seriesfolder>Series 3 - Why_</seriesfolder>
    <alias>Series three alias 1</alias>
    <alias>Series 3.0</alias>
    <alias>Series 3.0 (Premier)</alias>
  </series>
</recordings>


I'd like to add a view of all this data in my UI so I've been playing with a WPF TreeView. I've used a HierarchicalDataTemplate but I've run into a problem. I display [NodeName][NodeValue] which works - but gives the entire node content for <series> as it's supposed to. I can suppress the <series> field, which works, but if I collapse the tree to get more one screen, instead of a list of series titles, I get the fieldname over and over - not very useful for navigation. Here's the XAML and codebehind for my main window.

<Window x:Class="XmlDataTree.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:sys="clr-namespace:System;assembly=mscorlib"
        xmlns:local="clr-namespace:XmlDataTree"
        Title="XmlData Tree Test"
        Loaded="Window_Loaded">

    <Window.Resources>
        <!-- Expand all nodes on load for demo -->
        <Style TargetType="{x:Type TreeViewItem}">
            <Setter Property="IsExpanded" Value="{Binding ElementName=chkExpand, Path=IsChecked, TargetNullValue=false}"/>
        </Style>

        <HierarchicalDataTemplate x:Key="NodeTemplate">
            <StackPanel Orientation="Horizontal" Focusable="False">
                <TextBlock x:Name="tbName" Text="{Binding Name}" />
                <TextBlock Text=": " />
                <TextBox x:Name="tbValue" Text="{Binding Value}" />
            </StackPanel>
            <!-- Hide series data -->
            <HierarchicalDataTemplate.Triggers>
                <MultiDataTrigger>
                    <MultiDataTrigger.Conditions>
                        <Condition Binding="{Binding Path=Name.LocalName}" Value="series"/>
                        <Condition Binding="{Binding ElementName=chkHide, Path=IsChecked, TargetNullValue=false}" Value="True"/>
                    </MultiDataTrigger.Conditions>
                    <Setter TargetName="tbValue" Property="Visibility" Value="Collapsed"/>
                </MultiDataTrigger>
            </HierarchicalDataTemplate.Triggers>
            <HierarchicalDataTemplate.ItemsSource>
                <Binding Path="Elements" />
            </HierarchicalDataTemplate.ItemsSource>
        </HierarchicalDataTemplate>
    </Window.Resources>

    <Grid Margin="4">
        <StackPanel Orientation="Vertical">
            <StackPanel Orientation="Horizontal">
                <TextBlock Text="Expand Tree" />
                <CheckBox Name="chkExpand" IsChecked="True" />
                <TextBlock Text="Hide Series" Margin="10,0"/>
                <CheckBox Name="chkHide" IsChecked="False" />
            </StackPanel>
            <TreeView 
            Name="trview"
            ItemsSource="{Binding Path=Root.Elements}"
            ItemTemplate="{StaticResource NodeTemplate}"
            HorizontalAlignment="Stretch"
            VerticalAlignment="Stretch"
            />
        </StackPanel>
    </Grid>
</Window>



C#
using System.Windows;
using System.Xml.Linq;

namespace XmlDataTree
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            XDocument xDoc = new XDocument();
            xDoc = XDocument.Load(System.IO.Path.GetFullPath(System.AppDomain.CurrentDomain.BaseDirectory) + "aliases.xml");
            trview.DataContext = xDoc;
        }
    }
}


If you run this, you'll see the "series" field contains a lot of info. If you hide the series field by ticking the checkbox you can see the data clearer. Alternately if you collapse the tree by ticking the other box, you can see many more series and a "series" field isn't too terrible as an index. But if you do both. all you get is a list of the word "series" over and over.

Is there a way for the "<series>" field collapse/expand ability to be preserved but to display the <seriestitle> childnode rather than the <series> node itself? I feel I should be able to manage something by replacing

<Setter TargetName="tbValue" Property="Text" Value="{Value}"/>

with

<Setter TargetName="tbValue" Property="Text" Value="{Binding Path=node::childnode[seriestitle].text()"/>


What I have tried:

I've spent a long time Googling and getting confused between Path and XPath, XDocuments and XmlDocuments and many more. It probably doesn't help than I'm not a pro, this is just a hobby ;-)

All suggestions gratefull received!
Posted
Updated 1-Mar-18 23:14pm

1 solution

I've written a Converter which accepts the current node and returns the text of the seriestitle child node. I haven't written the Convertback yet though!

public class seriesTitleConverter : IValueConverter
    {
        public Object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            if (value == null) return string.Empty;
            try
            {
                XElement xe = value as XElement;
                XElement ce = xe.Element("seriestitle");
                return (ce.Value);
            }
            catch (Exception ex)
            {
                return "No title node found";
            }
        }
        public Object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900