Git Product home page Git Product logo

avalonia.controls.treedatagrid's Introduction

NuGet

Avalonia TreeDataGrid

Introduction

TreeDataGrid is a control for the Avalonia UI framework which displays hierarchical and tabular data together in a single view. It is a combination of a TreeView and DataGrid control.

The control has two modes of operation:

  • Hierarchical: data is displayed in a tree with optional columns
  • Flat: data is displayed in a 2D table, similar to other DataGrid controls

An example of TreeDataGrid displaying hierarchical data:

TreeDataGrid in hierarchical mode

An example of TreeDataGrid displaying flat data:

TreeDataGrid in hierarchical mode

Current Status

The control is currently in early beta. As such there will be bugs, missing features and lacking docs, but the control should be generally usable and performant.

Note:

We accept issues and pull requests but we answer and review only pull requests and issues that are created by our customers. It's a quite big project and servicing all issues and pull requests will require more time than we have. But feel free to open issues and pull requests because they may be useful for us!

Getting Started

avalonia.controls.treedatagrid's People

Contributors

danipen avatar grokys avatar jizc avatar jmacato avatar maxkatz6 avatar superjmn avatar takoooooo avatar vmelnalksnis avatar wieslawsoltes avatar workgroupengineering avatar yohdeadfall avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

avalonia.controls.treedatagrid's Issues

Template columns in an expander are not recycled

If a TemplateColumn is placed in a HierarchicalExpanderColumn then the template is recreated each time the grid is scrolled.

You can see this by running the files tab on the sample application and putting a breakpoint here. When scrolling around, the breakpoint will be hit for each row that is brought into view, even though the templates should be getting recycled.

TreeDataGrid: Index out of bounds when pressing tab on an empty table

When changing the focus to the TreeDataGrid, pressing Tab, if the table is empty, we get an index out of bounds error.

This is the stack trace:

