This is a migrated thread and some comments may be shown as answers.

TreeListViewRow.ParentRow throws NullReferenceException in Telerik.Windows.Controls.GridView when child collection is null

2 Answers 144 Views
TreeListView
This is a migrated thread and some comments may be shown as answers.
Cale
Top achievements
Rank 1
Cale asked on 01 Mar 2012, 02:40 AM
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:
<Window x:Class="TestTreeListView.MainWindow"
        xmlns:local="clr-namespace:TestTreeListView"
        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;
   }
}

2 Answers, 1 is accepted

Sort by
0
Accepted
Yordanka
Telerik team
answered on 01 Mar 2012, 04:05 PM
Hello Cale,

Thank you for the feedback.

We were able to reproduce the exception and it was resolved immediately. The fix will be part of the next internal build (on Monday).
 
Kind regards,
Yordanka
the Telerik team
Sharpen your .NET Ninja skills! Attend Q1 webinar week and get a chance to win a license! Book your seat now >>
0
Cale
Top achievements
Rank 1
answered on 01 Mar 2012, 05:24 PM
That was fast! Thanks!
Tags
TreeListView
Asked by
Cale
Top achievements
Rank 1
Answers by
Yordanka
Telerik team
Cale
Top achievements
Rank 1
Share this question
or