Wednesday, February 2, 2011

IronPython & WPF: Data binding with TreeView's selected element

In this post I'm going to show a small example of using data binding with the selected element of a WPF TreeView with an IronPython class.

A couple of days ago I had the necessity of using data binding to keep track of the selected value of a WPF TreeView . At first it seemed to be an easy task so I wrote:

<TreeView SelectedValue="{Binding selected, Mode=TwoWay}" ... />

Running this code results on the following error:

SystemError: 'Provide value on 'System.Windows.Data.Binding' threw an exception.' Line number '12' and line position '7'.

The problem is that the SelectedValue (and SelectedItem) property is read-only.

There are several ways to deal with this problem. One alternative is to use a technique similar to the one described in the "Forwarding the Result of WPF Validation in MVVM" post. We're going to define an attached property which works as an "output only" property that could be used with data binding.

Attached property definition

I couldn't find a way to wrote the definition of the attached property in IronPython because it needed to be instanciated by XamlReader. So the definition was written using C#:

using System.Windows.Markup;
using System.Windows;
using System.Windows.Controls;
using System.IO;
using System.Collections.ObjectModel;

namespace Langexplr
public static class TreeViewSelectedBehavior
public static readonly DependencyProperty MySelectedProperty =
public static object GetMySelected(TreeView t)
return t.GetValue(MySelectedProperty);

public static void SetMySelected(TreeView t, object theValue)
t.SetValue(MySelectedProperty, theValue);

public static readonly DependencyProperty SelectedHelperProperty =
new UIPropertyMetadata(null,OnSelectedHelperChanged)

public static TreeViewSelectedHelper GetSelectedHelper(TreeView t)
return (TreeViewSelectedHelper)t.GetValue(SelectedHelperProperty);

public static void SetSelectedHelper(TreeView t,
TreeViewSelectedHelper theValue)
t.SetValue(SelectedHelperProperty, theValue);
static void OnSelectedHelperChanged(
DependencyObject depObj,
DependencyPropertyChangedEventArgs e)


This class define two properties:
  • MySelected: the output property that is used to set the selected element in the view model
  • SelectedHelper: which is used to as an object that modifies the value of MySelected when the selected item changes(see below).

The following helper class is used to subscribe the SelectedItemChanged event and change "MySelected" .

public class TreeViewSelectedHelper 
public TreeViewSelectedHelper() { }
void SelectedItemChanged(object sender,
RoutedPropertyChangedEventArgs<object> args)
(sender as TreeView).SetValue(
((sender as TreeView)).SelectedItem);
public void Register(TreeView t)
t.SelectedItemChanged += SelectedItemChanged;


We can now compile this class:

set NETFX4=c:\WINDOWS\Microsoft.NET\Framework\v4.0.30319\
csc /debug /r:%NETFX4%System.Xaml.dll /r:%WPFPATH%\WindowsBase.dll /r:%WPFPATH%\PresentationCore.dll /r:%WPFPATH%\PresentationFramework.dll /target:library utils.cs

The example

Having defined this attached property and helper class we can now write the following example.

<Window xmlns=""
Title="TreeView selection test" Width="300" Height="300">
<utils:TreeViewSelectedHelper x:Key="selHelper" />


<TextBlock Text="{Binding selected.label}"/>
<TreeView ItemsSource="{Binding roots}"
utils:TreeViewSelectedBehavior.SelectedHelper="{StaticResource selHelper}">
<Binding Path="selected" Mode="OneWayToSource"/>

<HierarchicalDataTemplate ItemsSource="{Binding children}">
<TextBlock Text="{Binding label}"/>

With this XAML definition we can write the following IronPython code:

import clr

from System.Windows.Markup import XamlReader
from System.Windows import Application
from System.IO import File
from System.Windows.Controls import TreeView
import System
import clrtype
from GalaSoft.MvvmLight import ViewModelBase
from System.Collections.ObjectModel import ObservableCollection

class TestModel(ViewModelBase):
__metaclass__ = clrtype.ClrClass
def __init__(self): = 'algo'
self.root = NodeModel('x1',[NodeModel('y2',[NodeModel('z2',[])]),

self.sselected = NodeModel('',[])

def selected(self):
result = self.sselected
return result

def selected(self, value):
self.sselected = value

def roots(self):
return [self.root]

def label(self):

def label(self, value): = value

class NodeModel:
__metaclass__ = clrtype.ClrClass

def __init__(self,label, initchildren):
self.children_collection = ObservableCollection[System.Object](initchildren) = label

def label(self):

def children(self):
return self.children_collection

xamlFile = File.OpenRead('test.xaml')
window = XamlReader.Load(xamlFile)
window.DataContext = TestModel()


By running this example we can see how the label of the selected element of the TreeView is reflected in the TextBlock defined above.