System.ArgumentOutOfRangeException: Index was out of range. Must be non-negative and less than the size of the collection. (Parameter 'index')
   at System.Collections.Generic.List`1.get_Item(Int32 index)
   at Avalonia.Controls.Models.TreeDataGrid.AnonymousSortableRows`1.get_Item(Int32 index) in /home/wkspaces/codice_static/01plastic/test/avalonia-test/Avalonia.Controls.TreeDataGrid/Models/TreeDataGrid/AnonymousSortableRows.cs:line 43
   at Avalonia.Controls.Models.TreeDataGrid.AnonymousSortableRows`1.System.Collections.Generic.IReadOnlyList<Avalonia.Controls.Models.TreeDataGrid.IRow>.get_Item(Int32 index) in /home/wkspaces/codice_static/01plastic/test/avalonia-test/Avalonia.Controls.TreeDataGrid/Models/TreeDataGrid/AnonymousSortableRows.cs:line 47
   at Avalonia.Controls.Primitives.TreeDataGridPresenterBase`1.GetRecycledOrCreateElement(Int32 index) in /home/wkspaces/codice_static/01plastic/test/avalonia-test/Avalonia.Controls.TreeDataGrid/Primitives/TreeDataGridPresenterBase.cs:line 329
   at Avalonia.Controls.Primitives.TreeDataGridPresenterBase`1.GetOrCreateElement(Int32 index) in /home/wkspaces/codice_static/01plastic/test/avalonia-test/Avalonia.Controls.TreeDataGrid/Primitives/TreeDataGridPresenterBase.cs:line 303
   at Avalonia.Controls.Primitives.TreeDataGridPresenterBase`1.BringIntoView(Int32 index) in /home/wkspaces/codice_static/01plastic/test/avalonia-test/Avalonia.Controls.TreeDataGrid/Primitives/TreeDataGridPresenterBase.cs:line 95
   at Avalonia.Controls.TreeDataGrid.MoveSelection(NavigationDirection direction, Boolean rangeModifier, ITreeDataGridCell focused) in /home/wkspaces/codice_static/01plastic/test/avalonia-test/Avalonia.Controls.TreeDataGrid/TreeDataGrid.cs:line 245
   at Avalonia.Controls.TreeDataGrid.OnKeyDown(KeyEventArgs e) in /home/wkspaces/codice_static/01plastic/test/avalonia-test/Avalonia.Controls.TreeDataGrid/TreeDataGrid.cs:line 173
   at Avalonia.Input.InputElement.<>c.<.cctor>b__30_2(InputElement x, KeyEventArgs e) in /_/src/Avalonia.Input/InputElement.cs:line 202
   at Avalonia.Interactivity.RoutedEvent`1.<>c__DisplayClass2_0`1.<AddClassHandler>g__Adapter|0(Object sender, RoutedEventArgs e) in /_/src/Avalonia.Interactivity/RoutedEvent.cs:line 145
   at Avalonia.Interactivity.RoutedEvent.<>c__DisplayClass23_0.<AddClassHandler>b__0(ValueTuple`2 args) in /_/src/Avalonia.Interactivity/RoutedEvent.cs:line 94
   at System.Reactive.AnonymousObserver`1.OnNextCore(T value) in /_/Rx.NET/Source/src/System.Reactive/AnonymousObserver.cs:line 67
   at System.Reactive.ObserverBase`1.OnNext(T value) in /_/Rx.NET/Source/src/System.Reactive/ObserverBase.cs:line 36
   at System.Reactive.Subjects.Subject`1.OnNext(T value) in /_/Rx.NET/Source/src/System.Reactive/Subjects/Subject.cs:line 147
   at Avalonia.Interactivity.RoutedEvent.InvokeRaised(Object sender, RoutedEventArgs e) in /_/src/Avalonia.Interactivity/RoutedEvent.cs:line 100
   at Avalonia.Interactivity.EventRoute.RaiseEventImpl(RoutedEventArgs e) in /_/src/Avalonia.Interactivity/EventRoute.cs:line 152
   at Avalonia.Interactivity.EventRoute.RaiseEvent(IInteractive source, RoutedEventArgs e) in /_/src/Avalonia.Interactivity/EventRoute.cs:line 102
   at Avalonia.Interactivity.Interactive.RaiseEvent(RoutedEventArgs e) in /_/src/Avalonia.Interactivity/Interactive.cs:line 121
   at Avalonia.Input.KeyboardDevice.ProcessRawEvent(RawInputEventArgs e) in /_/src/Avalonia.Input/KeyboardDevice.cs:line 230
   at Avalonia.Input.InputManager.ProcessInput(RawInputEventArgs e) in /_/src/Avalonia.Input/InputManager.cs:line 36
   at Avalonia.Controls.TopLevel.HandleInput(RawInputEventArgs e) in /_/src/Avalonia.Controls/TopLevel.cs:line 477
   at Avalonia.X11.X11Window.<ScheduleInput>b__120_0() in /_/src/Avalonia.X11/X11Window.cs:line 715
   at Avalonia.Threading.JobRunner.Job.Avalonia.Threading.JobRunner.IJob.Run() in /_/src/Avalonia.Base/Threading/JobRunner.cs:line 167
   at Avalonia.Threading.JobRunner.RunJobs(Nullable`1 priority) in /_/src/Avalonia.Base/Threading/JobRunner.cs:line 31
   at Avalonia.Threading.Dispatcher.RunJobs() in /_/src/Avalonia.Base/Threading/Dispatcher.cs:line 70
   at Avalonia.X11.X11PlatformThreading.HandleX11(CancellationToken cancellationToken) in /_/src/Avalonia.X11/X11PlatformThreading.cs:line 200
   at Avalonia.X11.X11PlatformThreading.RunLoop(CancellationToken cancellationToken) in /_/src/Avalonia.X11/X11PlatformThreading.cs:line 205
   at Avalonia.Threading.Dispatcher.MainLoop(CancellationToken cancellationToken) in /_/src/Avalonia.Base/Threading/Dispatcher.cs:line 62
   at Avalonia.Controls.SyncDialogExtensions.ShowDialogSync[T](Window window, Window owner) in /home/wkspaces/codice_static/01plastic/src/client/guiplastic/avalonia/ui/extensions/WindowExtensions.cs:line 73
   at PlasticAvalonia.WorkspaceWindow.Views.PendingChanges.Dialogs.SearchMatchesDialog.AskForMatches(WorkspaceInfo wkInfo, WorkspaceWindow window, String changePath) in /home/wkspaces/codice_static/01plastic/src/client/guiplastic/avalonia/plastic/workspacewindow/views/pendingchanges/dialogs/SearchMatchesDialog.cs:line 38
   at PlasticAvalonia.WorkspaceWindow.Views.PendingChanges.PendingChangesView.AskForMatches(String changePath) in /home/wkspaces/codice_static/01plastic/src/client/guiplastic/avalonia/plastic/workspacewindow/views/pendingchanges/PendingChangesView.cs:line 458
   at PlasticGui.WorkspaceWindow.PendingChanges.SearchMatchesOperation.SearchMatches(ChangeInfo selected, List`1 allChanges) in /home/wkspaces/codice_static/01plastic/src/client/guiplastic/plasticgui/workspacewindow/pendingchanges/SearchMatchesOperation.cs:line 37
   at PlasticAvalonia.WorkspaceWindow.Views.PendingChanges.PendingChangesView.SearchMatches() in /home/wkspaces/codice_static/01plastic/src/client/guiplastic/avalonia/plastic/workspacewindow/views/pendingchanges/PendingChangesView.cs:line 399
   at PlasticAvalonia.WorkspaceWindow.Views.PendingChanges.PendingChangesView.UndoButton_Click(Object sender, EventArgs e) in /home/wkspaces/codice_static/01plastic/src/client/guiplastic/avalonia/plastic/workspacewindow/views/pendingchanges/PendingChangesView.cs:line 872
   at UiAvalonia.Exceptions.EventProtection`1.Event(Object sender, T e) in /home/wkspaces/codice_static/01plastic/src/client/guiplastic/avalonia/ui/exceptions/ProtectedEventsTranslator.cs:line 191

Unwanted scroll in header

When you use the touch pad in macOS and you place the pointer in the TreeDataGrid header, if you scroll horizontally, only the header is scrolled.

Edit mode example

Hello,

Is there any example that exists for the edit mode?

I try to use TextColumn with getter and setter and no success.

new TextColumn<BsonValue, string>(
	key,
	v => v[key].ToString(),
	(b, v) => b[key] = v)

Thanks.

Collection Move not supported

Randomly got this exception.
Flat source was used.
Shouldn't Move operation be supported as well?

Unhandled exception. System.NotSupportedException: Collection Move not supported.
   at Avalonia.Controls.Selection.TreeSelectionNode`1.OnSourceCollectionChanged(NotifyCollectionChangedEventArgs e) in /_/src/Avalonia.Controls.TreeDataGrid/Selection/TreeSelectionNode.cs:line 158
   at Avalonia.Controls.Selection.SelectionNodeBase`1.Avalonia.Controls.Utils.ICollectionChangedListener.Changed(INotifyCollectionChanged sender, NotifyCollectionChangedEventArgs e) in /_/src/Avalonia.Controls.TreeDataGrid/Selection/SelectionNodeBase.cs:line 86
   at Avalonia.Controls.Utils.CollectionChangedEventManager.<Avalonia.Utilities.IWeakSubscriber<System.Collections.Specialized.NotifyCollectionChangedEventArgs>.OnEvent>g__Notify|7_0(INotifyCollectionChanged incc, NotifyCollectionChangedEventArgs args, List`1 listeners) in /_/src/Avalonia.Controls.TreeDataGrid/Utils/CollectionChangedEventManager.cs:line 100
   at Avalonia.Controls.Utils.CollectionChangedEventManager.Avalonia.Utilities.IWeakSubscriber<System.Collections.Specialized.NotifyCollectionChangedEventArgs>.OnEvent(Object sender, NotifyCollectionChangedEventArgs e) in /_/src/Avalonia.Controls.TreeDataGrid/Utils/CollectionChangedEventManager.cs:line 117
   at Avalonia.Utilities.WeakSubscriptionManager.Subscription`1.OnEvent(Object sender, T eventArgs) in /_/src/Avalonia.Base/Utilities/WeakSubscriptionManager.cs:line 184
   at System.Collections.ObjectModel.ReadOnlyObservableCollection`1.OnCollectionChanged(NotifyCollectionChangedEventArgs args)
   at System.Collections.ObjectModel.ReadOnlyObservableCollection`1.HandleCollectionChanged(Object sender, NotifyCollectionChangedEventArgs e)
   at System.Collections.ObjectModel.ObservableCollection`1.OnCollectionChanged(NotifyCollectionChangedEventArgs e)
   at System.Collections.ObjectModel.ObservableCollection`1.MoveItem(Int32 oldIndex, Int32 newIndex)
   at System.Collections.ObjectModel.ObservableCollection`1.Move(Int32 oldIndex, Int32 newIndex)
   at DynamicData.Binding.ObservableCollectionExtended`1.DynamicData.Binding.IObservableCollection<T>.Move(Int32 oldIndex, Int32 newIndex)
   at DynamicData.Binding.SortedObservableCollectionAdaptor`2.DoUpdate(ISortedChangeSet`2 updates, IObservableCollection`1 list) in /_/src/DynamicData/Binding/SortedObservableCollectionAdaptor.cs:line 93
   at DynamicData.Binding.SortedObservableCollectionAdaptor`2.Adapt(ISortedChangeSet`2 changes, IObservableCollection`1 collection) in /_/src/DynamicData/Binding/SortedObservableCollectionAdaptor.cs:line 71
   at DynamicData.ObservableCacheEx.<>c__DisplayClass27_0`2.<Bind>b__1(ISortedChangeSet`2 changes) in /_/src/DynamicData/Cache/ObservableCacheEx.cs:line 691
   at System.Reactive.Linq.ObservableImpl.Select`2.Selector._.OnNext(TSource value) in /_/Rx.NET/Source/src/System.Reactive/Linq/Observable/Select.cs:line 48
--- End of stack trace from previous location ---
   at System.Reactive.PlatformServices.ExceptionServicesImpl.Rethrow(Exception exception) in /_/Rx.NET/Source/src/System.Reactive/Internal/ExceptionServicesImpl.cs:line 19
   at System.Reactive.ExceptionHelpers.Throw(Exception exception) in /_/Rx.NET/Source/src/System.Reactive/Internal/ExceptionServices.cs:line 16
   at System.Reactive.Stubs.<>c.<.cctor>b__2_1(Exception ex) in /_/Rx.NET/Source/src/System.Reactive/Internal/Stubs.cs:line 16
   at System.Reactive.AnonymousObserver`1.OnErrorCore(Exception error) in /_/Rx.NET/Source/src/System.Reactive/AnonymousObserver.cs:line 73
   at System.Reactive.ObserverBase`1.OnError(Exception error) in /_/Rx.NET/Source/src/System.Reactive/ObserverBase.cs:line 59
   at System.Reactive.AutoDetachObserver`1.OnErrorCore(Exception exception) in /_/Rx.NET/Source/src/System.Reactive/Internal/AutoDetachObserver.cs:line 77
   at System.Reactive.ObserverBase`1.OnError(Exception error) in /_/Rx.NET/Source/src/System.Reactive/ObserverBase.cs:line 59
   at System.Reactive.Sink`1.ForwardOnError(Exception error) in /_/Rx.NET/Source/src/System.Reactive/Internal/Sink.cs:line 60
   at System.Reactive.Linq.ObservableImpl.Select`2.Selector._.OnNext(TSource value) in /_/Rx.NET/Source/src/System.Reactive/Linq/Observable/Select.cs:line 48
   at System.Reactive.Concurrency.Synchronize`1._.OnNext(TSource value) in /_/Rx.NET/Source/src/System.Reactive/Concurrency/Synchronization.Synchronize.cs:line 44
   at System.Reactive.ObserveOnObserverNew`1.DrainStep(ConcurrentQueue`1 q) in /_/Rx.NET/Source/src/System.Reactive/Internal/ScheduledObserver.cs:line 559
   at System.Reactive.ObserveOnObserverNew`1.DrainShortRunning(IScheduler recursiveScheduler) in /_/Rx.NET/Source/src/System.Reactive/Internal/ScheduledObserver.cs:line 513
   at Avalonia.Threading.AvaloniaScheduler.<>c__DisplayClass4_1`1.<Schedule>b__1() in /_/src/Avalonia.Base/Threading/AvaloniaScheduler.cs:line 45
   at Avalonia.Threading.JobRunner.RunJobs(Nullable`1 priority) in /_/src/Avalonia.Base/Threading/JobRunner.cs:line 37
   at Avalonia.Native.PlatformThreadingInterface.SignaledCallback.Signaled(Int32 priority, Int32 priorityContainsMeaningfulValue) in /_/src/Avalonia.Native/PlatformThreadingInterface.cs:line 39
   at Avalonia.Native.Interop.Impl.__MicroComIAvnSignaledCallbackVTable.Signaled(IntPtr this, Int32 priority, Int32 priorityContainsMeaningfulValue) in /_/src/Avalonia.Native/Interop.Generated.cs:line 3796
--- End of stack trace from previous location ---
   at Avalonia.Native.PlatformThreadingInterface.RunLoop(CancellationToken cancellationToken) in /_/src/Avalonia.Native/PlatformThreadingInterface.cs:line 90
   at Avalonia.Threading.Dispatcher.MainLoop(CancellationToken cancellationToken) in /_/src/Avalonia.Base/Threading/Dispatcher.cs:line 65
   at Avalonia.Controls.ApplicationLifetimes.ClassicDesktopStyleApplicationLifetime.Start(String[] args) in /_/src/Avalonia.Controls/ApplicationLifetimes/ClassicDesktopStyleApplicationLifetime.cs:line 120
   at Avalonia.ClassicDesktopStyleApplicationLifetimeExtensions.StartWithClassicDesktopLifetime[T](T builder, String[] args, ShutdownMode shutdownMode) in /_/src/Avalonia.Controls/ApplicationLifetimes/ClassicDesktopStyleApplicationLifetime.cs:line 209
   at Program.Main(String[] args)

'Specified argument was out of the range of valid values. Arg_ParamName_Name'

Help me, please
I have three observable collections that I want to add to the tables. I do following:

public FlatTreeDataGridSource<BaseAccessPoint> AccessPointSource { get; }
public FlatTreeDataGridSource<BaseController> ControllerSource { get; }
public FlatTreeDataGridSource<BasePort> PortSource { get; }
public MainWindowViewModel()
{
        AccessPointSource = new FlatTreeDataGridSource<BaseAccessPoint>( BaseAccessPoint )
        {
            Columns =
            {
                new TextColumn<BaseAccessPoint, string?>( "Timestamp", x => x.LocalTime, GridLength.Star ),
                new TextColumn<BaseAccessPoint, string?>( "Event/Command", x => x.EventName, GridLength.Star )
            },
            Items = BaseAccessPoint
        };

         ... etc
}

My view:

<TreeDataGrid Source="{Binding PortSource}" Grid.Column="0" Grid.Row="1"/>
<TreeDataGrid Source="{Binding ControllerSource }" Grid.Column="1" Grid.Row="1"/>
<TreeDataGrid Source="{Binding AccessPointSource }" Grid.Column="2" Grid.Row="1"/>

I think I'm doing everything right, but unfortunately I get an error:
'Specified argument was out of the range of valid values. Arg_ParamName_Name'

StackTrace:

at Avalonia.Controls.Primitives.TreeDataGridCellsPresenter.UpdateRowIndex(Int32 index) in /_/src/Avalonia.Controls.TreeDataGrid/Primitives/TreeDataGridCellsPresenter.cs:line 67
 at Avalonia.Controls.Primitives.TreeDataGridRow.UpdateIndex(Int32 index) in /_/src/Avalonia.Controls.TreeDataGrid/Primitives/TreeDataGridRow.cs:line 86
 at Avalonia.Controls.Primitives.TreeDataGridRowsPresenter.UpdateElementIndex(IControl element, Int32 index) in /_/src/Avalonia.Controls.TreeDataGrid/Primitives/TreeDataGridRowsPresenter.cs:line 82
 at Avalonia.Controls.Primitives.RealizedElementList.ItemsInserted(Int32 modelIndex, Int32 count, Action`2 updateElementIndex) in /_/src/Avalonia.Controls.TreeDataGrid/Primitives/RealizedElementList.cs:line 124
 at Avalonia.Controls.Primitives.TreeDataGridPresenterBase`1.OnItemsCollectionChanged(Object sender, NotifyCollectionChangedEventArgs e) in /_/src/Avalonia.Controls.TreeDataGrid/Primitives/TreeDataGridPresenterBase.cs:line 584
 at Avalonia.Controls.Models.TreeDataGrid.AnonymousSortableRows`1.OnItemsCollectionChangedUnsorted(NotifyCollectionChangedEventArgs e) in /_/src/Avalonia.Controls.TreeDataGrid/Models/TreeDataGrid/AnonymousSortableRows.cs:line 167
 at Avalonia.Controls.Models.TreeDataGrid.AnonymousSortableRows`1.OnItemsCollectionChanged(Object sender, NotifyCollectionChangedEventArgs e) in /_/src/Avalonia.Controls.TreeDataGrid/Models/TreeDataGrid/AnonymousSortableRows.cs:line 135
 at Avalonia.Controls.TreeDataGridItemsSourceView.OnItemsSourceChanged(NotifyCollectionChangedEventArgs args) in /_/src/Avalonia.Controls.TreeDataGrid/TreeDataGridItemsSourceView.cs:line 216
 at Avalonia.Controls.TreeDataGridItemsSourceView.Avalonia.Controls.Utils.ICollectionChangedListener.Changed(INotifyCollectionChanged sender, NotifyCollectionChangedEventArgs e) in /_/src/Avalonia.Controls.TreeDataGrid/TreeDataGridItemsSourceView.cs:line 191
 at Avalonia.Controls.Utils.CollectionChangedEventManager.<Avalonia.Utilities.IWeakSubscriber<System.Collections.Specialized.NotifyCollectionChangedEventArgs>.OnEvent>g__Notify|7_0(INotifyCollectionChanged incc, NotifyCollectionChangedEventArgs args, List`1 listeners) in /_/src/Avalonia.Controls.TreeDataGrid/Utils/CollectionChangedEventManager.cs:line 96
 at Avalonia.Controls.Utils.CollectionChangedEventManager.<>c__DisplayClass7_0.<Avalonia.Utilities.IWeakSubscriber<System.Collections.Specialized.NotifyCollectionChangedEventArgs>.OnEvent>b__1() in /_/src/Avalonia.Controls.TreeDataGrid/Utils/CollectionChangedEventManager.cs:line 124
 at Avalonia.Threading.JobRunner.RunJobs(Nullable`1 priority) in /_/src/Avalonia.Base/Threading/JobRunner.cs:line 37
 at Avalonia.Win32.Win32Platform.WndProc(IntPtr hWnd, UInt32 msg, IntPtr wParam, IntPtr lParam) in /_/src/Windows/Avalonia.Win32/Win32Platform.cs:line 266
 at Avalonia.Win32.Interop.UnmanagedMethods.DispatchMessage(MSG& lpmsg)
 at Avalonia.Win32.Win32Platform.RunLoop(CancellationToken cancellationToken) in /_/src/Windows/Avalonia.Win32/Win32Platform.cs:line 210
 at Avalonia.Threading.Dispatcher.MainLoop(CancellationToken cancellationToken) in /_/src/Avalonia.Base/Threading/Dispatcher.cs:line 66
 at Avalonia.Controls.ApplicationLifetimes.ClassicDesktopStyleApplicationLifetime.Start(String[] args) in /_/src/Avalonia.Controls/ApplicationLifetimes/ClassicDesktopStyleApplicationLifetime.cs:line 121
 at Avalonia.ClassicDesktopStyleApplicationLifetimeExtensions.StartWithClassicDesktopLifetime[T](T builder, String[] args, ShutdownMode shutdownMode) in /_/src/Avalonia.Controls/ApplicationLifetimes/ClassicDesktopStyleApplicationLifetime.cs:line 209

Why 'Hierarchical' instead of 'Tree'?

This term was changed in Avalonia (TreeDataTemplate) and even the name of the control uses 'Tree'. I think it would make sense to rename the two modes:

  1. Hierarchical: -> Tree
  2. Flat: -> List

"List" implies 1 dimension, and "Tree" implies 2 dimensions. I think this makes the most sense and matches other Avalonia terminology.

Exception when resetting items.

Repro:

  • Run ProControlsDemo, go to Files tab
  • Expand C:\, Windows, Program Files in that order
  • Select another drive from drop-down

Exception:

System.ArgumentOutOfRangeException
  HResult=0x80131502
  Message=Non-negative number required. Arg_ParamName_Name
  Source=System.Private.CoreLib
>	Avalonia.Controls.TreeDataGrid.dll!Avalonia.Controls.Primitives.RealizedElementList.ItemsRemoved(int modelIndex, int count, System.Action<Avalonia.Controls.IControl, int> updateElementIndex, System.Action<Avalonia.Controls.IControl> recycleElement) Line 185	C#
 	Avalonia.Controls.TreeDataGrid.dll!Avalonia.Controls.Primitives.TreeDataGridPresenterBase<Avalonia.Controls.Models.TreeDataGrid.IRow>.OnItemsCollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) Line 476	C#
 	Avalonia.Controls.TreeDataGrid.dll!Avalonia.Controls.Models.TreeDataGrid.HierarchicalRows<ProControlsDemo.Models.FileTreeNodeModel>.OnCollectionChanged.__Remove|33_1(int index, int count, bool raise) Line 270	C#
 	Avalonia.Controls.TreeDataGrid.dll!Avalonia.Controls.Models.TreeDataGrid.HierarchicalRows<ProControlsDemo.Models.FileTreeNodeModel>.OnCollectionChanged(Avalonia.Controls.IndexPath parentIndex, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) Line 349	C#
 	Avalonia.Controls.TreeDataGrid.dll!Avalonia.Controls.Models.TreeDataGrid.HierarchicalRows<ProControlsDemo.Models.FileTreeNodeModel>.Avalonia.Controls.Models.TreeDataGrid.IExpanderRowController<ProControlsDemo.Models.FileTreeNodeModel>.OnChildCollectionChanged(Avalonia.Controls.Models.TreeDataGrid.IExpanderRow<ProControlsDemo.Models.FileTreeNodeModel> row, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) Line 181	C#
 	Avalonia.Controls.TreeDataGrid.dll!Avalonia.Controls.Models.TreeDataGrid.HierarchicalRow<ProControlsDemo.Models.FileTreeNodeModel>.ChildRows.OnCollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) Line 181	C#
 	Avalonia.Controls.TreeDataGrid.dll!Avalonia.Controls.Models.TreeDataGrid.SortableRowsBase<ProControlsDemo.Models.FileTreeNodeModel, Avalonia.Controls.Models.TreeDataGrid.HierarchicalRow<ProControlsDemo.Models.FileTreeNodeModel>>.OnItemsCollectionChangedUnsorted(System.Collections.Specialized.NotifyCollectionChangedEventArgs e) Line 225	C#
 	Avalonia.Controls.TreeDataGrid.dll!Avalonia.Controls.Models.TreeDataGrid.SortableRowsBase<ProControlsDemo.Models.FileTreeNodeModel, Avalonia.Controls.Models.TreeDataGrid.HierarchicalRow<ProControlsDemo.Models.FileTreeNodeModel>>.OnItemsCollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) Line 135	C#
 	Avalonia.Controls.TreeDataGrid.dll!Avalonia.Controls.Models.TreeDataGrid.SortableRowsBase<ProControlsDemo.Models.FileTreeNodeModel, Avalonia.Controls.Models.TreeDataGrid.HierarchicalRow<ProControlsDemo.Models.FileTreeNodeModel>>.SetItems(Avalonia.Controls.ItemsSourceViewFix<ProControlsDemo.Models.FileTreeNodeModel> items) Line 73	C#
 	Avalonia.Controls.TreeDataGrid.dll!Avalonia.Controls.Models.TreeDataGrid.SortableRowsBase<ProControlsDemo.Models.FileTreeNodeModel, Avalonia.Controls.Models.TreeDataGrid.HierarchicalRow<ProControlsDemo.Models.FileTreeNodeModel>>.Dispose() Line 49	C#
 	Avalonia.Controls.TreeDataGrid.dll!Avalonia.Controls.Models.TreeDataGrid.HierarchicalRow<ProControlsDemo.Models.FileTreeNodeModel>.Dispose() Line 93	C#
 	Avalonia.Controls.TreeDataGrid.dll!Avalonia.Controls.Models.TreeDataGrid.SortableRowsBase<ProControlsDemo.Models.FileTreeNodeModel, Avalonia.Controls.Models.TreeDataGrid.HierarchicalRow<ProControlsDemo.Models.FileTreeNodeModel>>.ResetRows() Line 125	C#
 	Avalonia.Controls.TreeDataGrid.dll!Avalonia.Controls.Models.TreeDataGrid.SortableRowsBase<ProControlsDemo.Models.FileTreeNodeModel, Avalonia.Controls.Models.TreeDataGrid.HierarchicalRow<ProControlsDemo.Models.FileTreeNodeModel>>.OnItemsCollectionChangedUnsorted(System.Collections.Specialized.NotifyCollectionChangedEventArgs e) Line 224	C#
 	Avalonia.Controls.TreeDataGrid.dll!Avalonia.Controls.Models.TreeDataGrid.SortableRowsBase<ProControlsDemo.Models.FileTreeNodeModel, Avalonia.Controls.Models.TreeDataGrid.HierarchicalRow<ProControlsDemo.Models.FileTreeNodeModel>>.OnItemsCollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) Line 135	C#
 	Avalonia.Controls.TreeDataGrid.dll!Avalonia.Controls.Models.TreeDataGrid.SortableRowsBase<ProControlsDemo.Models.FileTreeNodeModel, Avalonia.Controls.Models.TreeDataGrid.HierarchicalRow<ProControlsDemo.Models.FileTreeNodeModel>>.SetItems(Avalonia.Controls.ItemsSourceViewFix<ProControlsDemo.Models.FileTreeNodeModel> items) Line 73	C#
 	Avalonia.Controls.TreeDataGrid.dll!Avalonia.Controls.Models.TreeDataGrid.SortableRowsBase<ProControlsDemo.Models.FileTreeNodeModel, Avalonia.Controls.Models.TreeDataGrid.HierarchicalRow<ProControlsDemo.Models.FileTreeNodeModel>>.Dispose() Line 49	C#
 	Avalonia.Controls.TreeDataGrid.dll!Avalonia.Controls.Models.TreeDataGrid.HierarchicalRow<ProControlsDemo.Models.FileTreeNodeModel>.Dispose() Line 93	C#
 	Avalonia.Controls.TreeDataGrid.dll!Avalonia.Controls.Models.TreeDataGrid.SortableRowsBase<ProControlsDemo.Models.FileTreeNodeModel, Avalonia.Controls.Models.TreeDataGrid.HierarchicalRow<ProControlsDemo.Models.FileTreeNodeModel>>.ResetRows() Line 125	C#
 	Avalonia.Controls.TreeDataGrid.dll!Avalonia.Controls.Models.TreeDataGrid.SortableRowsBase<ProControlsDemo.Models.FileTreeNodeModel, Avalonia.Controls.Models.TreeDataGrid.HierarchicalRow<ProControlsDemo.Models.FileTreeNodeModel>>.OnItemsCollectionChangedUnsorted(System.Collections.Specialized.NotifyCollectionChangedEventArgs e) Line 224	C#
 	Avalonia.Controls.TreeDataGrid.dll!Avalonia.Controls.Models.TreeDataGrid.SortableRowsBase<ProControlsDemo.Models.FileTreeNodeModel, Avalonia.Controls.Models.TreeDataGrid.HierarchicalRow<ProControlsDemo.Models.FileTreeNodeModel>>.OnItemsCollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) Line 135	C#
 	Avalonia.Controls.TreeDataGrid.dll!Avalonia.Controls.Models.TreeDataGrid.SortableRowsBase<ProControlsDemo.Models.FileTreeNodeModel, Avalonia.Controls.Models.TreeDataGrid.HierarchicalRow<ProControlsDemo.Models.FileTreeNodeModel>>.SetItems(Avalonia.Controls.ItemsSourceViewFix<ProControlsDemo.Models.FileTreeNodeModel> items) Line 73	C#
 	Avalonia.Controls.TreeDataGrid.dll!Avalonia.Controls.Models.TreeDataGrid.HierarchicalRows<ProControlsDemo.Models.FileTreeNodeModel>.SetItems(Avalonia.Controls.ItemsSourceViewFix<ProControlsDemo.Models.FileTreeNodeModel> items) Line 118	C#
 	Avalonia.Controls.TreeDataGrid.dll!Avalonia.Controls.HierarchicalTreeDataGridSource<ProControlsDemo.Models.FileTreeNodeModel>.Items.set(System.Collections.Generic.IEnumerable<ProControlsDemo.Models.FileTreeNodeModel> value) Line 51	C#
 	ProControlsDemo.dll!ProControlsDemo.ViewModels.FilesPageViewModel..ctor.AnonymousMethod__4_2(string x) Line 88	C#

