This code used to work with an older Telerik release (can verify the version if need be), but no longer works with the latest (RadControls_for_WPF_2012_1_0215_Dev).
Steps to reproduce:
1. Right-click and select the context menu item to add a top-level row.
2. Right-click the row and select the context menu item to add a child row.
3. Right-click the child row, and you get the exception.
TreeListViewRow.ParentRow throws an exception because it tries to do "var parentView = this.Items.ParentView;" but Items is null.
Each top-level (parent) row contains a ParentItem object with a ChildItems property, and the ChildTableDefinition is bound to the ChildItems property. Each child row contains a ChildItem object, which doesn't have a ChildItems property, so when it tries to get the child items for a child row, the collection is null. As a workaround, if I give the ChildItem class a ChildItems property and have it return an empty collection, then the exception goes away. I'm no telerik expert, but it seems strange to me that a row needs to have a non-null collection of child items in order to access the row's parent row.
Apparently you don't let users upload test projects, so here's the source:
MainWindow.xaml:
MainWindow.xaml.cs:
Steps to reproduce:
1. Right-click and select the context menu item to add a top-level row.
2. Right-click the row and select the context menu item to add a child row.
3. Right-click the child row, and you get the exception.
TreeListViewRow.ParentRow throws an exception because it tries to do "var parentView = this.Items.ParentView;" but Items is null.
Each top-level (parent) row contains a ParentItem object with a ChildItems property, and the ChildTableDefinition is bound to the ChildItems property. Each child row contains a ChildItem object, which doesn't have a ChildItems property, so when it tries to get the child items for a child row, the collection is null. As a workaround, if I give the ChildItem class a ChildItems property and have it return an empty collection, then the exception goes away. I'm no telerik expert, but it seems strange to me that a row needs to have a non-null collection of child items in order to access the row's parent row.
Apparently you don't let users upload test projects, so here's the source:
MainWindow.xaml:
<Window x:Class="TestTreeListView.MainWindow" xmlns:local="clr-namespace:TestTreeListView" xmlns:telerik="http://schemas.telerik.com/2008/xaml/presentation" xmlns:scm="clr-namespace:System.ComponentModel;assembly=WindowsBase" Name="mainWindow" Title="MainWindow" Height="350" Width="525"> <Window.CommandBindings> <CommandBinding Command="local:MainWindow.AddParentRow" Executed="AddParentRow_Executed" /> </Window.CommandBindings> <Window.Resources> <!-- The style of the expand button in the totally rad tree. --> <Style x:Key="ExpandButtonStyle" TargetType="{x:Type telerik:GridViewToggleButton}"> <Setter Property="PresentationMode" Value="PlusMinus"/> </Style> <!-- Context menu for adding a child row to a parent row. --> <ContextMenu x:Key="ParentRowContextMenu"> <ContextMenu.CommandBindings> <CommandBinding Command="local:MainWindow.AddChildRow" Executed="AddChildRow_Executed" /> </ContextMenu.CommandBindings> <MenuItem Command="local:MainWindow.AddChildRow" /> </ContextMenu> <!-- A sorted view of the totally rad tree items. --> <CollectionViewSource x:Key="TotallyRadItemsView" Source="{Binding ElementName=mainWindow, Path=ParentItems}"> <CollectionViewSource.SortDescriptions> <scm:SortDescription PropertyName="Name" /> </CollectionViewSource.SortDescriptions> </CollectionViewSource> </Window.Resources> <Grid> <telerik:RadTreeListView Name="totallyRadTreeListView" AutoGenerateColumns="True" GridLinesVisibility="None" RowIndicatorVisibility="Collapsed" IsFilteringAllowed="False" CanUserSortColumns="False" HierarchyExpandButtonStyle="{StaticResource ExpandButtonStyle}" ScrollViewer.HorizontalScrollBarVisibility="Disabled" ItemsSource="{Binding Source={StaticResource TotallyRadItemsView}}"> <telerik:RadTreeListView.ChildTableDefinitions> <telerik:TreeListViewTableDefinition ItemsSource="{Binding ChildItems}" /> </telerik:RadTreeListView.ChildTableDefinitions> <telerik:RadTreeListView.ContextMenu> <!-- Context menu for adding a parent row. --> <ContextMenu> <MenuItem Command="local:MainWindow.AddParentRow" CommandTarget="{Binding Path=PlacementTarget, RelativeSource={RelativeSource AncestorType={x:Type ContextMenu}}}" /> </ContextMenu> </telerik:RadTreeListView.ContextMenu> </telerik:RadTreeListView> </Grid></Window>MainWindow.xaml.cs:
using System;using System.Collections.Generic;using System.Collections.ObjectModel;using System.Linq;using System.Text;using System.Windows;using System.Windows.Controls;using System.Windows.Data;using System.Windows.Documents;using System.Windows.Input;using System.Windows.Media;using System.Windows.Media.Imaging;using System.Windows.Navigation;using System.Windows.Shapes;using Telerik.Windows.Controls.GridView; // for RowLoadedEventArgsusing Telerik.Windows.Controls.TreeListView; // for TreeListViewRownamespace TestTreeListView{ /// <summary> /// Interaction logic for MainWindow.xaml /// </summary> public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); // RadTreeListView doesn't select its items on right-click, so add // an event handler that accomplishes this. mTreeItemClickHandler = new MouseButtonEventHandler( TotallyRadTreeListViewRow_MouseRightButtonDown ); totallyRadTreeListView.RowLoaded += new EventHandler<RowLoadedEventArgs>( TotallyRadTreeListView_RowLoaded ); totallyRadTreeListView.RowUnloaded += new EventHandler<RowUnloadedEventArgs>( TotallyRadTreeListView_RowUnloaded ); } static MainWindow() { AddParentRow = new RoutedUICommand( "Add Parent Row", "AddParentRow", typeof( MainWindow ) ); AddChildRow = new RoutedUICommand( "Add Child Row", "AddChildRow", typeof( MainWindow ) ); } public static RoutedUICommand AddParentRow { get; set; } public static RoutedUICommand AddChildRow { get; set; } public ObservableCollection<ParentItem> ParentItems { get { return mParentItems; } } private void TotallyRadTreeListViewRow_MouseRightButtonDown( object sender, MouseButtonEventArgs e ) { TreeListViewRow row = sender as TreeListViewRow; row.IsSelected = true; // Throws an exception when right-clicking a child row. if ( row.ParentRow != null ) { // use row.ParentRow.Item here } // Show the context menu whenever a parent row is clicked. if ( row.Item is ParentItem ) { ContextMenu menu = FindResource( "ParentRowContextMenu" ) as ContextMenu; menu.IsOpen = true; } } private void TotallyRadTreeListView_RowLoaded( object sender, RowLoadedEventArgs e ) { if ( e.Row.Item != null ) { e.Row.MouseRightButtonDown += mTreeItemClickHandler; } } private void TotallyRadTreeListView_RowUnloaded( object sender, RowUnloadedEventArgs e ) { e.Row.MouseRightButtonDown -= mTreeItemClickHandler; } private void AddParentRow_Executed( object target, ExecutedRoutedEventArgs e ) { mParentItems.Add( new ParentItem() ); } private void AddChildRow_Executed( object target, ExecutedRoutedEventArgs e ) { ParentItem parentItem = totallyRadTreeListView.SelectedItem as ParentItem; parentItem.ChildItems.Add( new ChildItem() ); } private MouseButtonEventHandler mTreeItemClickHandler = null; ObservableCollection<ParentItem> mParentItems = new ObservableCollection<ParentItem>(); } public class ParentItem { public string Name { get { return name; } } public ObservableCollection<ChildItem> ChildItems { get { return mChildItems; } } private string name = "Parent" + i++; ObservableCollection<ChildItem> mChildItems = new ObservableCollection<ChildItem>(); private static int i = 0; } public class ChildItem { public string Name { get { return name; } } //public ObservableCollection<ChildItem> ChildItems { get { return mChildItems; } } private string name = "Child" + i++; //ObservableCollection<ChildItem> mChildItems = new ObservableCollection<ChildItem>(); private static int i = 0; }}