Skip to content

Commit e3b5ec8

Browse files
committed
2 parents abb13f0 + b0245db commit e3b5ec8

File tree

12 files changed

+402
-29
lines changed

12 files changed

+402
-29
lines changed

src/BootstrapBlazor.Server/Components/Samples/Table/TablesFilter.razor.cs

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -64,13 +64,7 @@ private Task<QueryData<Foo>> OnQueryAsync(QueryPageOptions options)
6464
isSorted = true;
6565
}
6666

67-
// 此段代码可不写,组件内部自行处理
68-
if (options.SortName == nameof(Foo.DateTime))
69-
{
70-
items = items.Sort(options.SortList);
71-
isSorted = true;
72-
}
73-
else if (!string.IsNullOrEmpty(options.SortName))
67+
if (!string.IsNullOrEmpty(options.SortName))
7468
{
7569
// 外部未进行排序,内部自动进行排序处理
7670
items = items.Sort(options.SortName, options.SortOrder);

src/BootstrapBlazor.Server/Components/Samples/TreeViews.razor

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,14 @@
5252
<ConsoleLogger @ref="Logger2"></ConsoleLogger>
5353
</DemoBlock>
5454

55+
<DemoBlock Title="@Localizer["TreeViewDraggableTitle"]"
56+
Introduction="@Localizer["TreeViewDraggableIntro"]"
57+
Name="TreeDraggable">
58+
<section ignore>@((MarkupString)Localizer["TreeViewDraggableDescription"].Value)</section>
59+
<TreeView Items="@DraggableItems" AllowDrag="true" OnDragItemEndAsync="OnDragItemEndAsync">
60+
</TreeView>
61+
</DemoBlock>
62+
5563
<DemoBlock Title="@Localizer["TreeViewTreeDisableTitle"]"
5664
Introduction="@Localizer["TreeViewTreeDisableIntro"]"
5765
Name="TreeDisable">

src/BootstrapBlazor.Server/Components/Samples/TreeViews.razor.cs

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
// See the LICENSE file in the project root for more information.
44
// Maintainer: Argo Zhang([email protected]) Website: https://www.blazor.zone
55

6+
using DocumentFormat.OpenXml.Spreadsheet;
7+
68
namespace BootstrapBlazor.Server.Components.Samples;
79

810
/// <summary>
@@ -33,6 +35,8 @@ public sealed partial class TreeViews
3335

3436
private bool AutoCheckParent { get; set; }
3537

38+
private List<TreeViewItem<TreeFoo>> DraggableItems { get; set; } = [];
39+
3640
private List<TreeViewItem<TreeFoo>> DisabledItems { get; } = GetDisabledItems();
3741

3842
private List<TreeViewItem<TreeFoo>>? AccordionItems { get; } = TreeFoo.GetAccordionItems();
@@ -77,12 +81,61 @@ public sealed partial class TreeViews
7781

7882
private string? _selectedValue;
7983

84+
/// <summary>
85+
/// <inheritdoc/>
86+
/// </summary>
87+
protected override void OnInitialized()
88+
{
89+
base.OnInitialized();
90+
91+
var items = GetDraggableItems();
92+
DraggableItems = TreeFoo.CascadingTree(items);
93+
DraggableItems[0].IsExpand = true;
94+
if (DraggableItems.Count > 1)
95+
{
96+
DraggableItems[1].IsExpand = true;
97+
}
98+
if (DraggableItems.Count > 2)
99+
{
100+
DraggableItems[2].IsExpand = true;
101+
}
102+
}
103+
80104
private Task OnTreeItemClick(TreeViewItem<TreeFoo> item)
81105
{
82106
Logger1.Log($"TreeItem: {item.Text} clicked");
83107
return Task.CompletedTask;
84108
}
85109

110+
private Task OnDragItemEndAsync(TreeViewDragContext<TreeFoo> context)
111+
{
112+
// 本例是使用静态数据模拟数据库操作的,实战中应该是更新节点的父级 Id 可能还需要更改排序字段等信息,然后重构 TreeView 数据源即可
113+
// 根据 context 处理原始数据
114+
var items = GetDraggableItems();
115+
var source = items.Find(i => i.Id == context.Source.Value.Id);
116+
if (source != null)
117+
{
118+
var target = items.Find(i => i.Id == context.Target.Value.Id);
119+
if (target != null)
120+
{
121+
source.ParentId = context.IsChildren ? target.Id : target.ParentId;
122+
}
123+
}
124+
DraggableItems = TreeFoo.CascadingTree(items);
125+
DraggableItems[0].IsExpand = true;
126+
if (DraggableItems.Count > 1)
127+
{
128+
DraggableItems[1].IsExpand = true;
129+
}
130+
if (DraggableItems.Count > 2)
131+
{
132+
DraggableItems[2].IsExpand = true;
133+
}
134+
135+
StateHasChanged();
136+
return Task.CompletedTask;
137+
}
138+
86139
private Task OnTreeItemKeyboardClick(TreeViewItem<TreeFoo> item)
87140
{
88141
_selectedValue = item.Value.Text;
@@ -122,6 +175,28 @@ private Task OnTreeItemChecked(List<TreeViewItem<TreeFoo>> items)
122175
return Task.CompletedTask;
123176
}
124177

178+
private static List<TreeFoo>? _dragItems = null;
179+
private static List<TreeFoo> GetDraggableItems()
180+
{
181+
_dragItems ??=
182+
[
183+
new() { Text = "Item A", Id = "1", Icon = "fa-solid fa-font-awesome" },
184+
new() { Text = "Item D", Id = "4", ParentId = "1", Icon = "fa-solid fa-font-awesome" },
185+
new() { Text = "Item E", Id = "5", ParentId = "1", Icon = "fa-solid fa-font-awesome" },
186+
187+
new() { Text = "Item B (Drop inside blocked)", Id = "2", Icon = "fa-solid fa-font-awesome" },
188+
new() { Text = "Item F", Id = "6", ParentId = "2", Icon = "fa-solid fa-font-awesome" },
189+
new() { Text = "Item G (Can not move out)", Id = "9", ParentId = "2", Icon = "fa-solid fa-font-awesome" },
190+
191+
new() { Text = "Item C", Id = "3", Icon = "fa-solid fa-font-awesome" },
192+
new() { Text = "Item H", Id = "7", ParentId = "3", Icon = "fa-solid fa-font-awesome" },
193+
new() { Text = "Item I", Id = "8", ParentId = "3", Icon = "fa-solid fa-font-awesome" },
194+
195+
196+
];
197+
return _dragItems;
198+
}
199+
125200
private static List<TreeViewItem<TreeFoo>> GetDisabledItems()
126201
{
127202
var ret = TreeFoo.GetTreeItems();

src/BootstrapBlazor.Server/Locales/en-US.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -676,6 +676,9 @@
676676
"TreeViewCheckboxCheckBoxDisplayText2": "Automatically select parent node",
677677
"TreeViewCheckboxButtonText": "Refresh",
678678
"TreeViewCheckboxAddButtonText": "Add",
679+
"TreeViewDraggableTitle": "Draggable nodes",
680+
"TreeViewDraggableIntro": "Allows nodes to be dragged and dropped in the tree control",
681+
"TreeViewDraggableDescription": "By setting the <code>AllowDrag</code> property, you can drag and drop nodes in the tree control. Use the <code>OnDragItemEndAsync</code> callback delegate to handle the drop event.",
679682
"TreeViewTreeDisableTitle": "Disabled state",
680683
"TreeViewTreeDisableIntro": "Some nodes of the Tree can be set to disabled state",
681684
"TreeViewTreeDisableDescription": "By setting the <code>Disabled</code> property of the data source <code>TreeViewItem</code> object, you can control whether this node can be checked or not. When set to <code>false</code>, it will not affect the node expansion. /shrink function",

src/BootstrapBlazor.Server/Locales/zh-CN.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -676,6 +676,9 @@
676676
"TreeViewCheckboxCheckBoxDisplayText2": "自动选中父节点",
677677
"TreeViewCheckboxButtonText": "刷新",
678678
"TreeViewCheckboxAddButtonText": "追加节点",
679+
"TreeViewDraggableTitle": "可拖拽节点",
680+
"TreeViewDraggableIntro": "使树中的节点可以进行跨层级拖拽操作",
681+
"TreeViewDraggableDescription": "通过设置 <code>AllowDrag</code> 属性开启节点拖拽功能,使用 <code>OnDragItemEndAsync</code> 回调委托方法响应拖拽节点放置事件",
679682
"TreeViewTreeDisableTitle": "禁用状态",
680683
"TreeViewTreeDisableIntro": "可将 Tree 的某些节点设置为禁用状态",
681684
"TreeViewTreeDisableDescription": "通过设置数据源 <code>TreeViewItem</code> 对象的 <code>Disabled</code> 属性,来控制此节点是否可以进行勾选动作,设置为 <code>false</code> 时不影响节点展开/收缩功能",

src/BootstrapBlazor/BootstrapBlazor.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<Project Sdk="Microsoft.NET.Sdk.Razor">
22

33
<PropertyGroup>
4-
<Version>9.8.1-beta02</Version>
4+
<Version>9.8.1-beta03</Version>
55
</PropertyGroup>
66

77
<ItemGroup>

src/BootstrapBlazor/Components/TreeView/TreeView.razor.cs

Lines changed: 62 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -256,20 +256,6 @@ public partial class TreeView<TItem> : IModelEqualityComparer<TItem>
256256
[Parameter]
257257
public Func<TItem, string?, Task<bool>>? OnUpdateCallbackAsync { get; set; }
258258

259-
[NotNull]
260-
private string? NotSetOnTreeExpandErrorMessage { get; set; }
261-
262-
[Inject]
263-
[NotNull]
264-
private IStringLocalizer<TreeView<TItem>>? Localizer { get; set; }
265-
266-
[Inject]
267-
[NotNull]
268-
private IIconTheme? IconTheme { get; set; }
269-
270-
[NotNull]
271-
private TreeNodeCache<TreeViewItem<TItem>, TItem>? _treeNodeStateCache = null;
272-
273259
/// <summary>
274260
/// Gets or sets whether to automatically update child nodes when the node state changes. Default is false.
275261
/// </summary>
@@ -282,12 +268,36 @@ public partial class TreeView<TItem> : IModelEqualityComparer<TItem>
282268
[Parameter]
283269
public bool AutoCheckParent { get; set; }
284270

285-
private string? _searchText;
271+
/// <summary>
272+
/// Gets or sets a value indicating whether drag-and-drop operations are allowed. Default is false
273+
/// </summary>
274+
[Parameter]
275+
public bool AllowDrag { get; set; }
276+
277+
/// <summary>
278+
/// 获得/设置 拖动标签页结束回调方法
279+
/// </summary>
280+
[Parameter]
281+
public Func<TreeViewDragContext<TItem>, Task>? OnDragItemEndAsync { get; set; }
282+
283+
[Inject]
284+
[NotNull]
285+
private IStringLocalizer<TreeView<TItem>>? Localizer { get; set; }
286+
287+
[Inject]
288+
[NotNull]
289+
private IIconTheme? IconTheme { get; set; }
286290

287291
private string? EnableKeyboardString => EnableKeyboard ? "true" : null;
288292

289-
private bool _shouldRender = true;
293+
[NotNull]
294+
private string? NotSetOnTreeExpandErrorMessage { get; set; }
290295

296+
[NotNull]
297+
private TreeNodeCache<TreeViewItem<TItem>, TItem>? _treeNodeStateCache = null;
298+
299+
private string? _searchText;
300+
private bool _shouldRender = true;
291301
private bool _init;
292302

293303
/// <summary>
@@ -368,6 +378,11 @@ protected override async Task OnAfterRenderAsync(bool firstRender)
368378
_keyboardArrowUpDownTrigger = false;
369379
await InvokeVoidAsync("scroll", Id, ScrollIntoViewOptions);
370380
}
381+
382+
if(!firstRender && AllowDrag)
383+
{
384+
await InvokeVoidAsync("resetTreeViewRow", Id);
385+
}
371386
}
372387