TreeDataGridPresenterBase doesn't clean up visual and logical children on assigning a new collection to the Items property

When I tried to write a unit test for some other problem I have realized the Items property would not call OnItemsCollectionChanged with NotifyCollectionChangedAction.Reset
image
But even when we rework the test in that way(which would call OnItemsCollectionChanged with NotifyCollectionChangedAction.Reset)
image
it would not work also since in OnItemsCollectionChanged we call only RecycleAllElements but I think we should also cleanup realized elements and visual\logical children when we receive an empty collection as a value in Items .

Updating Source causes star-sized columns to collapse

I was trying to overcome this issue. To do so, I set a new Source every time the model changes, in order to force the TreeDataGrid to update its contents.

However, this has led me to another bug:

  • When TreeDataGrid.Source is set the 1st time, things go OK
  • but when you try set it afterwards, star-sized columns collapse.
TreeDataGridWeirdColumn_JmNitN6nAj.mp4

The code to reproduce this is really simple. You can reproduce it by cloning this repo

TreeDataGrid version: 0.10.10

Issues bringing newly added row into view.

Repro can be seen here: 18db01c

  • Run sample app
  • Remove all items not fully visible on the screen
  • Leave space of less than a row after last item
  • Add new row
  • Newly added row is laid out incorrectly
  • Add another new row
  • New row is not brought into view and scrollbar does not appear

