0

I have followed the advice of this article in binding a treeview control to an xml document: http://www.codeproject.com/Articles/317766/Displaying-XML-in-a-WPF-TreeView?msg=4546407#xx4546407xx

However, now I can't figure out how to gain access to the selected item.

Here is my XAML:

<Window.Resources>
    <XmlDataProvider x:Key="xmldata" Source="cats.xml" XPath="/CategoryArray" />
    <HierarchicalDataTemplate DataType="Category" ItemsSource="{Binding XPath=./*}">
        <StackPanel Orientation="Horizontal">
            <TextBlock Margin="5,0,0,0" Text="{Binding XPath=@Name}" Tag="{Binding XPath=@ID}" />
        </StackPanel>
    </HierarchicalDataTemplate>
    <HierarchicalDataTemplate DataType="CategoryArray" ItemsSource="{Binding XPath=./*}">
        <TextBlock Margin="0" Text="eBay Categories" />
    </HierarchicalDataTemplate>
</Window.Resources>
<Grid DataContext="{StaticResource xmldata}">
    <TreeView Name="treeView1" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" ItemsSource="{Binding}" VirtualizingStackPanel.IsVirtualizing="False" VirtualizingStackPanel.VirtualizationMode="Standard" SelectedItemChanged="treeView1_SelectedItemChanged" />
</Grid>

This doesn't seem to work the way I thought it would:

    private void treeView1_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
    {
        try
        {
            TreeViewItem selectedItem = treeView1.SelectedValue as TreeViewItem;
            categoryName = selectedItem.Name;
            categoryID = selectedItem.Tag.ToString();
            categoryChosen = true;
        }
        catch { }
    }

Since I'm using this hierarchical data template and a textblock, I'm not sure what to do. Any ideas? Thanks in advance.

Doug
  • 5,116
  • 10
  • 33
  • 42
  • I asked this same question here: http://stackoverflow.com/a/9143193/279516. I ended up not using the answer because it's complicated. I cheated and used the code-behind file. Hope this helps. – Bob Horn Apr 21 '13 at 21:22
  • How did you use the code-behind file? Do you mean you programmatically populated the treeview instead of using binding? – Doug Apr 21 '13 at 21:29
  • "This doesn't seem to work the way I thought it would." Could you be more specific? How is it behaving? – Brandon Dybala Apr 21 '13 at 21:36
  • This is my comment from that question/link: I just looked at the code again, and it appears that I cheated. I have this in the treeview control: SelectedItemChanged="TreeView_SelectedItemChanged". In the xaml.cs, I set the selected item: ((ApplicationServerViewModel)DataContext).SelectedApplicationServer = e.NewValue as ApplicationServer; – Bob Horn Apr 21 '13 at 21:49

2 Answers2

0

You should probably get rid of the dirty try catch em all. You can use the e.NewValue and check if its one of your specified types. Since you are directly telling WPF whats your data model you can use it like this:

private void treeView1_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
{
    var category =  e.NewValue as Category;
    if(category != null)
    {
        //FIXME: do things if its Category
    }
    else
    {
        var categoryArray = e.NewValue as CategoryArray;
        if(categoryArray != null)
        {
            //FIXME: do things if its CategoryArray
        }
    }  
}
iamsed
  • 43
  • 1
  • 8
0

While using XAML you can use binding to retrieve the property of the framework elements. However in this particular case the SelectedItem property of TreeView is read only so you may not bind it directly, but you can make use of attached properties to achieve the same.

I tried to make a sample for your case

declare an attached property in the VM class with change notification to execute your logic

public static object GetSelectedTreeItem(DependencyObject obj)
{
    return (object)obj.GetValue(SelectedTreeItemProperty);
}

public static void SetSelectedTreeItem(DependencyObject obj, object value)
{
    obj.SetValue(SelectedTreeItemProperty, value);
}

// Using a DependencyProperty as the backing store for SelectedTreeItem.  This enables     animation, styling, binding, etc...
public static readonly DependencyProperty SelectedTreeItemProperty =
    DependencyProperty.RegisterAttached("SelectedTreeItem", typeof(object), typeof(YourVMClass), new PropertyMetadata(null, OnSelectedItemChange));

public static void OnSelectedItemChange(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
    //do your stuff here eg.
    YourVMClass vm = d as YourVMClass;
    dynamic selectedItem = e.NewValue;
    vm.categoryName = selectedItem.Name;
    vm.categoryID = selectedItem.Tag.ToString();
    vm.categoryChosen = true;
}

your XAML binding goes as follows

<TreeView vm:YourVMClass.SelectedTreeItem="{Binding SelectedItem,Mode=OneWay,RelativeSource={RelativeSource Self}}">

So this will set the value of the Selected Item of TreeView to SelectedTreeItem property of VM class and will trigger the change event for you to perform further actions.

Also I can see that currently you are using XML data as your data context, so probably you may need adjust the above code according to your usage, concept remains same. You may perhaps declare the attached property in the code behind file for the respective XAML if you do not intent to change your data context. But I would recommend you to do some re-factoring to implement a VM class for your XAML and expose the XML data as a property in your new VM.

pushpraj
  • 13,458
  • 3
  • 33
  • 50