|
191 | 191 | [Parameter] |
192 | 192 | public Func<TItem, bool>? HasChildrenSelector { get; set; } |
193 | 193 |
|
| 194 | + [Parameter] |
| 195 | + public Func<TItem, bool>? InitiallyExpandedSelector { get; set; } |
| 196 | + |
194 | 197 | [Parameter] |
195 | 198 | public FancyTableTexts? Texts { get; set; } |
196 | 199 |
|
|
349 | 352 | TreeNodeState<TItem> rootNode = BuildNode(item, depth: 0, parent: null, ancestors: []); |
350 | 353 | RootNodes.Add(rootNode); |
351 | 354 | } |
| 355 | + |
| 356 | + RemoveObsoleteExpandedStates(); |
352 | 357 | } |
353 | 358 |
|
354 | 359 | private TreeNodeState<TItem> BuildNode( |
|
366 | 371 | } |
367 | 372 |
|
368 | 373 | List<TItem> orderedChildren = ApplySiblingSort(childItems).ToList(); |
| 374 | + bool hasChildren = HasChildrenSelector?.Invoke(item) ?? orderedChildren.Count > 0; |
| 375 | + bool isExpanded = GetOrInitializeExpandedState(item); |
369 | 376 | TreeNodeState<TItem> node = new() |
370 | 377 | { |
371 | 378 | Item = item, |
372 | 379 | Depth = depth, |
373 | 380 | Parent = parent, |
374 | | - HasChildren = HasChildrenSelector?.Invoke(item) ?? orderedChildren.Count > 0, |
375 | | - IsExpanded = ExpandedStates.TryGetValue(item, out bool isExpanded) && isExpanded, |
| 381 | + HasChildren = hasChildren, |
| 382 | + IsExpanded = hasChildren && isExpanded, |
376 | 383 | Children = [] |
377 | 384 | }; |
378 | 385 |
|
|
504 | 511 |
|
505 | 512 | private void ShowColumn(string key) => HiddenColumns.Remove(key); |
506 | 513 |
|
507 | | - private Task ToggleNodeAsync(TreeNodeState<TItem> node) |
| 514 | + private bool GetOrInitializeExpandedState(TItem item) |
508 | 515 | { |
509 | | - node.IsExpanded = !node.IsExpanded; |
510 | | - if (node.IsExpanded) |
| 516 | + if (ExpandedStates.TryGetValue(item, out bool isExpanded)) |
511 | 517 | { |
512 | | - ExpandedStates[node.Item] = true; |
513 | | - } |
514 | | - else |
515 | | - { |
516 | | - ExpandedStates.Remove(node.Item); |
| 518 | + return isExpanded; |
517 | 519 | } |
518 | 520 |
|
| 521 | + bool initialState = InitiallyExpandedSelector?.Invoke(item) ?? false; |
| 522 | + ExpandedStates[item] = initialState; |
| 523 | + return initialState; |
| 524 | + } |
| 525 | + |
| 526 | + private Task ToggleNodeAsync(TreeNodeState<TItem> node) |
| 527 | + { |
| 528 | + node.IsExpanded = !node.IsExpanded; |
| 529 | + ExpandedStates[node.Item] = node.IsExpanded; |
| 530 | + |
519 | 531 | return Task.CompletedTask; |
520 | 532 | } |
521 | 533 |
|
522 | 534 | public async Task ExpandAllAsync() |
523 | 535 | { |
524 | | - ExpandedStates.Clear(); |
525 | 536 | SetExpandedStateForAllNodes(expanded: true); |
526 | 537 | await InvokeAsync(StateHasChanged); |
527 | 538 | } |
528 | 539 |
|
529 | 540 | public async Task CollapseAllAsync() |
530 | 541 | { |
531 | | - ExpandedStates.Clear(); |
532 | 542 | SetExpandedStateForAllNodes(expanded: false); |
533 | 543 | await InvokeAsync(StateHasChanged); |
534 | 544 | } |
|
639 | 649 | { |
640 | 650 | ExpandedStates[node.Item] = true; |
641 | 651 | } |
| 652 | + else |
| 653 | + { |
| 654 | + ExpandedStates[node.Item] = false; |
| 655 | + } |
642 | 656 | } |
643 | 657 | else |
644 | 658 | { |
645 | 659 | node.IsExpanded = false; |
| 660 | + ExpandedStates[node.Item] = false; |
646 | 661 | } |
647 | 662 |
|
648 | 663 | foreach (TreeNodeState<TItem> child in node.Children) |
|
651 | 666 | } |
652 | 667 | } |
653 | 668 |
|
| 669 | + private void RemoveObsoleteExpandedStates() |
| 670 | + { |
| 671 | + HashSet<TItem> activeItems = []; |
| 672 | + foreach (TreeNodeState<TItem> rootNode in RootNodes) |
| 673 | + { |
| 674 | + CollectNodeItems(rootNode, activeItems); |
| 675 | + } |
| 676 | + |
| 677 | + List<TItem> obsoleteItems = ExpandedStates.Keys.Where(key => !activeItems.Contains(key)).ToList(); |
| 678 | + foreach (TItem obsoleteItem in obsoleteItems) |
| 679 | + { |
| 680 | + ExpandedStates.Remove(obsoleteItem); |
| 681 | + } |
| 682 | + } |
| 683 | + |
| 684 | + private static void CollectNodeItems(TreeNodeState<TItem> node, HashSet<TItem> activeItems) |
| 685 | + { |
| 686 | + activeItems.Add(node.Item); |
| 687 | + |
| 688 | + foreach (TreeNodeState<TItem> child in node.Children) |
| 689 | + { |
| 690 | + CollectNodeItems(child, activeItems); |
| 691 | + } |
| 692 | + } |
| 693 | + |
654 | 694 | private TreeNodeStatistics GetTreeNodeStatistics() |
655 | 695 | { |
656 | 696 | TreeNodeStatistics stats = new(); |
|
0 commit comments