373388
/// <summary>
@@ -380,7 +395,13 @@ protected override async Task OnAfterRenderAsync(bool firstRender)
380395
/// <inheritdoc/>
381396
/// </summary>
382397
/// <returns></returns>
383-
protected override Task InvokeInitAsync() => InvokeVoidAsync("init", Id, new { Invoke = Interop, Method = nameof(TriggerKeyDown) });
398+
protected override Task InvokeInitAsync() => InvokeVoidAsync("init", Id, new
399+
{
400+
Invoke = Interop,
401+
Method = nameof(TriggerKeyDown),
402+
AllowDrag,
403+
TriggerDragEnd = nameof(TriggerDragEnd)
404+
});
384405

385406
private bool _keyboardArrowUpDownTrigger;
386407

@@ -408,6 +429,30 @@ public async ValueTask TriggerKeyDown(string key)
408429
}
409430
}
410431

432+
/// <summary>
433+
/// Triggers the end of a drag-and-drop operation within the tree view.
434+
/// </summary>
435+
/// <remarks>This method is invoked via JavaScript interop to signal the completion of a drag-and-drop
436+
/// action. If a handler is assigned to <see cref="OnDragItemEndAsync"/>, it will be invoked with the drag
437+
/// context.</remarks>
438+
/// <param name="originIndex">The zero-based index of the item being dragged from its original position.</param>
439+
/// <param name="currentIndex">The zero-based index of the item's current position after the drag operation.</param>
440+
/// <param name="isChildren">A value indicating whether the drag operation involves child items.</param>
441+
/// <returns></returns>
442+
[JSInvokable]
443+
public async ValueTask TriggerDragEnd(int originIndex, int currentIndex, bool isChildren)
444+
{
445+
if (OnDragItemEndAsync != null)
446+
{
447+
var context = new TreeViewDragContext<TItem>(
448+
source: Rows[originIndex],
449+
target: Rows[currentIndex],
450+
children: isChildren
451+
);
452+
await OnDragItemEndAsync(context);
453+
}
454+
}
455+
411456
/// <summary>
412457
/// Client-side method to query the state of the specified row checkbox, called by JavaScript
413458
/// </summary>

0 commit comments

Comments
 (0)