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 RowLoadedEventArgs
using Telerik.Windows.Controls.TreeListView; // for TreeListViewRow
namespace 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;
}
}