TreeListBox generates phantom items when selecting via code

Grids for WPF Forum

Posted 3 years ago by John Dunn
Version: 19.1.0687
Platform: .NET 4.8
Environment: Windows 10 (64-bit)
Avatar

If I select a TreeListBox item via its IsSelected property before I expand the RootItem phantom items are created in the TreeListBox. Here's a simple example which shows the issue. To reproduce launch the app and hit the button before expanding anything in the TreeListBox - that will select an item in the tree. If you then expand the items on the left a few phantom entries will be displayed

Screen Shot Here

<Window x:Class="ActiProTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:ActiProTest"
        xmlns:ac="http://schemas.actiprosoftware.com/winfx/xaml/grids"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
  <DockPanel LastChildFill="True">
    <ac:TreeListBox       
      SelectionMode="Extended"
      MultiSelectionKind="SameDepth"
      IsRootItemVisible="True"
      Width="200"
      DockPanel.Dock="Left" 
      x:Name="_tree">
      <ac:TreeListBox.ItemAdapter>
        <local:LayerAdapter/>
      </ac:TreeListBox.ItemAdapter>
      <ac:TreeListBox.ItemTemplate>
        <DataTemplate>
          <TextBlock Text="{Binding Name}" />
        </DataTemplate>
      </ac:TreeListBox.ItemTemplate>
    </ac:TreeListBox>
    <Button Click="Button_Click">hit me</Button>
  </DockPanel>
</Window>
using ActiproSoftware.Windows.Controls.Grids;
using System.Collections;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Windows;

namespace ActiProTest
{
  /// <summary>
  /// Interaction logic for MainWindow.xaml
  /// </summary>
  public partial class MainWindow : Window
  {
    MyItem ItemToSelect;
    public MainWindow()
    {
      InitializeComponent();
      MyItem root = new MyItem() { Name = "The Root" };
      for( int ix = 0; ix < 5; ix++)
      {
        var subItem = new MyItem() { Name = $"child {ix + 1}" };
        for(int iy = 0; iy < 5; iy++)
        {
          var subsub = new MyItem() { Name = $"sub {ix + 1} {iy + 1}" };
          if (ix == 2 && iy == 3) ItemToSelect = subsub;
          subItem.Children.Add(subsub);
        }
        root.Children.Add(subItem);
      }
      _tree.RootItem = root;
    }

    private void Button_Click(object sender, RoutedEventArgs e)
    {
      ItemToSelect.IsSelected = true;
    }
  }


  public class MyItem : INotifyPropertyChanged
  {
    public event PropertyChangedEventHandler PropertyChanged;

    bool _IsSelected;
    public bool IsSelected
    {
      get { return _IsSelected; }
      set
      {
        if ( value != _IsSelected)
        {
          _IsSelected = value;
          PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("IsSelected"));
        }
      }
    }

    ObservableCollection<MyItem> _Children = new ObservableCollection<MyItem>();
    public ObservableCollection<MyItem> Children
    {
      get { return _Children; }
    }

    public string Name { get; set; }
  }

  public class LayerAdapter : TreeListBoxItemAdapter
  {

    public LayerAdapter()
    {
      IsSelectedPath = "IsSelected";
    }

    public override IEnumerable GetChildren(TreeListBox ownerControl, object item)
    {
      return (item as MyItem).Children;
    }

    public override bool GetIsSelected(TreeListBox ownerControl, object item)
    {
      return (item as MyItem).IsSelected;
    }

    public override void SetIsSelected(TreeListBox ownerControl, object item, bool value)
    {
      (item as MyItem).IsSelected = value;
    }

    public override bool CanHaveChildren(TreeListBox ownerControl, object item)
    {
      return (item as MyItem).Children.Count > 0;
    }
  }
}

[Modified 3 years ago]

Comments (2)

Posted 3 years ago by John Dunn
Avatar

I rolled back to 18.1.670 and the problem went away so it looks like this behavior was added in the 19.1 version. Unfortunately it's not possible to roll back our actual application to a version earlier than 19.1.

[Modified 3 years ago]

Posted 3 years ago by Actipro Software Support - Cleveland, OH, USA
Avatar

Hi John,

Thanks for the sample.  I believe we were able to track down the problem.  If you'd like to try a v2020.1 preview build with the update, please write our support address and mention this thread.


Actipro Software Support

The latest build of this product (v24.1.2) was released 1 days ago, which was after the last post in this thread.

Add Comment

Please log in to a validated account to post comments.