Unable to edit cells using pointer pressed

The cell is never selected (TreeDataGridCell.IsSelected is never set) and it prevents BeginEdit being called in OnPointerPressed

if (!_isEditing && CanEdit && !e.Handled && IsSelected)

Also OnKeyDown event in TreeDataGridCell does not check if cell is selected (IsSelected == true):

if (!_isEditing && CanEdit && !e.Handled && e.Key == Key.F2)

ObjectDisposedException on ShowExpanderObservable`1.Subscribed while measuring layout

Describe the bug
Exception is thrown upon rendering a new window with TreeDataGrid without clear explanation of what went wrong

To Reproduce
Steps to reproduce the behavior:

treedatagrid-bug.zip

  1. Download reproduction project
  2. Enter any text into text box
  3. Press crash

Expected behavior
No exception or exception explaining incorrect usage

Stacktrace

 	Avalonia.Controls.TreeDataGrid.dll!Avalonia.Controls.Models.TreeDataGrid.ShowExpanderObservable`1.Subscribed()	C#
 	Avalonia.Base.dll!Avalonia.Reactive.SingleSubscriberObservableBase`1.Subscribe(System.IObserver observer = {unknown})	C#
 	Avalonia.Controls.TreeDataGrid.dll!Avalonia.Controls.Models.TreeDataGrid.ExpanderCell`1..ctor(Avalonia.Controls.Models.TreeDataGrid.ICell inner = {unknown}, Avalonia.Controls.Models.TreeDataGrid.IExpanderRow row = {unknown}, System.IObservable<bool> showExpander = {unknown}, Avalonia.Experimental.Data.Core.TypedBindingExpression isExpanded = {unknown})	C#
 	Avalonia.Controls.TreeDataGrid.dll!Avalonia.Controls.Models.TreeDataGrid.HierarchicalExpanderColumn`1.CreateCell(Avalonia.Controls.Models.TreeDataGrid.IRow row = {unknown})	C#
 	Avalonia.Controls.TreeDataGrid.dll!Avalonia.Controls.Primitives.TreeDataGridCellsPresenter.GetElementFromFactory(Avalonia.Controls.Models.TreeDataGrid.IColumn column = {unknown}, int index = {unknown})	C#
 	Avalonia.Controls.TreeDataGrid.dll!Avalonia.Controls.Primitives.TreeDataGridPresenterBase`1.GetRecycledOrCreateElement(int index = {unknown})	C#
 	Avalonia.Controls.TreeDataGrid.dll!Avalonia.Controls.Primitives.TreeDataGridPresenterBase`1.GenerateElements(Avalonia.Size availableSize = {unknown}, ref MeasureViewport viewport = {unknown})	C#
 	Avalonia.Controls.TreeDataGrid.dll!Avalonia.Controls.Primitives.TreeDataGridPresenterBase`1.MeasureOverride(Avalonia.Size availableSize = {unknown})	C#
 	Avalonia.Base.dll!Avalonia.Layout.Layoutable.MeasureCore(Avalonia.Size availableSize = {unknown})	C#
 	Avalonia.Base.dll!Avalonia.Layout.Layoutable.Measure(Avalonia.Size availableSize = {unknown})	C#
 	Avalonia.Base.dll!Avalonia.Layout.LayoutHelper.MeasureChild(Avalonia.Layout.ILayoutable control = {unknown}, Avalonia.Size availableSize = {unknown}, Avalonia.Thickness padding = {unknown}, Avalonia.Thickness borderThickness = {unknown})	C#
 	Avalonia.Controls.dll!Avalonia.Controls.Border.MeasureOverride(Avalonia.Size availableSize = {unknown})	C#
 	Avalonia.Base.dll!Avalonia.Layout.Layoutable.MeasureCore(Avalonia.Size availableSize = {unknown})	C#
 	Avalonia.Base.dll!Avalonia.Layout.Layoutable.Measure(Avalonia.Size availableSize = {unknown})	C#
 	Avalonia.Base.dll!Avalonia.Layout.Layoutable.MeasureOverride(Avalonia.Size availableSize = {unknown})	C#
 	Avalonia.Base.dll!Avalonia.Layout.Layoutable.MeasureCore(Avalonia.Size availableSize = {unknown})	C#
 	Avalonia.Base.dll!Avalonia.Layout.Layoutable.Measure(Avalonia.Size availableSize = {unknown})	C#
 	Avalonia.Controls.TreeDataGrid.dll!Avalonia.Controls.Primitives.TreeDataGridPresenterBase`1.MeasureElement(int index = {unknown}, Avalonia.Controls.IControl element = {unknown}, Avalonia.Size availableSize = {unknown})	C#
 	Avalonia.Controls.TreeDataGrid.dll!Avalonia.Controls.Primitives.TreeDataGridPresenterBase`1.GenerateElements(Avalonia.Size availableSize = {unknown}, ref MeasureViewport viewport = {unknown})	C#
 	Avalonia.Controls.TreeDataGrid.dll!Avalonia.Controls.Primitives.TreeDataGridPresenterBase`1.MeasureOverride(Avalonia.Size availableSize = {unknown})	C#
 	Avalonia.Base.dll!Avalonia.Layout.Layoutable.MeasureCore(Avalonia.Size availableSize = {unknown})	C#
 	Avalonia.Base.dll!Avalonia.Layout.Layoutable.Measure(Avalonia.Size availableSize = {unknown})	C#
 	Avalonia.Controls.dll!Avalonia.Controls.Presenters.ScrollContentPresenter.MeasureOverride(Avalonia.Size availableSize = {unknown})	C#
 	Avalonia.Base.dll!Avalonia.Layout.Layoutable.MeasureCore(Avalonia.Size availableSize = {unknown})	C#
 	Avalonia.Base.dll!Avalonia.Layout.Layoutable.Measure(Avalonia.Size availableSize = {unknown})	C#
 	Avalonia.Controls.dll!Avalonia.Controls.Grid.MeasureCell(int cell = {unknown}, bool forceInfinityV = {unknown})	C#
 	Avalonia.Controls.dll!Avalonia.Controls.Grid.MeasureCellsGroup(int cellsHead = {unknown}, Avalonia.Size referenceSize = {unknown}, bool ignoreDesiredSizeU = {unknown}, bool forceInfinityV = {unknown}, out bool hasDesiredSizeUChanged = {unknown})	C#
 	Avalonia.Controls.dll!Avalonia.Controls.Grid.MeasureOverride(Avalonia.Size constraint = {unknown})	C#
 	Avalonia.Base.dll!Avalonia.Layout.Layoutable.MeasureCore(Avalonia.Size availableSize = {unknown})	C#
 	Avalonia.Base.dll!Avalonia.Layout.Layoutable.Measure(Avalonia.Size availableSize = {unknown})	C#
 	Avalonia.Base.dll!Avalonia.Layout.Layoutable.MeasureOverride(Avalonia.Size availableSize = {unknown})	C#
 	Avalonia.Base.dll!Avalonia.Layout.Layoutable.MeasureCore(Avalonia.Size availableSize = {unknown})	C#
 	Avalonia.Base.dll!Avalonia.Layout.Layoutable.Measure(Avalonia.Size availableSize = {unknown})	C#
 	Avalonia.Controls.dll!Avalonia.Controls.DockPanel.MeasureOverride(Avalonia.Size constraint = {unknown})	C#
 	Avalonia.Base.dll!Avalonia.Layout.Layoutable.MeasureCore(Avalonia.Size availableSize = {unknown})	C#
 	Avalonia.Base.dll!Avalonia.Layout.Layoutable.Measure(Avalonia.Size availableSize = {unknown})	C#
 	Avalonia.Base.dll!Avalonia.Layout.LayoutHelper.MeasureChild(Avalonia.Layout.ILayoutable control = {unknown}, Avalonia.Size availableSize = {unknown}, Avalonia.Thickness padding = {unknown}, Avalonia.Thickness borderThickness = {unknown})	C#
 	Avalonia.Controls.dll!Avalonia.Controls.Border.MeasureOverride(Avalonia.Size availableSize = {unknown})	C#
 	Avalonia.Base.dll!Avalonia.Layout.Layoutable.MeasureCore(Avalonia.Size availableSize = {unknown})	C#
 	Avalonia.Base.dll!Avalonia.Layout.Layoutable.Measure(Avalonia.Size availableSize = {unknown})	C#
 	Avalonia.Base.dll!Avalonia.Layout.Layoutable.MeasureOverride(Avalonia.Size availableSize = {unknown})	C#
 	Avalonia.Base.dll!Avalonia.Layout.Layoutable.MeasureCore(Avalonia.Size availableSize = {unknown})	C#
 	Avalonia.Base.dll!Avalonia.Layout.Layoutable.Measure(Avalonia.Size availableSize = {unknown})	C#
 	Avalonia.Controls.dll!Avalonia.Controls.StackPanel.MeasureOverride(Avalonia.Size availableSize = {unknown})	C#
 	Avalonia.Base.dll!Avalonia.Layout.Layoutable.MeasureCore(Avalonia.Size availableSize = {unknown})	C#
 	Avalonia.Base.dll!Avalonia.Layout.Layoutable.Measure(Avalonia.Size availableSize = {unknown})	C#
 	Avalonia.Base.dll!Avalonia.Layout.LayoutHelper.MeasureChild(Avalonia.Layout.ILayoutable control = {unknown}, Avalonia.Size availableSize = {unknown}, Avalonia.Thickness padding = {unknown}, Avalonia.Thickness borderThickness = {unknown})	C#
 	Avalonia.Controls.dll!Avalonia.Controls.Presenters.ContentPresenter.MeasureOverride(Avalonia.Size availableSize = {unknown})	C#
 	Avalonia.Base.dll!Avalonia.Layout.Layoutable.MeasureCore(Avalonia.Size availableSize = {unknown})	C#
 	Avalonia.Base.dll!Avalonia.Layout.Layoutable.Measure(Avalonia.Size availableSize = {unknown})	C#
 	Avalonia.Base.dll!Avalonia.Layout.LayoutHelper.MeasureChild(Avalonia.Layout.ILayoutable control = {unknown}, Avalonia.Size availableSize = {unknown}, Avalonia.Thickness padding = {unknown})	C#
 	Avalonia.Controls.dll!Avalonia.Controls.Primitives.VisualLayerManager.MeasureOverride(Avalonia.Size availableSize = {unknown})	C#
 	Avalonia.Base.dll!Avalonia.Layout.Layoutable.MeasureCore(Avalonia.Size availableSize = {unknown})	C#
 	Avalonia.Base.dll!Avalonia.Layout.Layoutable.Measure(Avalonia.Size availableSize = {unknown})	C#
 	Avalonia.Base.dll!Avalonia.Layout.Layoutable.MeasureOverride(Avalonia.Size availableSize = {unknown})	C#
 	Avalonia.Base.dll!Avalonia.Layout.Layoutable.MeasureCore(Avalonia.Size availableSize = {unknown})	C#
 	Avalonia.Base.dll!Avalonia.Layout.Layoutable.Measure(Avalonia.Size availableSize = {unknown})	C#
 	Avalonia.Base.dll!Avalonia.Layout.Layoutable.MeasureOverride(Avalonia.Size availableSize = {unknown})	C#
 	Avalonia.Controls.dll!Avalonia.Controls.Window.MeasureOverride(Avalonia.Size availableSize = {unknown})	C#
 	Avalonia.Controls.dll!Avalonia.Controls.WindowBase.MeasureCore(Avalonia.Size availableSize = {unknown})	C#
 	Avalonia.Base.dll!Avalonia.Layout.Layoutable.Measure(Avalonia.Size availableSize = {unknown})	C#
 	Avalonia.Base.dll!Avalonia.Layout.LayoutManager.Measure(Avalonia.Layout.ILayoutable control = {unknown})	C#
 	Avalonia.Base.dll!Avalonia.Layout.LayoutManager.ExecuteInitialLayoutPass()	C#
 	Avalonia.Controls.dll!Avalonia.Controls.Window.ShowDialog(Avalonia.Controls.Window owner = {unknown})	C#
>	treedatagrid-bug.dll!<Dialog>d__1.MoveNext()	C#
 	System.Private.CoreLib.dll!System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start(TStateMachine stateMachine = {unknown})	C#
 	System.Private.CoreLib.dll!System.Runtime.CompilerServices.AsyncTaskMethodBuilder.Start(TStateMachine stateMachine = {unknown})	C#
 	treedatagrid-bug.dll!treedatagrid_bug.Views.MainWindow.Dialog(ReactiveUI.InteractionContext<string,string> Interaction = {unknown})	C#
 	ReactiveUI.dll!<>c__DisplayClass5_0.AnonymousMethod(ReactiveUI.InteractionContext interaction = {unknown})	C#
 	ReactiveUI.dll!<>c__DisplayClass6_0`1.<RegisterHandler>g__ContentHandler|0(ReactiveUI.InteractionContext context = {unknown})	C#
 	System.Reactive.dll!_.Run()	C#
 	System.Reactive.dll!System.Reactive.Producer`2.SubscribeRaw(System.IObserver observer = {unknown}, bool enableSafeguard = {unknown})	C#
 	System.Reactive.dll!ConcatManyOuterObserver.Drain()	C#
 	System.Reactive.dll!System.Reactive.ObserveOnObserverNew`1.DrainStep(System.Collections.Concurrent.ConcurrentQueue q = {unknown})	C#
 	System.Reactive.dll!System.Reactive.ObserveOnObserverNew`1.DrainShortRunning(System.Reactive.Concurrency.IScheduler recursiveScheduler = {unknown})	C#
 	System.Reactive.dll!Trampoline.Run(System.Reactive.Concurrency.SchedulerQueue<System.TimeSpan> queue = {unknown})	C#
 	System.Reactive.dll!System.Reactive.Concurrency.CurrentThreadScheduler.Schedule(TState state = {unknown}, System.TimeSpan dueTime = {unknown}, System.Func action = {unknown})	C#
 	System.Reactive.dll!System.Reactive.Concurrency.Scheduler.ScheduleAction(System.Reactive.Concurrency.IScheduler scheduler = {unknown}, TState state = {unknown}, System.Action action = {unknown})	C#
 	System.Reactive.dll!System.Reactive.Producer`2.SubscribeRaw(System.IObserver observer = {unknown}, bool enableSafeguard = {unknown})	C#
 	System.Reactive.dll!System.Reactive.Linq.QueryLanguage.RunAsync(System.IObservable source = {unknown}, System.Threading.CancellationToken cancellationToken = {unknown})	C#
 	System.Reactive.dll!System.Reactive.Linq.QueryLanguage.GetAwaiter(System.IObservable source = {unknown})	C#
 	treedatagrid-bug.dll!<<-ctor>b__12_0>d.MoveNext()	C#
 	System.Private.CoreLib.dll!System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start(TStateMachine stateMachine = {unknown})	C#
 	System.Private.CoreLib.dll!System.Runtime.CompilerServices.AsyncTaskMethodBuilder.Start(TStateMachine stateMachine = {unknown})	C#
 	treedatagrid-bug.dll!treedatagrid_bug.ViewModels.MainWindowViewModel.AnonymousMethod()	C#
 	ReactiveUI.dll!<>c__DisplayClass9_0.AnonymousMethod()	C#
 	ReactiveUI.dll!ReactiveUI.ReactiveCommand`2.Execute(TParam parameter = {unknown})	C#
 	ReactiveUI.dll!ReactiveUI.ReactiveCommandBase`2.ICommandExecute([An error occurred while fetching the data for this event])	C#
 	Avalonia.Controls.dll!Avalonia.Controls.Button.OnClick()	C#
 	Avalonia.Controls.dll!Avalonia.Controls.Button.OnPointerReleased(Avalonia.Input.PointerReleasedEventArgs e = {unknown})	C#
 	System.Reactive.dll!System.Reactive.Subjects.Subject`1.OnNext(T value = {unknown})	C#
 	Avalonia.Base.dll!Avalonia.Interactivity.EventRoute.RaiseEventImpl(Avalonia.Interactivity.RoutedEventArgs e = {unknown})	C#
 	Avalonia.Base.dll!Avalonia.Interactivity.EventRoute.RaiseEvent(Avalonia.Interactivity.IInteractive source = {unknown}, Avalonia.Interactivity.RoutedEventArgs e = {unknown})	C#
 	Avalonia.Base.dll!Avalonia.Interactivity.Interactive.RaiseEvent(Avalonia.Interactivity.RoutedEventArgs e = {unknown})	C#
 	Avalonia.Base.dll!Avalonia.Input.MouseDevice.MouseUp(Avalonia.Input.IMouseDevice device = {unknown}, ulong timestamp = {unknown}, Avalonia.Input.IInputRoot root = {unknown}, Avalonia.Point p = {unknown}, Avalonia.Input.PointerPointProperties props = {unknown}, Avalonia.Input.KeyModifiers inputModifiers = {unknown}, Avalonia.Input.IInputElement hitTest = {unknown})	C#
 	Avalonia.Base.dll!Avalonia.Input.MouseDevice.ProcessRawEvent(Avalonia.Input.Raw.RawPointerEventArgs e = {unknown})	C#
 	Avalonia.Base.dll!Avalonia.Input.InputManager.ProcessInput(Avalonia.Input.Raw.RawInputEventArgs e = {unknown})	C#
 	Avalonia.Controls.dll!Avalonia.Controls.TopLevel.HandleInput(Avalonia.Input.Raw.RawInputEventArgs e = {unknown})	C#
 	Avalonia.Win32.dll!Avalonia.Win32.WindowImpl.AppWndProc(System.IntPtr hWnd = {unknown}, uint msg = {unknown}, System.IntPtr wParam = {unknown}, System.IntPtr lParam = {unknown})	C#
 	Avalonia.Win32.dll!Avalonia.Win32.WindowImpl.WndProc(System.IntPtr hWnd = {unknown}, uint msg = {unknown}, System.IntPtr wParam = {unknown}, System.IntPtr lParam = {unknown})	C#
 	Avalonia.Win32.dll!Avalonia.Win32.Win32Platform.RunLoop(System.Threading.CancellationToken cancellationToken = {unknown})	C#
 	Avalonia.Base.dll!Avalonia.Threading.Dispatcher.MainLoop(System.Threading.CancellationToken cancellationToken = {unknown})	C#
 	Avalonia.Controls.dll!Avalonia.Controls.ApplicationLifetimes.ClassicDesktopStyleApplicationLifetime.Start(string[] args = {unknown})	C#
 	treedatagrid-bug.dll!treedatagrid_bug.Program.Main(string[] args = {unknown})	C#

Desktop:

  • OS: Windows
  • Version Avalonia 11.0.0-preview2 / Avalonia.Controls.TreeDataGrid 11.0.0-preview1

Redraw cells on property change

Hello, i'm trying out TreeDataGrid - Flat view and would like to achieve to update UI when property is changed. Reading the docs, this should work.

Currently I need to scroll out and back in the row to get updated content.

This is same in TreeDataGridDemo sample, if you add code below to To CountriesPageViewModel.cs

            Task.Run(async () =>
            {
                for (var ii = 0; ii < 10; ii++)
                {
                    _data[0].Population = ii * 1000;
                    await Task.Delay(1000);
                }
            });

Is there any way to at least force redraw?

Thank you

Is there a way to asynchronously populate row children before (or during) expanding?

I am looking at files page sample (https://github.com/AvaloniaUI/Avalonia.Controls.TreeDataGrid/blob/master/samples/TreeDataGridDemo/ViewModels/FilesPageViewModel.cs) which loads row children on access (https://github.com/AvaloniaUI/Avalonia.Controls.TreeDataGrid/blob/master/samples/TreeDataGridDemo/Models/FileTreeNodeModel.cs#L80), however all of it is synchronous I/O access.

Is there a way maybe pre-load data so that .Children access would get it from cache? By the looks of it, as soon as you expand a row, everything in chain expects data to be ready immediately, so there is no point in time one could load data asynchronously.

Unused parameter - `TypedBinding<TIn, TOut>.Instance(TIn?, BindingMode)`

The parameter mode seems to be redundant here:

public TypedBindingExpression<TIn, TOut> Instance(TIn? source, BindingMode mode = BindingMode.OneWay)
{
return Instance(ObservableEx.SingleValue(source), mode, FallbackValue);
}

The only calls seem to be these, which keep the default value as BindingMode.OneWay:

protected TypedBindingExpression<TModel, TValue?> CreateBindingExpression(TModel model)
{
return Binding.Instance(model);
}

_subscription = _hasChildrenSelector?.Instance(_model).Subscribe(this);

Also, as this is a single instance binding, I guess it could be BindingMode.OneTime? Am I missing something?

Wrong behavior with horizontal scrolling

There are two issues when performing horizontal scrolling:

1. Messy label positions

Steps to reproduce:

  1. Open the Files example (ProControlsDemo project)
  2. Expand several nodes to have some more complex layout (and make some files visible)
  3. Resize the window horizontally to make the horizontal scrollbar to appear.
  4. Now move the horizontal scroll to the right.

The columns are not correctly aligned:
image

2. Wrong scroll metrics when using GridUnitType.Pixel

Using GridUnitType.Pixel instead GridUnitType.Star for the columns in the CountryPageViewModel.cs makes the TreeDataGrid horizontal scrollbar to not behave correctly.

I made the following change:

new TextColumn<Country, string>("Country", x => x.Name, (r, v) => r.Name = v, new GridLength(250, GridUnitType.Pixel)),
new TextColumn<Country, string>("Region", x => x.Region, new GridLength(150, GridUnitType.Pixel)),
new TextColumn<Country, int>("Population", x => x.Population, new GridLength(300, GridUnitType.Pixel)),
new TextColumn<Country, int>("Area", x => x.Area, new GridLength(200, GridUnitType.Pixel)),
new TextColumn<Country, int>("GDP", x => x.GDP, new GridLength(150, GridUnitType.Pixel)),

Then the horizontal scroll doesn't work as expected:
Animation

3. The files example cannot use GridColumnType.Pixel

the countries example works as expected, but the files example donโ€™t. If you use GridColumnType.Pixel in this sample, you get the following exception:
image

Is there data virtualization technology in TreeDataGrid?

I am using the TreeDataGrid custom template now, and it feels very stuck. Is there any way to optimize this stuck? In addition, if the icon of the expand/collapse button on the left is hidden, I have a custom expand button, thank you
ๅ›พ็‰‡

Index out of range when filtering the TreeDataGrid

When applying a filter and changing the items source, the TreeDataGrid throws an exception because it's accessing an index out of range in the HierarchicalRow.cs, member _rows:

System.ArgumentOutOfRangeException
  HResult=0x80131502
  Message=Index was out of range. Must be non-negative and less than the size of the collection. (Parameter 'index')
  Source=System.Private.CoreLib
  StackTrace:
   at System.ThrowHelper.ThrowArgumentOutOfRange_IndexException()
   at System.Collections.Generic.List`1.get_Item(Int32 index)
   at Avalonia.Controls.Models.TreeDataGrid.HierarchicalRows`1.System.Collections.Generic.IReadOnlyList<Avalonia.Controls.Models.TreeDataGrid.IRow>.get_Item(Int32 index) in C:\wks\code\01plastic\test\avalonia-test\Avalonia.Controls.TreeDataGrid\Models\TreeDataGrid\HierarchicalRows.cs:line 36

Avalonia.Controls.TreeDataGrid.dll!Avalonia.Controls.Models.TreeDataGrid.HierarchicalRows<Codice.Utils.ITreeViewNode>.System.Collections.Generic.IReadOnlyList<Avalonia.Controls.Models.TreeDataGrid.IRow>.get_Item(int index) Line 36	Avalonia.Controls.TreeDataGrid.dll!Avalonia.Controls.Primitives.TreeDataGridPresenterBase<Avalonia.Controls.Models.TreeDataGrid.IRow>.GetRecycledOrCreateElement(int index) Line 332	C# 	
Avalonia.Controls.TreeDataGrid.dll!Avalonia.Controls.Primitives.TreeDataGridPresenterBase<Avalonia.Controls.Models.TreeDataGrid.IRow>.GetOrCreateElement(int index) Line 306	C# 	
Avalonia.Controls.TreeDataGrid.dll!Avalonia.Controls.Primitives.TreeDataGridPresenterBase<Avalonia.Controls.Models.TreeDataGrid.IRow>.GenerateElements(Avalonia.Size availableSize, ref Avalonia.Controls.Primitives.TreeDataGridPresenterBase<Avalonia.Controls.Models.TreeDataGrid.IRow>.MeasureViewport viewport) Line 206	C# 	
Avalonia.Controls.TreeDataGrid.dll!Avalonia.Controls.Primitives.TreeDataGridPresenterBase<Avalonia.Controls.Models.TreeDataGrid.IRow>.MeasureOverride(Avalonia.Size availableSize) Line 177	C#
Avalonia.Controls.TreeDataGrid.dll!Avalonia.Controls.Primitives.TreeDataGridRowsPresenter.MeasureOverride(Avalonia.Size availableSize) Line 89	C#
[External Code]	
plastic.dll!PlasticAvalonia.Program.Main(string[] args) Line 35	C#

Checkout the following video to get more details about the issue here:
https://www.loom.com/share/b5d3f3dab8e844cda3edcb3725be9e78

TreeDataGrid does not update when model properties change

Describe the bug
Given an underlying model that implements INotifyPropertyChanged, the TreeDataGrid doesn't update when the model is updated.

To Reproduce

**For convenience, I've create a repo ready to test the issue:
https://github.com/SuperJMN-Tutorials/TreeDataGrid-Out-Of-Sync

If you want to do it yourself:

  1. Create a new MVVM application.
  2. Add the TreeDataGrid package.
  3. Add this code to MainViewModel.
public class MainWindowViewModel : ViewModelBase
{
    public MainWindowViewModel()
    {
        var collection = new ObservableCollection<Model>();
        var model = new Model("Hello!");
        collection.Add(model);
        Source = new FlatTreeDataGridSource<Model>(collection)
        {
            Columns =
            {
                new TextColumn<Model, string>("Text", x => x.Text),
            }
        };

        Observable.Timer(TimeSpan.FromSeconds(2))
            .ObserveOn(RxApp.MainThreadScheduler)
            .Subscribe(_ => model.Text = "How are you?");
    }

    public FlatTreeDataGridSource<Model> Source { get; }
}

public class Model : ViewModelBase
{
    private string text;

    public Model(string text)
    {
        Text = text;
    }

    public string Text
    {
        get => text;
        set => this.RaiseAndSetIfChanged(ref text, value);
    }
}
  1. Add this code to MainWindow.axaml:
 <TreeDataGrid Source="{Binding Source}" />
  1. Run the project.

Expected behavior
After 2 seconds, the data in the DataGrid should display "How are you?". However, it shows the initial text "Hello".

NOTES
Interestingly enough, the TreeDataGrid starts to behave correctly when you click the column header. It seems that sorting a column makes it update.

Desktop (please complete the following information):

  • OS: Windows 11

Additional context
Avalonia 0.10.18.

Replacing source in TreeDataGrid makes UI blank

Adding new data source to an initialized TreeDataGrid makes it completely blank. The data only becomes visible after a short scrolling. Calling treeDataGrid.InvalidateVisual() doesn't help.

Screen.Recording.2022-02-01.at.14.42.12.mov

Steps to reproduce:

.xaml

<Window xmlns="https://github.com/avaloniaui"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        x:Class="AvaloniaTest.MainWindow"
        Title="AvaloniaTest">
      <DockPanel>
        <Button DockPanel.Dock="Bottom" Click="PopulateClick">Populate</Button>
        <TreeDataGrid Name="treeDataGrid"/>
      </DockPanel>
</Window>

.cs

using System;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Models.TreeDataGrid;
using Avalonia.Interactivity;
using Avalonia.Markup.Xaml;

namespace AvaloniaTest;

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
#if DEBUG
        this.AttachDevTools();
#endif
    }

    private void InitializeComponent()
    {
        AvaloniaXamlLoader.Load(this);
    }

    public void PopulateClick(object sender, RoutedEventArgs e)
    {
        var treeDataGrid = this.FindControl<TreeDataGrid>("treeDataGrid");

        var rootCount = 100;
        var items = new Item[rootCount];
        for (var i = 0; i < rootCount; i += 1)
        {
            items[i] = new Item($"Item {i} {DateTime.UtcNow.Ticks}", null);
        }

        var source = new HierarchicalTreeDataGridSource<Item>(items)
        {
            Columns =
            {
                new HierarchicalExpanderColumn<Item>(
                    new TextColumn<Item, string>(
                        "Title",
                        x => x.Title,
                        new GridLength(1, GridUnitType.Star)
                    ),
                    x => x.Children,
                    x => x.Children != null
                )
            }
        };
        treeDataGrid.Source = source;
    }
}

public class Item
{
    public Item[]? Children { get; }
    public string Title { get; }

    public Item(string title, Item[]? children = null)
    {
        Title = title;
        Children = children;
    }
}

TreeDataGrid vertical scroll is reset when scrolling horizontally

Describe the bug
TreeDataGrid's vertical scroll is reset when you scroll horizontally.

To Reproduce
Steps to reproduce the behavior:

  1. Create a TreeDataGrid with enough content to scroll both vertically and horizontally.
  2. Go to the vertical scrollbar and scroll down
  3. Scroll horizontally
  4. See how the vertical scroll is reset

Expected behavior
The vertical scroll should not change.

Video

AvaloniaApplication23_ikjtS0JpHK.mp4

Desktop (please complete the following information):

  • OS: Windows 11
  • Versions:
  • TreeDataGrid 0.10.10
  • Avalonia 0.10.18

Collapse buttons disappear after expanding items programmatically

I couldn't find a way to expand items programmatically. For me it makes some of the collapse buttons disappear.

Screen.Recording.2022-02-02.at.16.40.08.mov

I managed to distill the problem as the short example:

<Window xmlns="https://github.com/avaloniaui"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        x:Class="AvaloniaTest.MainWindow"
        Title="AvaloniaTest">
      <DockPanel>
        <Button Name="refreshButton" DockPanel.Dock="Bottom" Click="RefreshClick">Refresh</Button>
        <TreeDataGrid Name="treeDataGrid" />
      </DockPanel>
</Window>
    public partial class MainWindow : Window
    {
        private AvaloniaList<MutableItem> _items = new AvaloniaList<MutableItem>();
        private HierarchicalTreeDataGridSource<MutableItem> _source;
        public MainWindow()
        {
            InitializeComponent();

            _source = new HierarchicalTreeDataGridSource<MutableItem>(_items)
            {
                Columns =
                {
                    new HierarchicalExpanderColumn<MutableItem>(
                        new TextColumn<MutableItem, string>(
                            "Title",
                            x => x.Title,
                            new GridLength(1, GridUnitType.Star)
                            ),
                        x => x.Children,
                        x => x.Children != null
                    )
                }
            };

            _source.RowSelection!.SingleSelect = false;
            var itemsTreeDataGrid = this.FindControl<TreeDataGrid>("treeDataGrid");
            itemsTreeDataGrid.Source = _source;
            RefreshButton();
        }

        private void InitializeComponent()
        {
            AvaloniaXamlLoader.Load(this);
        }

        private void RefreshButton()
        {
            this.FindControl<Button>("refreshButton").Content = _expand ? "Refresh and expand" : "Refresh";
        }

        private bool _expand = false;
        public void RefreshClick(object sender, RoutedEventArgs e)
        {
            _items.Clear();
            var folder = new MutableItem("Root", new AvaloniaList<MutableItem>());
            _items.Add(folder);

            if (_expand)
            {
                // ๐Ÿ”ด bug: the collapse button disappears
                var folderIndexPath = new IndexPath(0);
                _source.Expand(folderIndexPath);
            }
            folder.Children.Add(new MutableItem("Subfolder1", new AvaloniaList<MutableItem>()));

            _expand = !_expand;
            RefreshButton();
        }
    }

    public class MutableItem
    {
        public AvaloniaList<MutableItem>? Children { get; }
        public string Title { get; }

        public MutableItem(string title, AvaloniaList<MutableItem>? children = null)
        {
            Title = title;
            Children = children;
        }
    }

Question: How to collapse/expand all nodes

Hi,
Let's say my viewmodel don't have some kind of IsEpanded property, but I want to ask the DataTreeGrid to expand / collapse all nodes. How would I do that ?
I couldn't see any entry point but Expand(rowIndex) or Collapse(rowIndex).

Thanks for your help.

ShowColumnHeaders=false doesn't work if called before Windows.Initialized()

I noticed that hiding columns header before the Window.Initialized() event breaks the control refresh and leaves it blank.

Screen.Recording.2022-02-02.at.11.18.43.mov

There are two ways to reproduce that:

<TreeDataGrid Name="treeDataGrid" ShowColumnHeaders="False"/> <!--๐Ÿ”ด doesn't work-->

or

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        var itemsTreeDataGrid = this.FindControl<TreeDataGrid>("treeDataGrid");
        itemsTreeDataGrid.ShowColumnHeaders = false; // ๐Ÿ”ด doesn't work
    }
...
}

However, the following works fine:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        this.Initialized += (s, e) => {
            var itemsTreeDataGrid = this.FindControl<TreeDataGrid>("treeDataGrid");
            itemsTreeDataGrid.ShowColumnHeaders = false; // ๐ŸŸข works fine
        };
    }
}

TemplateColumn in hierarchical model - rendering/scrolling issue

Problem description
Watch wideo
After 15 seconds problem starts. 23s - some data are invisible

TreeDataGridDemo.mp4

Steps to reproduce

HierarchicalTreeDataGrid with many (>200) rows and TemplateColumn is not first one. File example is fine to reporduce with changed column order.

                Columns =
                {
                    
                    new HierarchicalExpanderColumn<FileTreeNodeModel>(
                        new TemplateColumn<FileTreeNodeModel>(
                            "Name",
                            new FuncDataTemplate<FileTreeNodeModel>(FileNameTemplate, true),
                            new GridLength(1, GridUnitType.Star),
                            new ColumnOptions<FileTreeNodeModel>
                            {
                                CompareAscending = FileTreeNodeModel.SortAscending(x => x.Name),
                                CompareDescending = FileTreeNodeModel.SortDescending(x => x.Name),
                            }),
                        x => x.Children,
                        x => x.IsDirectory,
                        x => x.IsExpanded),
                    new TemplateColumn<FileTreeNodeModel>(
                        null,
                        new FuncDataTemplate<FileTreeNodeModel>(FileCheckTemplate, true),
                        options: new ColumnOptions<FileTreeNodeModel>
                        {
                            CanUserResizeColumn = false,
                        }),
                    new TextColumn<FileTreeNodeModel, long?>(
                        "Size",
                        x => x.Size,
                        options: new TextColumnOptions<FileTreeNodeModel>
                        {
                            CompareAscending = FileTreeNodeModel.SortAscending(x => x.Size),
                            CompareDescending = FileTreeNodeModel.SortDescending(x => x.Size),
                        }),
                    new TextColumn<FileTreeNodeModel, DateTimeOffset?>(
                        "Modified",
                        x => x.Modified,
                        options: new TextColumnOptions<FileTreeNodeModel>
                        {
                            CompareAscending = FileTreeNodeModel.SortAscending(x => x.Modified),
                            CompareDescending = FileTreeNodeModel.SortDescending(x => x.Modified),
                        })
                }

Expand some nodes to make visible > 200 rows. Try to scroll to end (using mouse and scrollbar) + click mouse.

More info

  • additional "fool" check box as first column = issue not occurs..
                Columns =
                {
                    new TemplateColumn<FileTreeNodeModel>(
                        "Fool",
                        new FuncDataTemplate<FileTreeNodeModel>((a,e) => new CheckBox())
                        ),
                    new HierarchicalExpanderColumn<FileTreeNodeModel>(
                        new TemplateColumn<FileTreeNodeModel>(
                            "Name",
                            new FuncDataTemplate<FileTreeNodeModel>(FileNameTemplate, true),
                            new GridLength(1, GridUnitType.Star),
                            new ColumnOptions<FileTreeNodeModel>
                            {
                                CompareAscending = FileTreeNodeModel.SortAscending(x => x.Name),
                                CompareDescending = FileTreeNodeModel.SortDescending(x => x.Name),
                            }),
                        x => x.Children,
                        x => x.IsDirectory,
                        x => x.IsExpanded),
                    new TemplateColumn<FileTreeNodeModel>(
                        null,
                        new FuncDataTemplate<FileTreeNodeModel>(FileCheckTemplate, true),
                        options: new ColumnOptions<FileTreeNodeModel>
                        {
                            CanUserResizeColumn = false,
                        }),
                    new TextColumn<FileTreeNodeModel, long?>(
                        "Size",
                        x => x.Size,
                        options: new TextColumnOptions<FileTreeNodeModel>
                        {
                            CompareAscending = FileTreeNodeModel.SortAscending(x => x.Size),
                            CompareDescending = FileTreeNodeModel.SortDescending(x => x.Size),
                        }),
                    new TextColumn<FileTreeNodeModel, DateTimeOffset?>(
                        "Modified",
                        x => x.Modified,
                        options: new TextColumnOptions<FileTreeNodeModel>
                        {
                            CompareAscending = FileTreeNodeModel.SortAscending(x => x.Modified),
                            CompareDescending = FileTreeNodeModel.SortDescending(x => x.Modified),
                        })
                }

Text cell edit mode doesn't update model

Bug

Changing a value in a text cell doesn't call the setter.

Proposed fixes

I think DataContext should be replaced with Model in the following lines:

However, this is not enough, as TextCell.Value is never updated, so EndEdit always fails. I think that some kind of binding has to be set up on realize, i.e. here:

public override void Realize(IElementFactory factory, ICell model, int columnIndex, int rowIndex)
{
_canEdit = model.CanEdit;
Value = model.Value?.ToString();
TextTrimming = (model as ITextCell)?.TextTrimming ?? TextTrimming.CharacterEllipsis;
base.Realize(factory, model, columnIndex, rowIndex);
}

Could someone with more experience in this codebase please help me fixing this?

P0: Hang when closing modal dialogs in Linux

Closing a modal dialog makes the application freeze. But it seems to be random, so maybe it happens after closing the first dialog or after the 15th.
We could reproduce it in a simple app (shared it in slack).

Alternation background for rows

TreeDataGrid should support alternated rows as DataGrid. Perhaps, it can be done for selectors for nth element as it was discussed in Slack with Luis.

HasChildren is only evaluated once

The hasChildrenSelector in HierarchicalExpanderColumn is only evaluated once. This means that, if the children collection is modified, the selector should be re-evaluated.

Repro

I've prepared a minimal repro HERE.

Run it and you will see how the 2 TreeDataGrids behave differently even though they're using the same tree (same nodes).

TreeDataGridExpandBug_jY7ER5C7s0.mp4

Please, notice that if you run the sample and click the expand button before the root has any children, it won't be expandable either!

Manual repro:

In case you want to warm up your hands, you can create your own repro with the steps below:

  1. Inside a ViewModel's constructor, create a TreeDataGrid with a root node and let its children be inside an ObservableCollection.
  2. Create a Source of type HierarchicalTreeDataGridSource.
  3. Create a HierarchicalExpanderColumn where the hasChildSelector is set to node.Children.Any(). Put a breakpoint inside this lambda expression.
  4. Don't add any children in the root node.
  5. Put code that will add children to the collection AFTER the TreeDataGrid is displayed on the screen. For example, a Button that will add children when clicked.

Result: If you add children after the TreeDataGrid is initialized and shown, the breakpoint won't be hit, and the root node will never be expandable (the little expander won't show)

Expected: The breakpoint should be hit and the "has children" condition should be re-evaluated.

[Feature request] Scroll into View

Request

Provide a way to bring a given item into view.

Why?

When we need to highlight an item, E. g. a search feature, we'd need to bring the item into view so the user can locate the item easily. This will involve scrolling to the desired item.

This is intrinsically complex due to the nature of the TreeDataGrid which allows hierarchies. Bringing a model into view would imply to know which parents to expand in the hierarchy.

cc @grokys just in case you know an easy way to do this.

Servicing state of this project

We accept issues and pull requests but we answer and review only pull requests and issues that are created by our customers. It's a quite big project and servicing all issues and pull requests will require more time than we have. But feel free to open issues and pull requests because they may be useful for us!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.