From 6049f1e2074f219602d3839b4f3d1c3a3b3f63d9 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Wed, 12 Mar 2025 13:05:04 +0800 Subject: [PATCH 01/34] =?UTF-8?q?doc:=20=E6=96=87=E6=A1=A3=E6=B3=A8?= =?UTF-8?q?=E9=87=8A=E6=9B=B4=E6=94=B9=E4=B8=BA=E8=8B=B1=E6=96=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/TreeView/TreeView.razor.cs | 181 +++++++----------- 1 file changed, 66 insertions(+), 115 deletions(-) diff --git a/src/BootstrapBlazor/Components/TreeView/TreeView.razor.cs b/src/BootstrapBlazor/Components/TreeView/TreeView.razor.cs index a1b1a7aacd2..954fe08ddaf 100644 --- a/src/BootstrapBlazor/Components/TreeView/TreeView.razor.cs +++ b/src/BootstrapBlazor/Components/TreeView/TreeView.razor.cs @@ -9,41 +9,25 @@ namespace BootstrapBlazor.Components; /// -/// Tree 组件 +/// Tree component /// [CascadingTypeParameter(nameof(TItem))] public partial class TreeView : IModelEqualityComparer { - /// - /// 获得 按钮样式集合 - /// private string? ClassString => CssBuilder.Default("tree-view") .AddClass("is-fixed-search", ShowSearch && IsFixedSearch) .AddClassFromAttributes(AdditionalAttributes) .Build(); - /// - /// 获得 Loading 样式集合 - /// private string? LoadingClassString => CssBuilder.Default("table-loading") .AddClassFromAttributes(AdditionalAttributes) .Build(); - /// - /// 获得/设置 TreeItem 图标 - /// - /// - /// private static string? GetIconClassString(TreeViewItem item) => CssBuilder.Default("tree-icon") .AddClass(item.Icon) .AddClass(item.ExpandIcon, item.IsExpand && !string.IsNullOrEmpty(item.ExpandIcon)) .Build(); - /// - /// 获得/设置 TreeItem 小箭头样式 - /// - /// - /// private string? GetCaretClassString(TreeViewItem item) => CssBuilder.Default("node-icon") .AddClass("visible", item.HasChildren || item.Items.Count > 0) .AddClass(NodeIcon, !item.IsExpand) @@ -69,148 +53,145 @@ public partial class TreeView : IModelEqualityComparer private bool GetItemDisabledState(TreeViewItem item) => item.IsDisabled || IsDisabled; - /// - /// 获得/设置 选中节点 默认 null - /// private TreeViewItem? _activeItem; /// - /// 获得/设置 是否显示正在加载动画 默认为 false + /// Gets or sets whether to show the loading animation. Default is false. /// - [Obsolete("已弃用 直接删除即可;Deprecated Please remove it")] + [Obsolete("Deprecated. Please remove it.")] [ExcludeFromCodeCoverage] public bool IsReset { get; set; } /// - /// 获得/设置 是否禁用整个组件 默认 false + /// Gets or sets whether the tree view is editable. Default is false. + /// + [Parameter] + public bool IsEditable { get; set; } + + /// + /// Gets or sets whether the entire component is disabled. Default is false. /// [Parameter] public bool IsDisabled { get; set; } /// - /// 获得/设置 当节点被禁用时 是否可以进行折叠展开操作 默认 false + /// Gets or sets whether nodes can be expanded or collapsed when the component is disabled. Default is false. /// [Parameter] public bool CanExpandWhenDisabled { get; set; } /// - /// 获得/设置 是否为手风琴效果 默认为 false 虚拟滚动模式下不支持手风琴效果 + /// Gets or sets whether the tree view has accordion behavior. Default is false. Accordion behavior is not supported in virtual scrolling mode. /// [Parameter] public bool IsAccordion { get; set; } /// - /// 获得/设置 是否点击节点时展开或者收缩子项 默认 false + /// Gets or sets whether clicking a node expands or collapses its children. Default is false. /// [Parameter] public bool ClickToggleNode { get; set; } /// - /// 获得/设置 是否点击节点自动切换 Checkbox 状态 默认 false 时生效 + /// Gets or sets whether clicking a node toggles its checkbox state. Default is false. Effective when is true. /// [Parameter] public bool ClickToggleCheck { get; set; } /// - /// 获得/设置 是否显示加载骨架屏 默认 false 不显示 + /// Gets or sets whether to show the loading skeleton. Default is false. /// [Parameter] public bool ShowSkeleton { get; set; } /// - /// 获得/设置 是否显示搜索栏 默认 false 不显示 + /// Gets or sets whether to show the search bar. Default is false. /// [Parameter] public bool ShowSearch { get; set; } /// - /// 获得/设置 是否固定搜索栏 默认 false 不固定 + /// Gets or sets whether the search bar is fixed. Default is false. /// [Parameter] public bool IsFixedSearch { get; set; } /// - /// 获得/设置 是否显示重置搜索栏按钮 默认 true 显示 + /// Gets or sets whether to show the reset search button. Default is true. /// [Parameter] public bool ShowResetSearchButton { get; set; } = true; /// - /// 获得/设置 搜索栏模板 默认 null + /// Gets or sets the search bar template. Default is null. /// [Parameter] public RenderFragment? SearchTemplate { get; set; } /// - /// 获得/设置 搜索栏图标 默认 未设置 使用主题内置图标 + /// Gets or sets the search icon. Default is not set, using the built-in theme icon. /// [Parameter] public string? SearchIcon { get; set; } /// - /// 获得/设置 清除搜索栏图标 默认 未设置 使用主题内置图标 + /// Gets or sets the clear search icon. Default is not set, using the built-in theme icon. /// [Parameter] public string? ClearSearchIcon { get; set; } /// - /// 获得/设置 搜索回调方法 默认 null 未设置 + /// Gets or sets the search callback method. Default is null. /// - /// 通过设置 开启 + /// Enabled by setting to true. [Parameter] public Func>?>>? OnSearchAsync { get; set; } /// - /// 获得/设置 带层次数据集合 + /// Gets or sets the hierarchical data collection. /// [Parameter] [NotNull] public List>? Items { get; set; } - ///// - ///// 获得/设置 扁平化数据集合注意 参数一定要赋值,不然无法呈现层次结构 - ///// - //[Parameter] - //public List>? FlatItems { get; set; } - /// - /// 获得/设置 是否显示 CheckBox 默认 false 不显示 + /// Gets or sets whether to show checkboxes. Default is false. /// [Parameter] public bool ShowCheckbox { get; set; } /// - /// 获得/设置 最多选中数量 + /// Gets or sets the maximum number of selected items. /// [Parameter] public int MaxSelectedCount { get; set; } /// - /// 获得/设置 超过最大选中数量时回调委托 + /// Gets or sets the callback method when the maximum number of selected items is exceeded. /// [Parameter] public Func? OnMaxSelectedCountExceed { get; set; } /// - /// 获得/设置 是否显示 Icon 图标 默认 false 不显示 + /// Gets or sets whether to show icons. Default is false. /// [Parameter] public bool ShowIcon { get; set; } /// - /// 获得/设置 树形控件节点点击时回调委托 + /// Gets or sets the callback method when a tree item is clicked. /// [Parameter] public Func, Task>? OnTreeItemClick { get; set; } /// - /// 获得/设置 树形控件节点选中时回调委托 + /// Gets or sets the callback method when a tree item is checked. /// [Parameter] public Func>, Task>? OnTreeItemChecked { get; set; } /// - /// 获得/设置 点击节点获取子数据集合回调方法 + /// Gets or sets the callback method to get child data when a node is expanded. /// [Parameter] public Func, Task>>>? OnExpandNodeAsync { get; set; } @@ -222,57 +203,56 @@ public partial class TreeView : IModelEqualityComparer public Type CustomKeyAttribute { get; set; } = typeof(KeyAttribute); /// - /// 获得/设置 比较数据是否相同回调方法 默认为 null + /// /// - /// 提供此回调方法时忽略 属性 [Parameter] public Func? ModelEqualityComparer { get; set; } /// - /// 获得/设置 Tree Node 正在加载动画图标 + /// Gets or sets the loading icon for tree nodes. /// [Parameter] public string? LoadingIcon { get; set; } /// - /// 获得/设置 Tree Node 节点图标 + /// Gets or sets the icon for tree nodes. /// [Parameter] public string? NodeIcon { get; set; } /// - /// 获得/设置 Tree Node 展开节点图标 + /// Gets or sets the icon for expanded tree nodes. /// [Parameter] public string? ExpandNodeIcon { get; set; } /// - /// 获得/设置 是否开启键盘上下左右按键操作 默认 false - /// ArrowLeft 收起节点 - /// ArrowRight 展开节点 - /// ArrowUp 向上移动节点 - /// ArrowDown 向下移动节点 - /// Space 选中当前节点 + /// Gets or sets whether to enable keyboard navigation. Default is false. + /// ArrowLeft collapses the node. + /// ArrowRight expands the node. + /// ArrowUp moves to the previous node. + /// ArrowDown moves to the next node. + /// Space selects the current node. /// [Parameter] public bool EnableKeyboard { get; set; } /// - /// 获得/设置 是否键盘上下键操作当前选中节点与视窗关系配置 默认 null 使用 { behavior: "smooth", block: "nearest", inline: "start" } + /// Gets or sets the scroll into view options for keyboard navigation. Default is null, using { behavior: "smooth", block: "nearest", inline: "start" }. /// [Parameter] public ScrollIntoViewOptions? ScrollIntoViewOptions { get; set; } /// - /// 获得/设置 是否启用虚拟滚动 默认 false 不启用 + /// Gets or sets whether to enable virtual scrolling. Default is false. /// [Parameter] public bool IsVirtualize { get; set; } /// - /// 获得/设置 虚拟滚动行高 默认为 38 + /// Gets or sets the row height for virtual scrolling. Default is 38. /// - /// 需要设置 值为 Virtual 时生效 + /// Effective when is set to Virtual. [Parameter] public float RowHeight { get; set; } = 38f; @@ -294,20 +274,17 @@ public partial class TreeView : IModelEqualityComparer [NotNull] private IOptionsMonitor? Options { get; set; } - /// - /// 节点状态缓存类实例 - /// [NotNull] - private TreeNodeCache, TItem>? TreeNodeStateCache { get; set; } + private TreeNodeCache, TItem>? _treeNodeStateCache = null; /// - /// 改变节点状态后自动更新子节点 默认 false + /// Gets or sets whether to automatically update child nodes when the node state changes. Default is false. /// [Parameter] public bool AutoCheckChildren { get; set; } /// - /// 改变节点状态后自动更新父节点 默认 false + /// Gets or sets whether to automatically update parent nodes when the node state changes. Default is false. /// [Parameter] public bool AutoCheckParent { get; set; } @@ -331,8 +308,7 @@ protected override void OnInitialized() { base.OnInitialized(); - // 初始化节点缓存 - TreeNodeStateCache ??= new(this); + _treeNodeStateCache = new(this); NotSetOnTreeExpandErrorMessage = Localizer[nameof(NotSetOnTreeExpandErrorMessage)]; } @@ -371,13 +347,13 @@ protected override async Task OnParametersSetAsync() if (ShowCheckbox && (AutoCheckParent || AutoCheckChildren)) { // 开启 Checkbox 功能时初始化选中节点 - TreeNodeStateCache.IsChecked(Items); + _treeNodeStateCache.IsChecked(Items); } // 从数据源中恢复当前 active 节点 if (_activeItem != null) { - _activeItem = TreeNodeStateCache.Find(Items, _activeItem.Value, out _); + _activeItem = _treeNodeStateCache.Find(Items, _activeItem.Value, out _); } if (_init == false) @@ -467,7 +443,7 @@ public Task> GetParentsState(List items) return Task.FromResult(result); } - private static bool IsExpand(TreeViewItem item) => item.IsExpand && item.Items.Count > 0; + private static bool IsExpand(TreeViewItem item) => item is { IsExpand: true, Items.Count: > 0 }; private List> GetItems(TreeViewItem item) => item.Parent?.Items ?? Items; @@ -559,7 +535,7 @@ async Task CheckExpand(IEnumerable> nodes) // 恢复当前节点状态 foreach (var node in nodes) { - await TreeNodeStateCache.CheckExpandAsync(node, GetChildrenRowAsync); + await _treeNodeStateCache.CheckExpandAsync(node, GetChildrenRowAsync); if (node.Items.Count > 0) { @@ -657,18 +633,6 @@ public void SetItems(List> items) StateHasChanged(); } - ///// - ///// 重新设置 数据源方法 - ///// - ///// - //public void SetFlatItems(List> flatItems) - //{ - // Items = null; - // FlatItems = flatItems; - // _rows = null; - // StateHasChanged(); - //} - /// /// 设置选中节点 /// @@ -694,33 +658,20 @@ private async Task OnToggleNodeAsync(TreeViewItem node, bool shouldRender // 手风琴效果逻辑 node.IsExpand = !node.IsExpand; - //// 如果节点设置有子节点但是当前没有时调用 GetChildrenRowAsync 方法 - //if (node.IsExpand && node.HasChildren && node.Items.Count == 0) - //{ - // var items = await GetChildrenRowAsync(node); - // if (items != null) - // { - // foreach (var item in items) - // { - // item.Parent = node; - // node.Items.Add(item); - // } - // } - //} if (IsAccordion && !IsVirtualize) { - await TreeNodeStateCache.ToggleNodeAsync(node, GetChildrenRowAsync); + await _treeNodeStateCache.ToggleNodeAsync(node, GetChildrenRowAsync); // 展开此节点关闭其他同级节点 if (node.IsExpand) { // 通过 item 找到父节点 - var nodes = TreeNodeStateCache.FindParentNode(Items, node)?.Items ?? Items; + var nodes = _treeNodeStateCache.FindParentNode(Items, node)?.Items ?? Items; foreach (var n in nodes.Where(n => n != node)) { // 收缩同级节点 n.IsExpand = false; - await TreeNodeStateCache.ToggleNodeAsync(n, GetChildrenRowAsync); + await _treeNodeStateCache.ToggleNodeAsync(n, GetChildrenRowAsync); } } _rows = null; @@ -728,7 +679,7 @@ private async Task OnToggleNodeAsync(TreeViewItem node, bool shouldRender else { // 重建缓存 并且更改节点展开状态 - await TreeNodeStateCache.ToggleNodeAsync(node, GetChildrenRowAsync); + await _treeNodeStateCache.ToggleNodeAsync(node, GetChildrenRowAsync); _rows = null; } @@ -736,15 +687,15 @@ private async Task OnToggleNodeAsync(TreeViewItem node, bool shouldRender { if (AutoCheckChildren) { - node.SetChildrenCheck(TreeNodeStateCache); + node.SetChildrenCheck(_treeNodeStateCache); } if (AutoCheckParent) { - node.SetParentCheck(TreeNodeStateCache); + node.SetParentCheck(_treeNodeStateCache); } if (!AutoCheckChildren && AutoCheckParent && node.Items.Count > 0) { - node.Items[0].SetParentCheck(TreeNodeStateCache); + node.Items[0].SetParentCheck(_treeNodeStateCache); } } @@ -763,14 +714,14 @@ private async Task OnToggleNodeAsync(TreeViewItem node, bool shouldRender private async Task OnCheckStateChanged(TreeViewItem item, CheckboxState state) { item.CheckedState = state; - TreeNodeStateCache.ToggleCheck(item); + _treeNodeStateCache.ToggleCheck(item); if (AutoCheckChildren) { // 向下级联操作 if (item.CheckedState != CheckboxState.Indeterminate) { - item.SetChildrenCheck(TreeNodeStateCache); + item.SetChildrenCheck(_treeNodeStateCache); _ = InvokeVoidAsync("setChildrenState", Id, Rows.IndexOf(item), item.CheckedState); } } @@ -778,13 +729,13 @@ private async Task OnCheckStateChanged(TreeViewItem item, CheckboxState s if (AutoCheckParent) { // 向上级联操作 - item.SetParentCheck(TreeNodeStateCache); + item.SetParentCheck(_treeNodeStateCache); _ = InvokeVoidAsync("setParentState", Id, Interop, nameof(GetParentsState), Rows.IndexOf(item)); } if (OnTreeItemChecked != null) { - await OnTreeItemChecked(GetCheckedItems().ToList()); + await OnTreeItemChecked([.. GetCheckedItems()]); } } @@ -796,11 +747,11 @@ public void ClearCheckedItems() Items.ForEach(item => { item.CheckedState = CheckboxState.UnChecked; - TreeNodeStateCache.ToggleCheck(item); + _treeNodeStateCache.ToggleCheck(item); item.GetAllTreeSubItems().ToList().ForEach(s => { s.CheckedState = CheckboxState.UnChecked; - TreeNodeStateCache.ToggleCheck(s); + _treeNodeStateCache.ToggleCheck(s); }); }); StateHasChanged(); From 16a89eef32d3e754f7d1cb06dea144f1063626ea Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Wed, 12 Mar 2025 13:15:53 +0800 Subject: [PATCH 02/34] =?UTF-8?q?doc:=20=E6=9B=B4=E6=96=B0=E6=96=87?= =?UTF-8?q?=E6=A1=A3=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/TreeView/TreeView.razor.cs | 67 ++++++------------- 1 file changed, 22 insertions(+), 45 deletions(-) diff --git a/src/BootstrapBlazor/Components/TreeView/TreeView.razor.cs b/src/BootstrapBlazor/Components/TreeView/TreeView.razor.cs index 954fe08ddaf..c6c091fe6f5 100644 --- a/src/BootstrapBlazor/Components/TreeView/TreeView.razor.cs +++ b/src/BootstrapBlazor/Components/TreeView/TreeView.razor.cs @@ -346,11 +346,9 @@ protected override async Task OnParametersSetAsync() if (ShowCheckbox && (AutoCheckParent || AutoCheckChildren)) { - // 开启 Checkbox 功能时初始化选中节点 _treeNodeStateCache.IsChecked(Items); } - // 从数据源中恢复当前 active 节点 if (_activeItem != null) { _activeItem = _treeNodeStateCache.Find(Items, _activeItem.Value, out _); @@ -358,7 +356,6 @@ protected override async Task OnParametersSetAsync() if (_init == false) { - // 设置 ActiveItem 默认值 _activeItem ??= Items.FirstOrDefaultActiveItem(); _activeItem?.SetParentExpand, TItem>(true); _init = true; @@ -397,15 +394,15 @@ protected override async Task OnAfterRenderAsync(bool firstRender) private bool _keyboardArrowUpDownTrigger; /// - /// 客户端用户键盘操作处理方法 由 JavaScript 调用 + /// Client-side user keyboard operation handler method called by JavaScript /// /// /// [JSInvokable] public async ValueTask TriggerKeyDown(string key) { - // 通过 ActiveItem 找到兄弟节点 - // 如果兄弟节点没有时,找到父亲节点 + // Find sibling nodes through ActiveItem + // If there are no sibling nodes, find the parent node if (_activeItem != null) { if (key == "ArrowUp" || key == "ArrowDown") @@ -421,7 +418,7 @@ public async ValueTask TriggerKeyDown(string key) } /// - /// 客户端查询指定行选择框状态方法 由 JavaScript 调用 + /// Client-side method to query the state of the specified row checkbox, called by JavaScript /// /// /// @@ -516,7 +513,6 @@ private async Task OnBeforeStateChangedCallback(TreeViewItem item, { if (state == CheckboxState.Checked) { - // 展开节点 var items = GetCheckedItems().Where(i => i.HasChildren == false).ToList(); var count = items.Count + item.GetAllTreeSubItems().Count(); ret = count < MaxSelectedCount; @@ -532,7 +528,6 @@ private async Task OnBeforeStateChangedCallback(TreeViewItem item, async Task CheckExpand(IEnumerable> nodes) { - // 恢复当前节点状态 foreach (var node in nodes) { await _treeNodeStateCache.CheckExpandAsync(node, GetChildrenRowAsync); @@ -557,10 +552,6 @@ private async Task>> GetChildrenRowAsync(Tree return ret; } - /// - /// 选中节点时触发此方法 - /// - /// private async Task OnClick(TreeViewItem item) { _activeItem = item; @@ -613,7 +604,7 @@ private Task OnClickResetSearch() } /// - /// 设置选中节点 + /// Set the active node /// public void SetActiveItem(TreeViewItem? item) { @@ -623,18 +614,17 @@ public void SetActiveItem(TreeViewItem? item) } /// - /// 重新设置 数据源方法 + /// Set the data source method for /// public void SetItems(List> items) { - //FlatItems = null; Items = items; _rows = null; StateHasChanged(); } /// - /// 设置选中节点 + /// Set the active node /// public void SetActiveItem(TItem item) { @@ -649,7 +639,7 @@ public void SetActiveItem(TItem item) }; /// - /// 切换节点展开收缩状态方法 + /// Toggle node expand collapse state method /// /// /// @@ -705,12 +695,6 @@ private async Task OnToggleNodeAsync(TreeViewItem node, bool shouldRender } } - /// - /// 节点 Checkbox 状态改变时触发此方法 - /// - /// - /// - /// private async Task OnCheckStateChanged(TreeViewItem item, CheckboxState state) { item.CheckedState = state; @@ -740,7 +724,7 @@ private async Task OnCheckStateChanged(TreeViewItem item, CheckboxState s } /// - /// 清除 所有选中节点 + /// Clear all selected nodes /// public void ClearCheckedItems() { @@ -758,7 +742,7 @@ public void ClearCheckedItems() } /// - /// 获得 所有选中节点集合 + /// Gets all selected node collections /// /// public IEnumerable> GetCheckedItems() => Items.Aggregate(new List>(), (t, item) => @@ -769,7 +753,7 @@ public IEnumerable> GetCheckedItems() => Items.Aggregate(new }).Where(i => i.CheckedState == CheckboxState.Checked); /// - /// 比较数据是否相同 + /// Check if the data is the same /// /// /// @@ -786,27 +770,22 @@ private async Task OnContextMenu(MouseEventArgs e, TreeViewItem item) private bool IsPreventDefault => ContextMenuZone != null; - /// - /// 是否触摸 - /// - private bool TouchStart { get; set; } + private bool _touchStart = false; - /// - /// 触摸定时器工作指示 - /// - private bool IsBusy { get; set; } + private bool _isBusy = false; private async Task OnTouchStart(TouchEventArgs e, TreeViewItem item) { - if (!IsBusy && ContextMenuZone != null) + if (!_isBusy && ContextMenuZone != null) { - IsBusy = true; - TouchStart = true; + _isBusy = true; + _touchStart = true; // 延时保持 TouchStart 状态 + // keep the TouchStart state for a while var delay = Options.CurrentValue.ContextMenuOptions.OnTouchDelay; await Task.Delay(delay); - if (TouchStart) + if (_touchStart) { var args = new MouseEventArgs() { @@ -815,19 +794,18 @@ private async Task OnTouchStart(TouchEventArgs e, TreeViewItem item) ScreenX = e.Touches[0].ScreenX, ScreenY = e.Touches[0].ScreenY, }; - // 弹出关联菜单 await OnContextMenu(args, item); - //延时防止重复激活菜单功能 + // prevents the menu from being activated repeatedly await Task.Delay(delay); } - IsBusy = false; + _isBusy = false; } } private void OnTouchEnd() { - TouchStart = false; + _touchStart = false; } private List>? _rows = null; @@ -836,8 +814,7 @@ private List> Rows { get { - // 扁平化数据集合 - _rows ??= GetTreeItems().ToFlat(); + _rows ??= GetTreeItems().ToFlat(); return _rows; } } From 60733e9de75bb1cec70e18b10387f699696d975c Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Wed, 12 Mar 2025 15:02:35 +0800 Subject: [PATCH 03/34] =?UTF-8?q?wip:=20=E4=B8=B4=E6=97=B6=E6=8F=90?= =?UTF-8?q?=E4=BA=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/TreeView/TreeView.razor | 1 + .../Components/TreeView/TreeView.razor.cs | 19 +++++++++++++++++-- .../Components/TreeView/TreeView.razor.scss | 4 ++++ .../Components/TreeView/TreeViewToolbar.cs | 12 ++++++++++++ 4 files changed, 34 insertions(+), 2 deletions(-) create mode 100644 src/BootstrapBlazor/Components/TreeView/TreeViewToolbar.cs diff --git a/src/BootstrapBlazor/Components/TreeView/TreeView.razor b/src/BootstrapBlazor/Components/TreeView/TreeView.razor index de3fa3df839..632fbaf9392 100644 --- a/src/BootstrapBlazor/Components/TreeView/TreeView.razor +++ b/src/BootstrapBlazor/Components/TreeView/TreeView.razor @@ -69,6 +69,7 @@ else @code { private RenderFragment> RenderTreeRow => item => @
+ @RenderToolbar(item)
diff --git a/src/BootstrapBlazor/Components/TreeView/TreeView.razor.cs b/src/BootstrapBlazor/Components/TreeView/TreeView.razor.cs index c6c091fe6f5..a836dbc4521 100644 --- a/src/BootstrapBlazor/Components/TreeView/TreeView.razor.cs +++ b/src/BootstrapBlazor/Components/TreeView/TreeView.razor.cs @@ -63,10 +63,16 @@ public partial class TreeView : IModelEqualityComparer public bool IsReset { get; set; } /// - /// Gets or sets whether the tree view is editable. Default is false. + /// Gets or sets whether show the toolbar of tree view item. Default is false. /// [Parameter] - public bool IsEditable { get; set; } + public bool ShowToolbar { get; set; } + + /// + /// A callback method that determines whether to show the toolbar of the tree view item. + /// + [Parameter] + public Func>? ShowToolbarCallback { get; set; } /// /// Gets or sets whether the entire component is disabled. Default is false. @@ -832,4 +838,13 @@ private List> Rows } return $"--bb-tree-view-level: {level};"; } + + private RenderFragment> RenderToolbar = item => builder => + { + builder.OpenComponent(0); + builder.AddAttribute(10, nameof(TreeViewToolbar.ShowToolbar), ) + builder.CloseComponent(); + }; } + + diff --git a/src/BootstrapBlazor/Components/TreeView/TreeView.razor.scss b/src/BootstrapBlazor/Components/TreeView/TreeView.razor.scss index 0d0f664ff25..7ae6193340d 100644 --- a/src/BootstrapBlazor/Components/TreeView/TreeView.razor.scss +++ b/src/BootstrapBlazor/Components/TreeView/TreeView.razor.scss @@ -39,6 +39,10 @@ align-items: center; cursor: pointer; + .tree-content-toolbar { + display: none; + } + .tree-content-header { flex-basis: calc(var(--bb-tree-padding-left) * var(--bb-tree-view-level, 0)); flex-shrink: 0; diff --git a/src/BootstrapBlazor/Components/TreeView/TreeViewToolbar.cs b/src/BootstrapBlazor/Components/TreeView/TreeViewToolbar.cs new file mode 100644 index 00000000000..f4dccc4d686 --- /dev/null +++ b/src/BootstrapBlazor/Components/TreeView/TreeViewToolbar.cs @@ -0,0 +1,12 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the Apache 2.0 License +// See the LICENSE file in the project root for more information. +// Maintainer: Argo Zhang(argo@live.ca) Website: https://www.blazor.zone + +namespace BootstrapBlazor.Components; + +class TreeViewToolbar : ComponentBase +{ + [Parameter] + public Func>? ShowToolbar { get; set; } +} From 95fcd1f14aea04777efbfbc995c98f2cc20ae04b Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Wed, 12 Mar 2025 16:24:24 +0800 Subject: [PATCH 04/34] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0=20TreeViewTool?= =?UTF-8?q?bar=20=E7=BB=84=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/TreeView/TreeViewToolbar.cs | 37 ++++++++++++++++++- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/src/BootstrapBlazor/Components/TreeView/TreeViewToolbar.cs b/src/BootstrapBlazor/Components/TreeView/TreeViewToolbar.cs index f4dccc4d686..ce076100e8d 100644 --- a/src/BootstrapBlazor/Components/TreeView/TreeViewToolbar.cs +++ b/src/BootstrapBlazor/Components/TreeView/TreeViewToolbar.cs @@ -3,10 +3,43 @@ // See the LICENSE file in the project root for more information. // Maintainer: Argo Zhang(argo@live.ca) Website: https://www.blazor.zone +using Microsoft.AspNetCore.Components.Rendering; + namespace BootstrapBlazor.Components; -class TreeViewToolbar : ComponentBase +class TreeViewToolbar : ComponentBase { + [Parameter, NotNull] + public Func>? ShowToolbarAsync { get; set; } + + [Parameter, NotNull] + public TItem? Item { get; set; } + [Parameter] - public Func>? ShowToolbar { get; set; } + public RenderFragment? ChildContent { get; set; } + + private bool _showToolbar = false; + + /// + /// + /// + /// + protected override async Task OnParametersSetAsync() + { + await base.OnParametersSetAsync(); + + _showToolbar = await ShowToolbarAsync(Item); + } + + /// + /// + /// + /// + protected override void BuildRenderTree(RenderTreeBuilder builder) + { + if (_showToolbar) + { + builder.AddContent(0, ChildContent); + } + } } From 2ad774210f7ca92a9ecbe9545054785949241094 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Thu, 13 Mar 2025 08:22:29 +0800 Subject: [PATCH 05/34] =?UTF-8?q?refactor:=20=E5=A2=9E=E5=8A=A0=E6=B8=B2?= =?UTF-8?q?=E6=9F=93=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/Samples/TreeViews.razor | 2 +- .../Components/TreeView/TreeView.razor | 4 +++- .../Components/TreeView/TreeView.razor.cs | 18 +++++++++++++++--- 3 files changed, 19 insertions(+), 5 deletions(-) diff --git a/src/BootstrapBlazor.Server/Components/Samples/TreeViews.razor b/src/BootstrapBlazor.Server/Components/Samples/TreeViews.razor index 97270a8e75b..0bf1f8298c5 100644 --- a/src/BootstrapBlazor.Server/Components/Samples/TreeViews.razor +++ b/src/BootstrapBlazor.Server/Components/Samples/TreeViews.razor @@ -27,7 +27,7 @@ Introduction="@Localizer["TreeViewNormalIntro"]" Name="Normal">
@((MarkupString)Localizer["TreeViewNormalDescription"].Value)
- + diff --git a/src/BootstrapBlazor/Components/TreeView/TreeView.razor b/src/BootstrapBlazor/Components/TreeView/TreeView.razor index 632fbaf9392..8c330e20e29 100644 --- a/src/BootstrapBlazor/Components/TreeView/TreeView.razor +++ b/src/BootstrapBlazor/Components/TreeView/TreeView.razor @@ -69,7 +69,6 @@ else @code { private RenderFragment> RenderTreeRow => item => @
- @RenderToolbar(item)
@@ -97,4 +96,7 @@ else
; + + RenderFragment RenderToolbarContent => + @
Test
; } diff --git a/src/BootstrapBlazor/Components/TreeView/TreeView.razor.cs b/src/BootstrapBlazor/Components/TreeView/TreeView.razor.cs index a836dbc4521..22eb2fdc5ab 100644 --- a/src/BootstrapBlazor/Components/TreeView/TreeView.razor.cs +++ b/src/BootstrapBlazor/Components/TreeView/TreeView.razor.cs @@ -839,12 +839,24 @@ private List> Rows return $"--bb-tree-view-level: {level};"; } - private RenderFragment> RenderToolbar = item => builder => + private RenderFragment RenderToolbar(TItem item) => builder => { - builder.OpenComponent(0); - builder.AddAttribute(10, nameof(TreeViewToolbar.ShowToolbar), ) + builder.OpenComponent>(0); + builder.AddAttribute(10, nameof(TreeViewToolbar.Item), item); + builder.AddAttribute(20, nameof(TreeViewToolbar.ShowToolbarAsync), ShowTollbarAsync); + builder.AddAttribute(30, nameof(TreeViewToolbar.ChildContent), RenderToolbarContent); builder.CloseComponent(); }; + + private async Task ShowTollbarAsync(TItem item) + { + if (ShowToolbarCallback != null) + { + return await ShowToolbarCallback(item); + } + + return ShowToolbar; + } } From f07e3e29c272e1373e769274520e0608f14ddd6f Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Thu, 13 Mar 2025 08:32:14 +0800 Subject: [PATCH 06/34] =?UTF-8?q?refactor:=20=E9=87=8D=E6=9E=84=E9=80=BB?= =?UTF-8?q?=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/TreeView/TreeView.razor | 1 + .../Components/TreeView/TreeView.razor.cs | 11 ++++------- .../Components/TreeView/TreeViewToolbar.cs | 3 ++- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/BootstrapBlazor/Components/TreeView/TreeView.razor b/src/BootstrapBlazor/Components/TreeView/TreeView.razor index 8c330e20e29..ff2e8afb55a 100644 --- a/src/BootstrapBlazor/Components/TreeView/TreeView.razor +++ b/src/BootstrapBlazor/Components/TreeView/TreeView.razor @@ -63,6 +63,7 @@ else }
} + @RenderToolbar
} diff --git a/src/BootstrapBlazor/Components/TreeView/TreeView.razor.cs b/src/BootstrapBlazor/Components/TreeView/TreeView.razor.cs index 22eb2fdc5ab..e07ecbdd7ac 100644 --- a/src/BootstrapBlazor/Components/TreeView/TreeView.razor.cs +++ b/src/BootstrapBlazor/Components/TreeView/TreeView.razor.cs @@ -839,24 +839,21 @@ private List> Rows return $"--bb-tree-view-level: {level};"; } - private RenderFragment RenderToolbar(TItem item) => builder => + private RenderFragment RenderToolbar => builder => { builder.OpenComponent>(0); - builder.AddAttribute(10, nameof(TreeViewToolbar.Item), item); - builder.AddAttribute(20, nameof(TreeViewToolbar.ShowToolbarAsync), ShowTollbarAsync); + //builder.AddAttribute(20, nameof(TreeViewToolbar.ShowToolbarAsync), ShowTollbarAsync); builder.AddAttribute(30, nameof(TreeViewToolbar.ChildContent), RenderToolbarContent); builder.CloseComponent(); }; - private async Task ShowTollbarAsync(TItem item) + private async Task ShowTollbarAsync() { if (ShowToolbarCallback != null) { - return await ShowToolbarCallback(item); + return await ShowToolbarCallback(default!); } return ShowToolbar; } } - - diff --git a/src/BootstrapBlazor/Components/TreeView/TreeViewToolbar.cs b/src/BootstrapBlazor/Components/TreeView/TreeViewToolbar.cs index ce076100e8d..d66683b84cf 100644 --- a/src/BootstrapBlazor/Components/TreeView/TreeViewToolbar.cs +++ b/src/BootstrapBlazor/Components/TreeView/TreeViewToolbar.cs @@ -28,7 +28,8 @@ protected override async Task OnParametersSetAsync() { await base.OnParametersSetAsync(); - _showToolbar = await ShowToolbarAsync(Item); + //_showToolbar = await ShowToolbarAsync(Item); + _showToolbar = true; } /// From a7bbb6a32e1247d2eb40485cf24a62bd22899d23 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Fri, 14 Mar 2025 08:38:57 +0800 Subject: [PATCH 07/34] =?UTF-8?q?refactor:=20=E5=A2=9E=E5=8A=A0=20RenderTo?= =?UTF-8?q?olbar=20=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/TreeView/TreeView.razor | 13 +++++++-- .../Components/TreeView/TreeView.razor.cs | 29 +++++++++++++++---- .../Components/TreeView/TreeView.razor.scss | 12 ++++++++ 3 files changed, 45 insertions(+), 9 deletions(-) diff --git a/src/BootstrapBlazor/Components/TreeView/TreeView.razor b/src/BootstrapBlazor/Components/TreeView/TreeView.razor index ff2e8afb55a..72c70bc0365 100644 --- a/src/BootstrapBlazor/Components/TreeView/TreeView.razor +++ b/src/BootstrapBlazor/Components/TreeView/TreeView.razor @@ -63,7 +63,6 @@ else } } - @RenderToolbar } @@ -94,10 +93,18 @@ else { @item.Template(item.Value) } + @RenderToolbar(item) ; - RenderFragment RenderToolbarContent => - @
Test
; + RenderFragment> RenderToolbarContent => item => + @
+ + + Label: + + + +
; } diff --git a/src/BootstrapBlazor/Components/TreeView/TreeView.razor.cs b/src/BootstrapBlazor/Components/TreeView/TreeView.razor.cs index e07ecbdd7ac..efd04fdbb13 100644 --- a/src/BootstrapBlazor/Components/TreeView/TreeView.razor.cs +++ b/src/BootstrapBlazor/Components/TreeView/TreeView.razor.cs @@ -72,7 +72,7 @@ public partial class TreeView : IModelEqualityComparer /// A callback method that determines whether to show the toolbar of the tree view item. ///
[Parameter] - public Func>? ShowToolbarCallback { get; set; } + public Func, Task>? ShowToolbarCallback { get; set; } /// /// Gets or sets whether the entire component is disabled. Default is false. @@ -262,6 +262,18 @@ public partial class TreeView : IModelEqualityComparer [Parameter] public float RowHeight { get; set; } = 38f; + /// + /// Gets or sets the toolbar content template. Default is null. + /// + [Parameter] + public RenderFragment? ToolbarTemplate { get; set; } + + /// + /// Gets or sets the callback method when a tree item is updated. + /// + [Parameter] + public Func, Task>? OnUpdateTreeNodeAsync { get; set; } + [CascadingParameter] private ContextMenuZone? ContextMenuZone { get; set; } @@ -839,21 +851,26 @@ private List> Rows return $"--bb-tree-view-level: {level};"; } - private RenderFragment RenderToolbar => builder => + private RenderFragment RenderToolbar(TreeViewItem item) => builder => { builder.OpenComponent>(0); - //builder.AddAttribute(20, nameof(TreeViewToolbar.ShowToolbarAsync), ShowTollbarAsync); + builder.AddAttribute(10, nameof(TreeViewToolbar.Item), item); + builder.AddAttribute(20, nameof(TreeViewToolbar.ShowToolbarAsync), ShowTollbarAsync); builder.AddAttribute(30, nameof(TreeViewToolbar.ChildContent), RenderToolbarContent); builder.CloseComponent(); }; - private async Task ShowTollbarAsync() + private async Task ShowTollbarAsync(TreeViewItem item) { if (ShowToolbarCallback != null) { - return await ShowToolbarCallback(default!); + return await ShowToolbarCallback(item); } - return ShowToolbar; } + + private async Task OnUpdateItemAsync(TreeViewItem item) + { + + } } diff --git a/src/BootstrapBlazor/Components/TreeView/TreeView.razor.scss b/src/BootstrapBlazor/Components/TreeView/TreeView.razor.scss index 7ae6193340d..f8dd8ebf071 100644 --- a/src/BootstrapBlazor/Components/TreeView/TreeView.razor.scss +++ b/src/BootstrapBlazor/Components/TreeView/TreeView.razor.scss @@ -136,5 +136,17 @@ &.disabled { opacity: var(--bb-tree-disabled-opacity); } + + .tree-node-toolbar { + position: absolute; + right: 0; + height: 100%; + display: flex; + align-items: center; + } + + &:not(:hover) .tree-node-toolbar { + display: none; + } } } From 7f457065a6f6c9a59abcee63316cf28725768e41 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Fri, 14 Mar 2025 08:39:07 +0800 Subject: [PATCH 08/34] =?UTF-8?q?refactor:=20=E4=BB=A3=E7=A0=81=E9=87=8D?= =?UTF-8?q?=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/BootstrapBlazor/Components/TreeView/TreeViewItem.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/BootstrapBlazor/Components/TreeView/TreeViewItem.cs b/src/BootstrapBlazor/Components/TreeView/TreeViewItem.cs index 0ba21d92675..e1599b73c8e 100644 --- a/src/BootstrapBlazor/Components/TreeView/TreeViewItem.cs +++ b/src/BootstrapBlazor/Components/TreeView/TreeViewItem.cs @@ -30,7 +30,7 @@ public class TreeViewItem : TreeNodeBase, ICheckableNode /// /// 获得/设置 子节点集合 /// - IEnumerable> IExpandableNode.Items { get => Items; set => Items = value.OfType>().ToList(); } + IEnumerable> IExpandableNode.Items { get => Items; set => Items = [.. value.OfType>()]; } /// /// 获得/设置 父级节点 From 278f9aa67ebcc4d63f527a98b727ce1e87c52196 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Fri, 14 Mar 2025 08:39:19 +0800 Subject: [PATCH 09/34] =?UTF-8?q?refactor:=20=E9=87=8D=E6=9E=84=20TreeView?= =?UTF-8?q?Toolbar=20=E7=BB=84=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/TreeView/TreeViewToolbar.cs | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/BootstrapBlazor/Components/TreeView/TreeViewToolbar.cs b/src/BootstrapBlazor/Components/TreeView/TreeViewToolbar.cs index d66683b84cf..b2a638053d1 100644 --- a/src/BootstrapBlazor/Components/TreeView/TreeViewToolbar.cs +++ b/src/BootstrapBlazor/Components/TreeView/TreeViewToolbar.cs @@ -10,13 +10,13 @@ namespace BootstrapBlazor.Components; class TreeViewToolbar : ComponentBase { [Parameter, NotNull] - public Func>? ShowToolbarAsync { get; set; } + public Func, Task>? ShowToolbarAsync { get; set; } [Parameter, NotNull] - public TItem? Item { get; set; } + public TreeViewItem? Item { get; set; } - [Parameter] - public RenderFragment? ChildContent { get; set; } + [Parameter, NotNull] + public RenderFragment>? ChildContent { get; set; } private bool _showToolbar = false; @@ -28,8 +28,7 @@ protected override async Task OnParametersSetAsync() { await base.OnParametersSetAsync(); - //_showToolbar = await ShowToolbarAsync(Item); - _showToolbar = true; + _showToolbar = await ShowToolbarAsync(Item); } /// @@ -40,7 +39,7 @@ protected override void BuildRenderTree(RenderTreeBuilder builder) { if (_showToolbar) { - builder.AddContent(0, ChildContent); + builder.AddContent(0, ChildContent(Item)); } } } From 841bff83e802149db34be8ae85435b86fcdce77b Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Fri, 14 Mar 2025 12:11:47 +0800 Subject: [PATCH 10/34] =?UTF-8?q?fix(PopConfirmButton):=20=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D=E5=BC=80=E5=90=AF=20Title=20=E5=90=8E=E5=BC=B9?= =?UTF-8?q?=E7=AA=97=20UI=20=E4=B8=8D=E6=AD=A3=E5=B8=B8=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/Button/PopConfirmButton.razor.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/BootstrapBlazor/Components/Button/PopConfirmButton.razor.js b/src/BootstrapBlazor/Components/Button/PopConfirmButton.razor.js index cc6527c27ab..a361d3a9ac3 100644 --- a/src/BootstrapBlazor/Components/Button/PopConfirmButton.razor.js +++ b/src/BootstrapBlazor/Components/Button/PopConfirmButton.razor.js @@ -31,9 +31,8 @@ export function init(id) { confirm.inserted = () => { const popover = getDescribedElement(el) const children = confirm.container.children - const len = children.length - for (let i = 0; i < len; i++) { - popover.appendChild(children[i]) + while (children.length > 0) { + popover.appendChild(children[0]) } } confirm.hide = () => { From 548aecd20d1f606ace782f015020dc7669a79218 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Fri, 14 Mar 2025 12:12:09 +0800 Subject: [PATCH 11/34] =?UTF-8?q?doc:=20=E6=9B=B4=E6=96=B0=E8=B5=84?= =?UTF-8?q?=E6=BA=90=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/BootstrapBlazor/Locales/en.json | 4 +++- src/BootstrapBlazor/Locales/zh.json | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/BootstrapBlazor/Locales/en.json b/src/BootstrapBlazor/Locales/en.json index 12d0d4c01a2..7166f59fed2 100644 --- a/src/BootstrapBlazor/Locales/en.json +++ b/src/BootstrapBlazor/Locales/en.json @@ -306,7 +306,9 @@ "NotSetOnTreeExpandErrorMessage": "not set OnExpandNodeAsync parameter" }, "BootstrapBlazor.Components.TreeView": { - "NotSetOnTreeExpandErrorMessage": "not set OnExpandNodeAsync parameter" + "NotSetOnTreeExpandErrorMessage": "not set OnExpandNodeAsync parameter", + "ToolbarEditTitle": "Edit Tree Node", + "ToolbarEditLabelText": "Rename" }, "BootstrapBlazor.Components.UploadBase": { "DeleteButtonText": "Delete", diff --git a/src/BootstrapBlazor/Locales/zh.json b/src/BootstrapBlazor/Locales/zh.json index be7cc4b2cb4..ecc46d43db4 100644 --- a/src/BootstrapBlazor/Locales/zh.json +++ b/src/BootstrapBlazor/Locales/zh.json @@ -306,7 +306,9 @@ "NotSetOnTreeExpandErrorMessage": "未设置 OnExpandNodeAsync 回调委托方法" }, "BootstrapBlazor.Components.TreeView": { - "NotSetOnTreeExpandErrorMessage": "未设置 OnExpandNodeAsync 回调委托方法" + "NotSetOnTreeExpandErrorMessage": "未设置 OnExpandNodeAsync 回调委托方法", + "ToolbarEditTitle": "节点名称编辑", + "ToolbarEditLabelText": "更改为" }, "BootstrapBlazor.Components.UploadBase": { "DeleteButtonText": "删除", From 8f828766034c0fc526aeda501912eebbcecfb075 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Fri, 14 Mar 2025 12:12:59 +0800 Subject: [PATCH 12/34] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0=20TreeViewTool?= =?UTF-8?q?bar=20=E7=BB=84=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/TreeView/TreeViewToolbar.cs | 45 ------------- .../Components/TreeView/TreeViewToolbar.razor | 19 ++++++ .../TreeView/TreeViewToolbar.razor.cs | 65 +++++++++++++++++++ 3 files changed, 84 insertions(+), 45 deletions(-) delete mode 100644 src/BootstrapBlazor/Components/TreeView/TreeViewToolbar.cs create mode 100644 src/BootstrapBlazor/Components/TreeView/TreeViewToolbar.razor create mode 100644 src/BootstrapBlazor/Components/TreeView/TreeViewToolbar.razor.cs diff --git a/src/BootstrapBlazor/Components/TreeView/TreeViewToolbar.cs b/src/BootstrapBlazor/Components/TreeView/TreeViewToolbar.cs deleted file mode 100644 index b2a638053d1..00000000000 --- a/src/BootstrapBlazor/Components/TreeView/TreeViewToolbar.cs +++ /dev/null @@ -1,45 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the Apache 2.0 License -// See the LICENSE file in the project root for more information. -// Maintainer: Argo Zhang(argo@live.ca) Website: https://www.blazor.zone - -using Microsoft.AspNetCore.Components.Rendering; - -namespace BootstrapBlazor.Components; - -class TreeViewToolbar : ComponentBase -{ - [Parameter, NotNull] - public Func, Task>? ShowToolbarAsync { get; set; } - - [Parameter, NotNull] - public TreeViewItem? Item { get; set; } - - [Parameter, NotNull] - public RenderFragment>? ChildContent { get; set; } - - private bool _showToolbar = false; - - /// - /// - /// - /// - protected override async Task OnParametersSetAsync() - { - await base.OnParametersSetAsync(); - - _showToolbar = await ShowToolbarAsync(Item); - } - - /// - /// - /// - /// - protected override void BuildRenderTree(RenderTreeBuilder builder) - { - if (_showToolbar) - { - builder.AddContent(0, ChildContent(Item)); - } - } -} diff --git a/src/BootstrapBlazor/Components/TreeView/TreeViewToolbar.razor b/src/BootstrapBlazor/Components/TreeView/TreeViewToolbar.razor new file mode 100644 index 00000000000..4b9b6ea53ce --- /dev/null +++ b/src/BootstrapBlazor/Components/TreeView/TreeViewToolbar.razor @@ -0,0 +1,19 @@ +@namespace BootstrapBlazor.Components +@typeparam TItem +@inherits ComponentBase + +
+ + + @if (BodyTemplate != null) + { + @BodyTemplate(Item) + } + else + { + + + } + + +
diff --git a/src/BootstrapBlazor/Components/TreeView/TreeViewToolbar.razor.cs b/src/BootstrapBlazor/Components/TreeView/TreeViewToolbar.razor.cs new file mode 100644 index 00000000000..8d1adec3073 --- /dev/null +++ b/src/BootstrapBlazor/Components/TreeView/TreeViewToolbar.razor.cs @@ -0,0 +1,65 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the Apache 2.0 License +// See the LICENSE file in the project root for more information. +// Maintainer: Argo Zhang(argo@live.ca) Website: https://www.blazor.zone + +namespace BootstrapBlazor.Components; + +/// +/// TreeViewToolbar component +/// +/// +public partial class TreeViewToolbar : ComponentBase +{ + /// + /// Gets or sets the tree view item. Default is null. + /// + [Parameter, NotNull] + public TreeViewItem? Item { get; set; } + + /// + /// Gets or sets the item changed event callback. + /// + [Parameter] + public EventCallback> ItemChanged { get; set; } + + /// + /// Gets or sets the child content of the tree view toolbar. Default is null. + /// + [Parameter, NotNull] + public RenderFragment>? BodyTemplate { get; set; } + + /// + /// Gets or sets the title of the popup-window. Default is null. + /// + [Parameter] + public string? Title { get; set; } + + /// + /// Gets or sets the title of the popup-window. Default is null. + /// + [Parameter] + public string? Text { get; set; } + + private string? _text; + + /// + /// + /// + protected override void OnInitialized() + { + base.OnInitialized(); + + _text = Item?.Text ?? ""; + } + + private async Task OnConfirm() + { + Item.Text = _text; + + if (ItemChanged.HasDelegate) + { + await ItemChanged.InvokeAsync(Item); + } + } +} From 8516a137198ca0093ef284da4959747096dc1d09 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Fri, 14 Mar 2025 12:13:18 +0800 Subject: [PATCH 13/34] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0=20TreeViewRow?= =?UTF-8?q?=20=E7=BB=84=E4=BB=B6=E6=8F=90=E9=AB=98=E6=80=A7=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/TreeView/TreeViewRow.razor | 37 +++ .../Components/TreeView/TreeViewRow.razor.cs | 286 ++++++++++++++++++ 2 files changed, 323 insertions(+) create mode 100644 src/BootstrapBlazor/Components/TreeView/TreeViewRow.razor create mode 100644 src/BootstrapBlazor/Components/TreeView/TreeViewRow.razor.cs diff --git a/src/BootstrapBlazor/Components/TreeView/TreeViewRow.razor b/src/BootstrapBlazor/Components/TreeView/TreeViewRow.razor new file mode 100644 index 00000000000..87248873305 --- /dev/null +++ b/src/BootstrapBlazor/Components/TreeView/TreeViewRow.razor @@ -0,0 +1,37 @@ +@namespace BootstrapBlazor.Components +@typeparam TItem +@inherits ComponentBase + +
+
+
+ + + @if (ShowCheckbox) + { + + + } + + @if (ShowIcon) + { + + } + @if (Item.Template == null) + { + @Item.Text + } + else + { + @Item.Template(Item.Value) + } + @if (_showToolbar) + { + + } + +
+
diff --git a/src/BootstrapBlazor/Components/TreeView/TreeViewRow.razor.cs b/src/BootstrapBlazor/Components/TreeView/TreeViewRow.razor.cs new file mode 100644 index 00000000000..51fbdcab3f1 --- /dev/null +++ b/src/BootstrapBlazor/Components/TreeView/TreeViewRow.razor.cs @@ -0,0 +1,286 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the Apache 2.0 License +// See the LICENSE file in the project root for more information. +// Maintainer: Argo Zhang(argo@live.ca) Website: https://www.blazor.zone + +using Microsoft.AspNetCore.Components.Web; + +namespace BootstrapBlazor.Components; + +/// +/// TreeViewRow component +/// +public partial class TreeViewRow +{ + /// + /// Gets or sets whether the node is active. Default is false. + /// + [Parameter] + public bool IsActive { get; set; } + + /// + /// Gets or sets the node index. Default is 0. + /// + [Parameter] + public int Index { get; set; } + + /// + /// Gets or sets the tree node item. Default is null. + /// + [Parameter, NotNull] + public TreeViewItem? Item { get; set; } + + /// + /// Gets or sets the child content of the tree node. Default is null. + /// + [Parameter, NotNull] + public RenderFragment>? ChildContent { get; set; } + + /// + /// Gets or sets the loading icon for tree nodes. + /// + [Parameter] + public string? LoadingIcon { get; set; } + + /// + /// Gets or sets the icon for tree nodes. + /// + [Parameter] + public string? NodeIcon { get; set; } + + /// + /// Gets or sets the icon for expanded tree nodes. + /// + [Parameter] + public string? ExpandNodeIcon { get; set; } + + /// + /// Gets or sets whether the entire component is disabled. Default is false. + /// + [Parameter] + public bool IsDisabled { get; set; } + + /// + /// Gets or sets whether to show checkboxes. Default is false. + /// + [Parameter] + public bool ShowCheckbox { get; set; } + + /// + /// Gets or sets whether nodes can be expanded or collapsed when the component is disabled. Default is false. + /// + [Parameter] + public bool CanExpandWhenDisabled { get; set; } + + /// + /// Get or sets the node click event callback. + /// + [Parameter] + public Func, Task>? OnToggleNodeAsync { get; set; } + + /// + /// Get or sets the node checkbox state change event callback. + /// + [Parameter] + public Func, CheckboxState, Task>? OnCheckStateChanged { get; set; } + + /// + /// Gets or sets the maximum number of selected items. + /// + [Parameter] + public int MaxSelectedCount { get; set; } + + /// + /// Gets or sets the callback that is invoked before the node state changes. + /// + [Parameter] + public Func, CheckboxState, Task>? OnBeforeStateChangedCallback { get; set; } + + /// + /// Gets or sets whether to show icons. Default is false. + /// + [Parameter] + public bool ShowIcon { get; set; } + + /// + /// Gets or sets the click event callback. Default is null. + /// + [Parameter] + public Func, Task>? OnClick { get; set; } + + /// + /// Gets or sets whether show the toolbar of tree view item. Default is false. + /// + [Parameter] + public bool ShowToolbar { get; set; } + + /// + /// A callback method that determines whether to show the toolbar of the tree view item. + /// + [Parameter] + public Func, Task>? ShowToolbarCallback { get; set; } + + /// + /// Gets or sets the title of the popup-window. Default is null. + /// + [Parameter] + public string? ToolbarEditTitle { get; set; } + + /// + /// Gets or sets the title of the popup-window. Default is null. + /// + [Parameter] + public string? ToolbarEditLabelText { get; set; } + + [Inject] + [NotNull] + private IOptionsMonitor? Options { get; set; } + + [CascadingParameter] + private ContextMenuZone? ContextMenuZone { get; set; } + + private string? ContentClassString => CssBuilder.Default("tree-content") + .AddClass("active", IsActive) + .Build(); + + private string? CaretClassString => CssBuilder.Default("node-icon") + .AddClass("visible", Item.HasChildren || Item.Items.Count > 0) + .AddClass(NodeIcon, !Item.IsExpand) + .AddClass(ExpandNodeIcon, Item.IsExpand) + .AddClass("disabled", IsDisabled) + .Build(); + + private string? NodeLoadingClassString => CssBuilder.Default("node-icon node-loading") + .AddClass(LoadingIcon) + .Build(); + + private string? NodeClassString => CssBuilder.Default("tree-node") + .AddClass("disabled", ItemDisabledState) + .Build(); + + private string? ItemTextClassString() => CssBuilder.Default("tree-node-text") + .AddClass(Item.CssClass) + .Build(); + + private string? IconClassString() => CssBuilder.Default("tree-icon") + .AddClass(Item.Icon) + .AddClass(Item.ExpandIcon, Item.IsExpand && !string.IsNullOrEmpty(Item.ExpandIcon)) + .Build(); + + private bool IsPreventDefault => ContextMenuZone != null; + + private bool _touchStart = false; + + private bool _isBusy = false; + + private bool _showToolbar = false; + + /// + /// + /// + /// + protected override async Task OnParametersSetAsync() + { + await base.OnParametersSetAsync(); + + if (ShowToolbarCallback != null) + { + _showToolbar = await ShowToolbarCallback(Item); + } + else + { + _showToolbar = ShowToolbar; + } + } + + private async Task OnTouchStart(TouchEventArgs e) + { + if (!_isBusy && ContextMenuZone != null) + { + _isBusy = true; + _touchStart = true; + + // 延时保持 TouchStart 状态 + // keep the TouchStart state for a while + var delay = Options.CurrentValue.ContextMenuOptions.OnTouchDelay; + await Task.Delay(delay); + if (_touchStart) + { + var args = new MouseEventArgs() + { + ClientX = e.Touches[0].ClientX, + ClientY = e.Touches[0].ClientY, + ScreenX = e.Touches[0].ScreenX, + ScreenY = e.Touches[0].ScreenY, + }; + await OnContextMenu(args); + + // prevents the menu from being activated repeatedly + await Task.Delay(delay); + } + _isBusy = false; + } + } + + private void OnTouchEnd() + { + _touchStart = false; + } + + private async Task OnContextMenu(MouseEventArgs e) + { + if (ContextMenuZone != null) + { + await ContextMenuZone.OnContextMenu(e, Item.Value); + } + } + + private string? GetTreeRowStyle() + { + var level = 0; + var parent = Item.Parent; + while (parent != null) + { + level++; + parent = parent.Parent; + } + return $"--bb-tree-view-level: {level};"; + } + + private bool CanTriggerClickNode => !IsDisabled && (CanExpandWhenDisabled || !Item.IsDisabled); + + private bool ItemDisabledState => Item.IsDisabled || IsDisabled; + + private async Task ToggleNodeAsync() + { + if (OnToggleNodeAsync != null) + { + await OnToggleNodeAsync(Item); + } + } + + private async Task CheckStateChanged(CheckboxState state) + { + if (OnCheckStateChanged != null) + { + await OnCheckStateChanged(Item, state); + } + } + + private async Task TriggerBeforeStateChangedCallback(CheckboxState state) + { + if (OnBeforeStateChangedCallback != null) + { + return await OnBeforeStateChangedCallback(Item, state); + } + return true; + } + + private async Task ClickRow() + { + if (OnClick != null) + { + await OnClick(Item); + } + } +} From a782c8831082043c74d7eb9dcf8f0b0634cdaec3 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Fri, 14 Mar 2025 12:14:28 +0800 Subject: [PATCH 14/34] =?UTF-8?q?feat:=20=E4=BD=BF=E7=94=A8=20TreeViewRow?= =?UTF-8?q?=20=E7=BB=84=E4=BB=B6=E9=87=8D=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/TreeView/TreeView.razor | 59 ++------ .../Components/TreeView/TreeView.razor.cs | 139 +++--------------- 2 files changed, 37 insertions(+), 161 deletions(-) diff --git a/src/BootstrapBlazor/Components/TreeView/TreeView.razor b/src/BootstrapBlazor/Components/TreeView/TreeView.razor index 72c70bc0365..24f0f6692f3 100644 --- a/src/BootstrapBlazor/Components/TreeView/TreeView.razor +++ b/src/BootstrapBlazor/Components/TreeView/TreeView.razor @@ -49,7 +49,13 @@ else
- @RenderTreeRow(context) +
@@ -59,52 +65,15 @@ else
@foreach (var item in Rows) { - @RenderTreeRow(item) + }
} } - -@code { - private RenderFragment> RenderTreeRow => item => - @
-
-
- - - @if (ShowCheckbox) - { - - } - - @if (ShowIcon) - { - - } - @if (item.Template == null) - { - @item.Text - } - else - { - @item.Template(item.Value) - } - @RenderToolbar(item) - -
-
; - - RenderFragment> RenderToolbarContent => item => - @
- - - Label: - - - -
; -} diff --git a/src/BootstrapBlazor/Components/TreeView/TreeView.razor.cs b/src/BootstrapBlazor/Components/TreeView/TreeView.razor.cs index efd04fdbb13..ec35fd3be47 100644 --- a/src/BootstrapBlazor/Components/TreeView/TreeView.razor.cs +++ b/src/BootstrapBlazor/Components/TreeView/TreeView.razor.cs @@ -23,36 +23,8 @@ public partial class TreeView : IModelEqualityComparer .AddClassFromAttributes(AdditionalAttributes) .Build(); - private static string? GetIconClassString(TreeViewItem item) => CssBuilder.Default("tree-icon") - .AddClass(item.Icon) - .AddClass(item.ExpandIcon, item.IsExpand && !string.IsNullOrEmpty(item.ExpandIcon)) - .Build(); - - private string? GetCaretClassString(TreeViewItem item) => CssBuilder.Default("node-icon") - .AddClass("visible", item.HasChildren || item.Items.Count > 0) - .AddClass(NodeIcon, !item.IsExpand) - .AddClass(ExpandNodeIcon, item.IsExpand) - .AddClass("disabled", IsDisabled || (!CanExpandWhenDisabled && item.IsDisabled)) - .Build(); - - private string? NodeLoadingClassString => CssBuilder.Default("node-icon node-loading") - .AddClass(LoadingIcon) - .Build(); - - private string? GetContentClassString(TreeViewItem item) => CssBuilder.Default("tree-content") - .AddClass("active", _activeItem == item) - .Build(); - - private string? GetNodeClassString(TreeViewItem item) => CssBuilder.Default("tree-node") - .AddClass("disabled", GetItemDisabledState(item)) - .Build(); - private bool CanTriggerClickNode(TreeViewItem item) => !IsDisabled && (CanExpandWhenDisabled || !item.IsDisabled); - private bool TriggerNodeLabel(TreeViewItem item) => !GetItemDisabledState(item); - - private bool GetItemDisabledState(TreeViewItem item) => item.IsDisabled || IsDisabled; - private TreeViewItem? _activeItem; /// @@ -274,8 +246,17 @@ public partial class TreeView : IModelEqualityComparer [Parameter] public Func, Task>? OnUpdateTreeNodeAsync { get; set; } - [CascadingParameter] - private ContextMenuZone? ContextMenuZone { get; set; } + /// + /// Gets or sets the title of the popup-window. Default is null. + /// + [Parameter] + public string? ToolbarEditTitle { get; set; } + + /// + /// Gets or sets the title of the popup-window. Default is null. + /// + [Parameter] + public string? ToolbarEditLabelText { get; set; } [NotNull] private string? NotSetOnTreeExpandErrorMessage { get; set; } @@ -288,10 +269,6 @@ public partial class TreeView : IModelEqualityComparer [NotNull] private IIconTheme? IconTheme { get; set; } - [Inject] - [NotNull] - private IOptionsMonitor? Options { get; set; } - [NotNull] private TreeNodeCache, TItem>? _treeNodeStateCache = null; @@ -313,10 +290,6 @@ public partial class TreeView : IModelEqualityComparer private bool _shouldRender = true; - private static string? GetItemTextClassString(TreeViewItem item) => CssBuilder.Default("tree-node-text") - .AddClass(item.CssClass) - .Build(); - private bool _init; /// @@ -328,6 +301,8 @@ protected override void OnInitialized() _treeNodeStateCache = new(this); NotSetOnTreeExpandErrorMessage = Localizer[nameof(NotSetOnTreeExpandErrorMessage)]; + ToolbarEditTitle = Localizer[nameof(ToolbarEditTitle)]; + ToolbarEditLabelText = Localizer[nameof(ToolbarEditLabelText)]; } /// @@ -430,7 +405,7 @@ public async ValueTask TriggerKeyDown(string key) } else if (key == "ArrowLeft" || key == "ArrowRight") { - await OnToggleNodeAsync(_activeItem, true); + await OnToggleNodeAsync(_activeItem); } } } @@ -575,7 +550,7 @@ private async Task OnClick(TreeViewItem item) _activeItem = item; if (ClickToggleNode && CanTriggerClickNode(item)) { - await OnToggleNodeAsync(item, false); + await OnToggleNodeAsync(item); } if (OnTreeItemClick != null) @@ -660,8 +635,7 @@ public void SetActiveItem(TItem item) /// Toggle node expand collapse state method /// /// - /// - private async Task OnToggleNodeAsync(TreeViewItem node, bool shouldRender) + private async Task OnToggleNodeAsync(TreeViewItem node) { // 手风琴效果逻辑 node.IsExpand = !node.IsExpand; @@ -706,11 +680,7 @@ private async Task OnToggleNodeAsync(TreeViewItem node, bool shouldRender node.Items[0].SetParentCheck(_treeNodeStateCache); } } - - if (shouldRender) - { - StateHasChanged(); - } + StateHasChanged(); } private async Task OnCheckStateChanged(TreeViewItem item, CheckboxState state) @@ -778,54 +748,6 @@ public IEnumerable> GetCheckedItems() => Items.Aggregate(new /// public bool Equals(TItem? x, TItem? y) => this.Equals(x, y); - private async Task OnContextMenu(MouseEventArgs e, TreeViewItem item) - { - if (ContextMenuZone != null) - { - await ContextMenuZone.OnContextMenu(e, item.Value); - } - } - - private bool IsPreventDefault => ContextMenuZone != null; - - private bool _touchStart = false; - - private bool _isBusy = false; - - private async Task OnTouchStart(TouchEventArgs e, TreeViewItem item) - { - if (!_isBusy && ContextMenuZone != null) - { - _isBusy = true; - _touchStart = true; - - // 延时保持 TouchStart 状态 - // keep the TouchStart state for a while - var delay = Options.CurrentValue.ContextMenuOptions.OnTouchDelay; - await Task.Delay(delay); - if (_touchStart) - { - var args = new MouseEventArgs() - { - ClientX = e.Touches[0].ClientX, - ClientY = e.Touches[0].ClientY, - ScreenX = e.Touches[0].ScreenX, - ScreenY = e.Touches[0].ScreenY, - }; - await OnContextMenu(args, item); - - // prevents the menu from being activated repeatedly - await Task.Delay(delay); - } - _isBusy = false; - } - } - - private void OnTouchEnd() - { - _touchStart = false; - } - private List>? _rows = null; private List> Rows @@ -839,27 +761,6 @@ private List> Rows private List> GetTreeItems() => _searchItems ?? Items; - private static string? GetTreeRowStyle(TreeViewItem item) - { - var level = 0; - var parent = item.Parent; - while (parent != null) - { - level++; - parent = parent.Parent; - } - return $"--bb-tree-view-level: {level};"; - } - - private RenderFragment RenderToolbar(TreeViewItem item) => builder => - { - builder.OpenComponent>(0); - builder.AddAttribute(10, nameof(TreeViewToolbar.Item), item); - builder.AddAttribute(20, nameof(TreeViewToolbar.ShowToolbarAsync), ShowTollbarAsync); - builder.AddAttribute(30, nameof(TreeViewToolbar.ChildContent), RenderToolbarContent); - builder.CloseComponent(); - }; - private async Task ShowTollbarAsync(TreeViewItem item) { if (ShowToolbarCallback != null) @@ -873,4 +774,10 @@ private async Task OnUpdateItemAsync(TreeViewItem item) { } + + private bool GetActive(TreeViewItem item) => _activeItem == item; + + private int GetIndex(TreeViewItem item) => Rows.IndexOf(item); + + private bool GetDisabled(TreeViewItem item) => IsDisabled || (!CanExpandWhenDisabled && item.IsDisabled); } From 3238187ba6bdcc0f738ce1087ac13c8e7cc4bf94 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Fri, 14 Mar 2025 14:23:04 +0800 Subject: [PATCH 15/34] =?UTF-8?q?refactor:=20=E9=87=8D=E6=9E=84=E4=BB=A3?= =?UTF-8?q?=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/TreeView/TreeView.razor | 32 +++++++++---------- .../Components/TreeView/TreeView.razor.cs | 27 ++++------------ .../Components/TreeView/TreeViewRow.razor | 3 +- .../Components/TreeView/TreeViewRow.razor.cs | 13 ++++++++ .../Components/TreeView/TreeViewToolbar.razor | 2 +- .../TreeView/TreeViewToolbar.razor.cs | 31 ++++++++++++++---- .../TreeView/TreeViewToolbarContext.cs | 24 ++++++++++++++ 7 files changed, 85 insertions(+), 47 deletions(-) create mode 100644 src/BootstrapBlazor/Components/TreeView/TreeViewToolbarContext.cs diff --git a/src/BootstrapBlazor/Components/TreeView/TreeView.razor b/src/BootstrapBlazor/Components/TreeView/TreeView.razor index 24f0f6692f3..012ed6fcae0 100644 --- a/src/BootstrapBlazor/Components/TreeView/TreeView.razor +++ b/src/BootstrapBlazor/Components/TreeView/TreeView.razor @@ -8,7 +8,7 @@ { if (_init) { - + } else if (ShowSkeleton) { @@ -48,15 +48,7 @@ else {
- - - + @RenderRow(context)
} @@ -65,15 +57,21 @@ else
@foreach (var item in Rows) { - + @RenderRow(item) }
} } + +@code { + RenderFragment RenderRow(TreeViewItem item) => + @; +} diff --git a/src/BootstrapBlazor/Components/TreeView/TreeView.razor.cs b/src/BootstrapBlazor/Components/TreeView/TreeView.razor.cs index ec35fd3be47..e19f82256b9 100644 --- a/src/BootstrapBlazor/Components/TreeView/TreeView.razor.cs +++ b/src/BootstrapBlazor/Components/TreeView/TreeView.razor.cs @@ -241,22 +241,23 @@ public partial class TreeView : IModelEqualityComparer public RenderFragment? ToolbarTemplate { get; set; } /// - /// Gets or sets the callback method when a tree item is updated. + /// Gets or sets the title of the popup-window. Default is null. /// [Parameter] - public Func, Task>? OnUpdateTreeNodeAsync { get; set; } + public string? ToolbarEditTitle { get; set; } /// /// Gets or sets the title of the popup-window. Default is null. /// [Parameter] - public string? ToolbarEditTitle { get; set; } + public string? ToolbarEditLabelText { get; set; } /// - /// Gets or sets the title of the popup-window. Default is null. + /// Gets or sets the update the tree text value callback. Default is null. + /// If return true will update the tree text value, otherwise will not update. /// [Parameter] - public string? ToolbarEditLabelText { get; set; } + public Func, Task>? OnUpdateCallbackAsync { get; set; } [NotNull] private string? NotSetOnTreeExpandErrorMessage { get; set; } @@ -761,23 +762,7 @@ private List> Rows private List> GetTreeItems() => _searchItems ?? Items; - private async Task ShowTollbarAsync(TreeViewItem item) - { - if (ShowToolbarCallback != null) - { - return await ShowToolbarCallback(item); - } - return ShowToolbar; - } - - private async Task OnUpdateItemAsync(TreeViewItem item) - { - - } - private bool GetActive(TreeViewItem item) => _activeItem == item; private int GetIndex(TreeViewItem item) => Rows.IndexOf(item); - - private bool GetDisabled(TreeViewItem item) => IsDisabled || (!CanExpandWhenDisabled && item.IsDisabled); } diff --git a/src/BootstrapBlazor/Components/TreeView/TreeViewRow.razor b/src/BootstrapBlazor/Components/TreeView/TreeViewRow.razor index 87248873305..bf059e4bfe7 100644 --- a/src/BootstrapBlazor/Components/TreeView/TreeViewRow.razor +++ b/src/BootstrapBlazor/Components/TreeView/TreeViewRow.razor @@ -30,7 +30,8 @@ } @if (_showToolbar) { - + } diff --git a/src/BootstrapBlazor/Components/TreeView/TreeViewRow.razor.cs b/src/BootstrapBlazor/Components/TreeView/TreeViewRow.razor.cs index 51fbdcab3f1..c1206f99912 100644 --- a/src/BootstrapBlazor/Components/TreeView/TreeViewRow.razor.cs +++ b/src/BootstrapBlazor/Components/TreeView/TreeViewRow.razor.cs @@ -132,6 +132,19 @@ public partial class TreeViewRow [Parameter] public string? ToolbarEditLabelText { get; set; } + /// + /// Gets or sets the toolbar content template. Default is null. + /// + [Parameter] + public RenderFragment? ToolbarTemplate { get; set; } + + /// + /// Gets or sets the update the tree text value callback. Default is null. + /// If return true will update the tree text value, otherwise will not update. + /// + [Parameter] + public Func, Task>? OnUpdateCallbackAsync { get; set; } + [Inject] [NotNull] private IOptionsMonitor? Options { get; set; } diff --git a/src/BootstrapBlazor/Components/TreeView/TreeViewToolbar.razor b/src/BootstrapBlazor/Components/TreeView/TreeViewToolbar.razor index 4b9b6ea53ce..d338d65e9c2 100644 --- a/src/BootstrapBlazor/Components/TreeView/TreeViewToolbar.razor +++ b/src/BootstrapBlazor/Components/TreeView/TreeViewToolbar.razor @@ -7,7 +7,7 @@ @if (BodyTemplate != null) { - @BodyTemplate(Item) + @BodyTemplate(Item.Value) } else { diff --git a/src/BootstrapBlazor/Components/TreeView/TreeViewToolbar.razor.cs b/src/BootstrapBlazor/Components/TreeView/TreeViewToolbar.razor.cs index 8d1adec3073..6f1b307a744 100644 --- a/src/BootstrapBlazor/Components/TreeView/TreeViewToolbar.razor.cs +++ b/src/BootstrapBlazor/Components/TreeView/TreeViewToolbar.razor.cs @@ -23,11 +23,18 @@ public partial class TreeViewToolbar : ComponentBase [Parameter] public EventCallback> ItemChanged { get; set; } + /// + /// Gets or sets the update the tree text value callback. Default is null. + /// If return true will update the tree text value, otherwise will not update. + /// + [Parameter] + public Func, Task>? OnUpdateCallbackAsync { get; set; } + /// /// Gets or sets the child content of the tree view toolbar. Default is null. /// [Parameter, NotNull] - public RenderFragment>? BodyTemplate { get; set; } + public RenderFragment? BodyTemplate { get; set; } /// /// Gets or sets the title of the popup-window. Default is null. @@ -46,20 +53,30 @@ public partial class TreeViewToolbar : ComponentBase /// /// /// - protected override void OnInitialized() + protected override void OnParametersSet() { - base.OnInitialized(); + base.OnParametersSet(); - _text = Item?.Text ?? ""; + _text = Item.Text; } private async Task OnConfirm() { - Item.Text = _text; + var ret = true; + if (OnUpdateCallbackAsync != null) + { + var to = Utility.Clone(Item.Value); + var context = new TreeViewToolbarContext(Item.Value, to); + await OnUpdateCallbackAsync(context); + } - if (ItemChanged.HasDelegate) + if (ret) { - await ItemChanged.InvokeAsync(Item); + Item.Text = _text; + if (ItemChanged.HasDelegate) + { + await ItemChanged.InvokeAsync(Item); + } } } } diff --git a/src/BootstrapBlazor/Components/TreeView/TreeViewToolbarContext.cs b/src/BootstrapBlazor/Components/TreeView/TreeViewToolbarContext.cs new file mode 100644 index 00000000000..7addd8e7fb2 --- /dev/null +++ b/src/BootstrapBlazor/Components/TreeView/TreeViewToolbarContext.cs @@ -0,0 +1,24 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the Apache 2.0 License +// See the LICENSE file in the project root for more information. +// Maintainer: Argo Zhang(argo@live.ca) Website: https://www.blazor.zone + +namespace BootstrapBlazor.Components; + +/// +/// TreeViewToolbarContext class +/// +/// +/// +public class TreeViewToolbarContext(TItem from, TItem to) +{ + /// + /// Gets or sets the origin tree view item + /// + public TItem? From { get; set; } = from; + + /// + /// Gets or sets the new tree view item + /// + public TItem? To { get; set; } = to; +} From b8f6398b26a590a069e52951758c8346b84a9fd8 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Fri, 14 Mar 2025 14:30:01 +0800 Subject: [PATCH 16/34] =?UTF-8?q?refactor:=20=E6=9B=B4=E6=96=B0=E9=80=BB?= =?UTF-8?q?=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/BootstrapBlazor/Components/TreeView/TreeView.razor.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/BootstrapBlazor/Components/TreeView/TreeView.razor.cs b/src/BootstrapBlazor/Components/TreeView/TreeView.razor.cs index e19f82256b9..bbcf00b5a67 100644 --- a/src/BootstrapBlazor/Components/TreeView/TreeView.razor.cs +++ b/src/BootstrapBlazor/Components/TreeView/TreeView.razor.cs @@ -302,8 +302,8 @@ protected override void OnInitialized() _treeNodeStateCache = new(this); NotSetOnTreeExpandErrorMessage = Localizer[nameof(NotSetOnTreeExpandErrorMessage)]; - ToolbarEditTitle = Localizer[nameof(ToolbarEditTitle)]; - ToolbarEditLabelText = Localizer[nameof(ToolbarEditLabelText)]; + ToolbarEditTitle ??= Localizer[nameof(ToolbarEditTitle)]; + ToolbarEditLabelText ??= Localizer[nameof(ToolbarEditLabelText)]; } /// From 970a097b747833305da11992f893ce8b83e1a51b Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Fri, 14 Mar 2025 14:39:28 +0800 Subject: [PATCH 17/34] =?UTF-8?q?style:=20=E5=A2=9E=E5=8A=A0=E5=86=85?= =?UTF-8?q?=E7=BD=AE=E6=A8=A1=E6=9D=BF=E6=A0=B7=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/TreeView/TreeView.razor.scss | 16 ++++++++++++++++ .../Components/TreeView/TreeViewToolbar.razor | 6 ++++-- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/src/BootstrapBlazor/Components/TreeView/TreeView.razor.scss b/src/BootstrapBlazor/Components/TreeView/TreeView.razor.scss index f8dd8ebf071..6e92820d4cf 100644 --- a/src/BootstrapBlazor/Components/TreeView/TreeView.razor.scss +++ b/src/BootstrapBlazor/Components/TreeView/TreeView.razor.scss @@ -150,3 +150,19 @@ } } } + +.tree-view-edit-form { + display: flex; + + > span { + display: flex; + align-items: center; + margin-inline-end: 0.25rem; + + & + * { + flex: 1; + width: 1%; + min-width: 0; + } + } +} diff --git a/src/BootstrapBlazor/Components/TreeView/TreeViewToolbar.razor b/src/BootstrapBlazor/Components/TreeView/TreeViewToolbar.razor index d338d65e9c2..f8448ce8888 100644 --- a/src/BootstrapBlazor/Components/TreeView/TreeViewToolbar.razor +++ b/src/BootstrapBlazor/Components/TreeView/TreeViewToolbar.razor @@ -11,8 +11,10 @@ } else { - - +
+ @Text + +
} From beb683cd26dc7f52e346328889a55592a0b14bd7 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Fri, 14 Mar 2025 14:49:26 +0800 Subject: [PATCH 18/34] =?UTF-8?q?refactor:=20=E6=9B=B4=E6=96=B0=20OnUpdate?= =?UTF-8?q?CallbackAsync=20=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/BootstrapBlazor/Components/TreeView/TreeView.razor.cs | 2 +- .../Components/TreeView/TreeViewRow.razor.cs | 2 +- .../Components/TreeView/TreeViewToolbar.razor.cs | 6 ++---- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/BootstrapBlazor/Components/TreeView/TreeView.razor.cs b/src/BootstrapBlazor/Components/TreeView/TreeView.razor.cs index bbcf00b5a67..1f33071b7f0 100644 --- a/src/BootstrapBlazor/Components/TreeView/TreeView.razor.cs +++ b/src/BootstrapBlazor/Components/TreeView/TreeView.razor.cs @@ -257,7 +257,7 @@ public partial class TreeView : IModelEqualityComparer /// If return true will update the tree text value, otherwise will not update. ///
[Parameter] - public Func, Task>? OnUpdateCallbackAsync { get; set; } + public Func>? OnUpdateCallbackAsync { get; set; } [NotNull] private string? NotSetOnTreeExpandErrorMessage { get; set; } diff --git a/src/BootstrapBlazor/Components/TreeView/TreeViewRow.razor.cs b/src/BootstrapBlazor/Components/TreeView/TreeViewRow.razor.cs index c1206f99912..5222b17b505 100644 --- a/src/BootstrapBlazor/Components/TreeView/TreeViewRow.razor.cs +++ b/src/BootstrapBlazor/Components/TreeView/TreeViewRow.razor.cs @@ -143,7 +143,7 @@ public partial class TreeViewRow /// If return true will update the tree text value, otherwise will not update. ///
[Parameter] - public Func, Task>? OnUpdateCallbackAsync { get; set; } + public Func>? OnUpdateCallbackAsync { get; set; } [Inject] [NotNull] diff --git a/src/BootstrapBlazor/Components/TreeView/TreeViewToolbar.razor.cs b/src/BootstrapBlazor/Components/TreeView/TreeViewToolbar.razor.cs index 6f1b307a744..a5a7dc9325e 100644 --- a/src/BootstrapBlazor/Components/TreeView/TreeViewToolbar.razor.cs +++ b/src/BootstrapBlazor/Components/TreeView/TreeViewToolbar.razor.cs @@ -28,7 +28,7 @@ public partial class TreeViewToolbar : ComponentBase /// If return true will update the tree text value, otherwise will not update. ///
[Parameter] - public Func, Task>? OnUpdateCallbackAsync { get; set; } + public Func>? OnUpdateCallbackAsync { get; set; } /// /// Gets or sets the child content of the tree view toolbar. Default is null. @@ -65,9 +65,7 @@ private async Task OnConfirm() var ret = true; if (OnUpdateCallbackAsync != null) { - var to = Utility.Clone(Item.Value); - var context = new TreeViewToolbarContext(Item.Value, to); - await OnUpdateCallbackAsync(context); + ret = await OnUpdateCallbackAsync(Item.Value, _text); } if (ret) From 4a525ddb716671f9b376929c544efa0e05fa8f15 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Fri, 14 Mar 2025 14:54:25 +0800 Subject: [PATCH 19/34] =?UTF-8?q?refactor:=20=E6=9B=B4=E6=94=B9=E4=B8=BA?= =?UTF-8?q?=20ToolbarEditButton=20=E7=BB=84=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/TreeView/TreeView.razor.scss | 4 ++-- .../Components/TreeView/TreeViewRow.razor | 17 +++++++++---- .../Components/TreeView/TreeViewToolbar.razor | 21 ---------------- .../TreeView/TreeViewToolbarContext.cs | 24 ------------------- .../TreeView/TreeViewToolbarEditButton.razor | 14 +++++++++++ ....cs => TreeViewToolbarEditButton.razor.cs} | 10 ++------ 6 files changed, 30 insertions(+), 60 deletions(-) delete mode 100644 src/BootstrapBlazor/Components/TreeView/TreeViewToolbar.razor delete mode 100644 src/BootstrapBlazor/Components/TreeView/TreeViewToolbarContext.cs create mode 100644 src/BootstrapBlazor/Components/TreeView/TreeViewToolbarEditButton.razor rename src/BootstrapBlazor/Components/TreeView/{TreeViewToolbar.razor.cs => TreeViewToolbarEditButton.razor.cs} (87%) diff --git a/src/BootstrapBlazor/Components/TreeView/TreeView.razor.scss b/src/BootstrapBlazor/Components/TreeView/TreeView.razor.scss index 6e92820d4cf..7774e60a701 100644 --- a/src/BootstrapBlazor/Components/TreeView/TreeView.razor.scss +++ b/src/BootstrapBlazor/Components/TreeView/TreeView.razor.scss @@ -137,7 +137,7 @@ opacity: var(--bb-tree-disabled-opacity); } - .tree-node-toolbar { + .tree-node-toolbar-edit { position: absolute; right: 0; height: 100%; @@ -145,7 +145,7 @@ align-items: center; } - &:not(:hover) .tree-node-toolbar { + &:not(:hover) .tree-node-toolbar-edit { display: none; } } diff --git a/src/BootstrapBlazor/Components/TreeView/TreeViewRow.razor b/src/BootstrapBlazor/Components/TreeView/TreeViewRow.razor index bf059e4bfe7..7cefff7ff8d 100644 --- a/src/BootstrapBlazor/Components/TreeView/TreeViewRow.razor +++ b/src/BootstrapBlazor/Components/TreeView/TreeViewRow.razor @@ -10,9 +10,9 @@ @if (ShowCheckbox) { + SkipValidate="true" ShowLabel="false" ShowAfterLabel="false" + State="@Item.CheckedState" OnStateChanged="(state, v) => CheckStateChanged(state)" + OnBeforeStateChanged="@(MaxSelectedCount > 0 ? state => TriggerBeforeStateChangedCallback(state) : null)"> } @@ -30,8 +30,15 @@ } @if (_showToolbar) { - + @if (ToolbarTemplate != null) + { + @ToolbarTemplate(Item.Value) + } + else + { + + } } diff --git a/src/BootstrapBlazor/Components/TreeView/TreeViewToolbar.razor b/src/BootstrapBlazor/Components/TreeView/TreeViewToolbar.razor deleted file mode 100644 index f8448ce8888..00000000000 --- a/src/BootstrapBlazor/Components/TreeView/TreeViewToolbar.razor +++ /dev/null @@ -1,21 +0,0 @@ -@namespace BootstrapBlazor.Components -@typeparam TItem -@inherits ComponentBase - -
- - - @if (BodyTemplate != null) - { - @BodyTemplate(Item.Value) - } - else - { -
- @Text - -
- } -
-
-
diff --git a/src/BootstrapBlazor/Components/TreeView/TreeViewToolbarContext.cs b/src/BootstrapBlazor/Components/TreeView/TreeViewToolbarContext.cs deleted file mode 100644 index 7addd8e7fb2..00000000000 --- a/src/BootstrapBlazor/Components/TreeView/TreeViewToolbarContext.cs +++ /dev/null @@ -1,24 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the Apache 2.0 License -// See the LICENSE file in the project root for more information. -// Maintainer: Argo Zhang(argo@live.ca) Website: https://www.blazor.zone - -namespace BootstrapBlazor.Components; - -/// -/// TreeViewToolbarContext class -/// -/// -/// -public class TreeViewToolbarContext(TItem from, TItem to) -{ - /// - /// Gets or sets the origin tree view item - /// - public TItem? From { get; set; } = from; - - /// - /// Gets or sets the new tree view item - /// - public TItem? To { get; set; } = to; -} diff --git a/src/BootstrapBlazor/Components/TreeView/TreeViewToolbarEditButton.razor b/src/BootstrapBlazor/Components/TreeView/TreeViewToolbarEditButton.razor new file mode 100644 index 00000000000..8ab219092fb --- /dev/null +++ b/src/BootstrapBlazor/Components/TreeView/TreeViewToolbarEditButton.razor @@ -0,0 +1,14 @@ +@namespace BootstrapBlazor.Components +@typeparam TItem +@inherits ComponentBase + +
+ + +
+ @Text + +
+
+
+
diff --git a/src/BootstrapBlazor/Components/TreeView/TreeViewToolbar.razor.cs b/src/BootstrapBlazor/Components/TreeView/TreeViewToolbarEditButton.razor.cs similarity index 87% rename from src/BootstrapBlazor/Components/TreeView/TreeViewToolbar.razor.cs rename to src/BootstrapBlazor/Components/TreeView/TreeViewToolbarEditButton.razor.cs index a5a7dc9325e..247c48e207e 100644 --- a/src/BootstrapBlazor/Components/TreeView/TreeViewToolbar.razor.cs +++ b/src/BootstrapBlazor/Components/TreeView/TreeViewToolbarEditButton.razor.cs @@ -6,10 +6,10 @@ namespace BootstrapBlazor.Components; /// -/// TreeViewToolbar component +/// TreeViewToolbarEditButton component /// /// -public partial class TreeViewToolbar : ComponentBase +public partial class TreeViewToolbarEditButton : ComponentBase { /// /// Gets or sets the tree view item. Default is null. @@ -30,12 +30,6 @@ public partial class TreeViewToolbar : ComponentBase [Parameter] public Func>? OnUpdateCallbackAsync { get; set; } - /// - /// Gets or sets the child content of the tree view toolbar. Default is null. - /// - [Parameter, NotNull] - public RenderFragment? BodyTemplate { get; set; } - /// /// Gets or sets the title of the popup-window. Default is null. /// From 755b86ce118a890bd3a2e53b1ecd53163fb64c25 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Fri, 14 Mar 2025 15:05:49 +0800 Subject: [PATCH 20/34] =?UTF-8?q?doc:=20=E6=9B=B4=E6=96=B0=E7=A4=BA?= =?UTF-8?q?=E4=BE=8B=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/Samples/TreeViews.razor | 10 ++++++++++ .../Components/Samples/TreeViews.razor.cs | 8 ++++++++ src/BootstrapBlazor.Server/Locales/en-US.json | 5 ++++- src/BootstrapBlazor.Server/Locales/zh-CN.json | 5 ++++- 4 files changed, 26 insertions(+), 2 deletions(-) diff --git a/src/BootstrapBlazor.Server/Components/Samples/TreeViews.razor b/src/BootstrapBlazor.Server/Components/Samples/TreeViews.razor index 0bf1f8298c5..53beb0200ca 100644 --- a/src/BootstrapBlazor.Server/Components/Samples/TreeViews.razor +++ b/src/BootstrapBlazor.Server/Components/Samples/TreeViews.razor @@ -203,6 +203,16 @@ + +
+

@((MarkupString)Localizer["TreeViewShowToolbarDesc"].Value)

+
+ + +
+ diff --git a/src/BootstrapBlazor.Server/Components/Samples/TreeViews.razor.cs b/src/BootstrapBlazor.Server/Components/Samples/TreeViews.razor.cs index 45fdeba725e..9745d90689f 100644 --- a/src/BootstrapBlazor.Server/Components/Samples/TreeViews.razor.cs +++ b/src/BootstrapBlazor.Server/Components/Samples/TreeViews.razor.cs @@ -30,6 +30,8 @@ public sealed partial class TreeViews private List> Items { get; } = TreeFoo.GetTreeItems(); + private List> EditItems { get; } = TreeFoo.GetTreeItems(); + private bool AutoCheckChildren { get; set; } private bool AutoCheckParent { get; set; } @@ -218,6 +220,12 @@ private static async Task>> OnExpandVirtualNod return items; } + private Task OnUpdateCallbackAsync(TreeFoo foo, string? text) + { + foo.Text = text; + return Task.FromResult(true); + } + /// /// 获得属性方法 /// diff --git a/src/BootstrapBlazor.Server/Locales/en-US.json b/src/BootstrapBlazor.Server/Locales/en-US.json index 80eede68798..b9af6258e8f 100644 --- a/src/BootstrapBlazor.Server/Locales/en-US.json +++ b/src/BootstrapBlazor.Server/Locales/en-US.json @@ -711,7 +711,10 @@ "TreeViewEnableKeyboardArrowUpDownIntro": "Support keyboard up and down arrow operations by setting EnableKeyboardArrowUpDown=\"true\". ArrowLeft collapse the node, ArrowRight expand the node, ArrowUp move the node up, ArrowDown move the node down, Space select the node,", "TreeViewVirtualizeTitle": "Virtualize", "TreeViewVirtualizeIntro": "Enable virtual scrolling by setting IsVirtualize=\"true\" to support big data", - "TreeViewVirtualizeDescription": "The component uses Virtualize to implement virtual scrolling logic, which reduces the pressure on the browser. However, if there is a lot of tree structure data, such as Select All, all data must be marked, resulting in large data in the memory. This problem has not been solved yet. Currently, this component still puts a lot of pressure on the CPU due to large data." + "TreeViewVirtualizeDescription": "The component uses Virtualize to implement virtual scrolling logic, which reduces the pressure on the browser. However, if there is a lot of tree structure data, such as Select All, all data must be marked, resulting in large data in the memory. This problem has not been solved yet. Currently, this component still puts a lot of pressure on the CPU due to large data.", + "TreeViewShowToolbarTitle": "Show Toolbar", + "TreeViewShowToolbarIntro": "Show the toolbar by setting ShowToolbar=\"true\"", + "TreeViewShowToolbarDesc": "After it is turned on, when the mouse hovers over a node, a toolbar icon appears on the right, and the toolbar function can be customized; data is updated by setting the OnUpdateCallbackAsync callback method; the toolbar template is defined by setting ToolbarTemplate, and if not set, the internal default node name template is used" }, "BootstrapBlazor.Server.Components.Samples.SwitchButtons": { "SwitchButtonsTitle": "Switch Button state switch button", diff --git a/src/BootstrapBlazor.Server/Locales/zh-CN.json b/src/BootstrapBlazor.Server/Locales/zh-CN.json index 49ef713068a..9f0918a687f 100644 --- a/src/BootstrapBlazor.Server/Locales/zh-CN.json +++ b/src/BootstrapBlazor.Server/Locales/zh-CN.json @@ -711,7 +711,10 @@ "TreeViewEnableKeyboardArrowUpDownIntro": "通过设置 EnableKeyboardArrowUpDown=\"true\" 支持键盘上下箭头操作。左箭头 收起节点,右箭头 展开节点,上箭头 向上移动节点,下箭头 向下移动节点,空格 选中节点", "TreeViewVirtualizeTitle": "虚拟滚动", "TreeViewVirtualizeIntro": "通过设置 IsVirtualize=\"true\" 开启虚拟滚动,支持大数据", - "TreeViewVirtualizeDescription": "组件内部使用 Virtualize 来实现虚拟滚动逻辑,对浏览器压力会减少很多;但是如果树状结构数据比较多,比如 全选 等操作必须对所有数据进行标记,导致内存中确实有大数据存在,目前还没有解决这个问题,目前此组件由于大数据对 CPU 压力还是比较大的" + "TreeViewVirtualizeDescription": "组件内部使用 Virtualize 来实现虚拟滚动逻辑,对浏览器压力会减少很多;但是如果树状结构数据比较多,比如 全选 等操作必须对所有数据进行标记,导致内存中确实有大数据存在,目前还没有解决这个问题,目前此组件由于大数据对 CPU 压力还是比较大的", + "TreeViewShowToolbarTitle": "显示工具栏", + "TreeViewShowToolbarIntro": "通过设置 ShowToolbar=\"true\" 显示工具栏", + "TreeViewShowToolbarDesc": "开启后鼠标悬浮节点时,右侧出现工具栏图标,可自定义工具栏功能;通过设置 OnUpdateCallbackAsync 回调方法进行数据的更新;通过设置 ToolbarTemplate 定义工具栏模板,如未设置时使用内部默认更改节点名称模板" }, "BootstrapBlazor.Server.Components.Samples.SwitchButtons": { "SwitchButtonsTitle": "Switch Button 状态切换按钮", From 37cab7b31bb643e267886ee11a939a6841fb0f97 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Fri, 14 Mar 2025 15:23:46 +0800 Subject: [PATCH 21/34] =?UTF-8?q?refactor:=20=E5=A2=9E=E5=8A=A0=20NodeIcon?= =?UTF-8?q?=20ExpandNodeIcon=20=E5=8F=82=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/BootstrapBlazor/Components/TreeView/TreeView.razor | 1 + 1 file changed, 1 insertion(+) diff --git a/src/BootstrapBlazor/Components/TreeView/TreeView.razor b/src/BootstrapBlazor/Components/TreeView/TreeView.razor index 012ed6fcae0..4dcfee48672 100644 --- a/src/BootstrapBlazor/Components/TreeView/TreeView.razor +++ b/src/BootstrapBlazor/Components/TreeView/TreeView.razor @@ -67,6 +67,7 @@ else @code { RenderFragment RenderRow(TreeViewItem item) => @ Date: Fri, 14 Mar 2025 15:23:54 +0800 Subject: [PATCH 22/34] =?UTF-8?q?doc:=20=E6=A0=BC=E5=BC=8F=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/BootstrapBlazor/Components/TreeView/TreeViewRow.razor | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/BootstrapBlazor/Components/TreeView/TreeViewRow.razor b/src/BootstrapBlazor/Components/TreeView/TreeViewRow.razor index 7cefff7ff8d..cf24e05efdf 100644 --- a/src/BootstrapBlazor/Components/TreeView/TreeViewRow.razor +++ b/src/BootstrapBlazor/Components/TreeView/TreeViewRow.razor @@ -10,9 +10,9 @@ @if (ShowCheckbox) { + SkipValidate="true" ShowLabel="false" ShowAfterLabel="false" + State="@Item.CheckedState" OnStateChanged="(state, v) => CheckStateChanged(state)" + OnBeforeStateChanged="@(MaxSelectedCount > 0 ? state => TriggerBeforeStateChangedCallback(state) : null)"> } From 8fd05830bde5cf1a0a4b4b4e2a475724c10934c3 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Fri, 14 Mar 2025 15:24:03 +0800 Subject: [PATCH 23/34] =?UTF-8?q?refactor:=20=E6=9B=B4=E6=94=B9=E4=B8=BA?= =?UTF-8?q?=E5=B1=9E=E6=80=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/BootstrapBlazor/Components/TreeView/TreeViewRow.razor.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/BootstrapBlazor/Components/TreeView/TreeViewRow.razor.cs b/src/BootstrapBlazor/Components/TreeView/TreeViewRow.razor.cs index 5222b17b505..f052ffb248f 100644 --- a/src/BootstrapBlazor/Components/TreeView/TreeViewRow.razor.cs +++ b/src/BootstrapBlazor/Components/TreeView/TreeViewRow.razor.cs @@ -171,11 +171,11 @@ public partial class TreeViewRow .AddClass("disabled", ItemDisabledState) .Build(); - private string? ItemTextClassString() => CssBuilder.Default("tree-node-text") + private string? ItemTextClassString => CssBuilder.Default("tree-node-text") .AddClass(Item.CssClass) .Build(); - private string? IconClassString() => CssBuilder.Default("tree-icon") + private string? IconClassString => CssBuilder.Default("tree-icon") .AddClass(Item.Icon) .AddClass(Item.ExpandIcon, Item.IsExpand && !string.IsNullOrEmpty(Item.ExpandIcon)) .Build(); From 96dca2c5c91530fc73f937cdf4a32280cdef6b07 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Fri, 14 Mar 2025 15:30:22 +0800 Subject: [PATCH 24/34] =?UTF-8?q?refactor:=20=E5=A2=9E=E5=8A=A0=20OnCheckS?= =?UTF-8?q?tateChanged=20=E5=9B=9E=E8=B0=83=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/BootstrapBlazor/Components/TreeView/TreeView.razor | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/BootstrapBlazor/Components/TreeView/TreeView.razor b/src/BootstrapBlazor/Components/TreeView/TreeView.razor index 4dcfee48672..5738cd2ab2c 100644 --- a/src/BootstrapBlazor/Components/TreeView/TreeView.razor +++ b/src/BootstrapBlazor/Components/TreeView/TreeView.razor @@ -67,12 +67,13 @@ else @code { RenderFragment RenderRow(TreeViewItem item) => @; } From dc4b481dc49a1aa0f3ade50f42d07555f6dd5d0d Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Fri, 14 Mar 2025 15:36:51 +0800 Subject: [PATCH 25/34] =?UTF-8?q?refactor:=20=E6=9B=B4=E6=94=B9=E9=80=BB?= =?UTF-8?q?=E8=BE=91=E5=88=A4=E6=96=AD=E6=9D=A1=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/BootstrapBlazor/Components/TreeView/TreeViewRow.razor.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/BootstrapBlazor/Components/TreeView/TreeViewRow.razor.cs b/src/BootstrapBlazor/Components/TreeView/TreeViewRow.razor.cs index f052ffb248f..01eba133f9a 100644 --- a/src/BootstrapBlazor/Components/TreeView/TreeViewRow.razor.cs +++ b/src/BootstrapBlazor/Components/TreeView/TreeViewRow.razor.cs @@ -160,7 +160,7 @@ public partial class TreeViewRow .AddClass("visible", Item.HasChildren || Item.Items.Count > 0) .AddClass(NodeIcon, !Item.IsExpand) .AddClass(ExpandNodeIcon, Item.IsExpand) - .AddClass("disabled", IsDisabled) + .AddClass("disabled", !CanTriggerClickNode) .Build(); private string? NodeLoadingClassString => CssBuilder.Default("node-icon node-loading") From 0807b90cfda3791a5d2fe2475dcc46e8795c21f5 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Fri, 14 Mar 2025 16:02:22 +0800 Subject: [PATCH 26/34] =?UTF-8?q?test:=20=E5=A2=9E=E5=8A=A0=E5=8D=95?= =?UTF-8?q?=E5=85=83=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/UnitTest/Components/TreeViewTest.cs | 27 ++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/test/UnitTest/Components/TreeViewTest.cs b/test/UnitTest/Components/TreeViewTest.cs index 63de44ec223..5b007472506 100644 --- a/test/UnitTest/Components/TreeViewTest.cs +++ b/test/UnitTest/Components/TreeViewTest.cs @@ -1179,6 +1179,33 @@ public async Task ToggleExpand_Ok() cut.Contains("node-icon visible fa-solid fa-caret-right"); } + [Fact] + public void ShowToolbar_Ok() + { + List data = + [ + new() { Text = "1010", Id = "1010" }, + new() { Text = "1010-01", Id = "1010-01", ParentId = "1010" }, + ]; + + var items = TreeFoo.CascadingTree(data); + items[0].IsActive = true; + var count = 0; + var cut = Context.RenderComponent>(pb => + { + pb.Add(a => a.ShowToolbar, true); + pb.Add(a => a.ShowToolbarCallback, foo => + { + count++; + return Task.FromResult(true); + }); + pb.Add(a => a.Items, items); + }); + + // 节点未展开只回调一次 + Assert.Equal(1, count); + } + class MockTree : TreeView where TItem : class { public bool TestComparerItem(TItem? a, TItem? b) => base.Equals(a, b); From e6a42672a0f3d35da3a9957e0d94f06923c38c52 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Fri, 14 Mar 2025 16:11:13 +0800 Subject: [PATCH 27/34] =?UTF-8?q?test:=20=E5=A2=9E=E5=8A=A0=20OnUpdateCall?= =?UTF-8?q?backAsync=20=E5=8D=95=E5=85=83=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/UnitTest/Components/TreeViewTest.cs | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/test/UnitTest/Components/TreeViewTest.cs b/test/UnitTest/Components/TreeViewTest.cs index 5b007472506..b75621da0eb 100644 --- a/test/UnitTest/Components/TreeViewTest.cs +++ b/test/UnitTest/Components/TreeViewTest.cs @@ -3,6 +3,8 @@ // See the LICENSE file in the project root for more information. // Maintainer: Argo Zhang(argo@live.ca) Website: https://www.blazor.zone +using System.Threading.Tasks; + namespace UnitTest.Components; public class TreeViewTest : BootstrapBlazorTestBase @@ -1180,7 +1182,7 @@ public async Task ToggleExpand_Ok() } [Fact] - public void ShowToolbar_Ok() + public async Task ShowToolbar_Ok() { List data = [ @@ -1191,6 +1193,7 @@ public void ShowToolbar_Ok() var items = TreeFoo.CascadingTree(data); items[0].IsActive = true; var count = 0; + var edit = false; var cut = Context.RenderComponent>(pb => { pb.Add(a => a.ShowToolbar, true); @@ -1200,10 +1203,20 @@ public void ShowToolbar_Ok() return Task.FromResult(true); }); pb.Add(a => a.Items, items); + pb.Add(a => a.OnUpdateCallbackAsync, (foo, text) => + { + edit = true; + return Task.FromResult(true); + }); }); // 节点未展开只回调一次 Assert.Equal(1, count); + + // 点击确定按钮 + var button = cut.Find(".popover-body .btn-primary"); + await cut.InvokeAsync(() => button.Click()); + Assert.True(edit); } class MockTree : TreeView where TItem : class From 952d4bcd9effad25f23442482be0cd642f805cf6 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Fri, 14 Mar 2025 16:25:12 +0800 Subject: [PATCH 28/34] =?UTF-8?q?refactor:=20=E5=88=A4=E6=96=AD=E7=A9=BA?= =?UTF-8?q?=E6=9D=A1=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/BootstrapBlazor/Components/TreeView/TreeViewRow.razor.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/BootstrapBlazor/Components/TreeView/TreeViewRow.razor.cs b/src/BootstrapBlazor/Components/TreeView/TreeViewRow.razor.cs index 01eba133f9a..22a32789b9c 100644 --- a/src/BootstrapBlazor/Components/TreeView/TreeViewRow.razor.cs +++ b/src/BootstrapBlazor/Components/TreeView/TreeViewRow.razor.cs @@ -282,11 +282,12 @@ private async Task CheckStateChanged(CheckboxState state) private async Task TriggerBeforeStateChangedCallback(CheckboxState state) { + var ret = true; if (OnBeforeStateChangedCallback != null) { - return await OnBeforeStateChangedCallback(Item, state); + ret = await OnBeforeStateChangedCallback(Item, state); } - return true; + return ret; } private async Task ClickRow() From 2dc4f5dde881d5523c5b1de2d2f46ca636fdbd61 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Fri, 14 Mar 2025 16:26:15 +0800 Subject: [PATCH 29/34] =?UTF-8?q?test:=20=E5=A2=9E=E5=8A=A0=E5=8D=95?= =?UTF-8?q?=E5=85=83=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/UnitTest/Components/TreeViewTest.cs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/test/UnitTest/Components/TreeViewTest.cs b/test/UnitTest/Components/TreeViewTest.cs index b75621da0eb..f48a97d9042 100644 --- a/test/UnitTest/Components/TreeViewTest.cs +++ b/test/UnitTest/Components/TreeViewTest.cs @@ -1217,6 +1217,15 @@ public async Task ShowToolbar_Ok() var button = cut.Find(".popover-body .btn-primary"); await cut.InvokeAsync(() => button.Click()); Assert.True(edit); + + cut.SetParametersAndRender(pb => + { + pb.Add(a => a.ToolbarTemplate, foo => builder => + { + builder.AddContent(0, new MarkupString("
foo.Text
")); + }); + }); + Assert.Contains("test-toolbar-template", cut.Markup); } class MockTree : TreeView where TItem : class From f41a31a3667789d49af00c109682b2971b795616 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Fri, 14 Mar 2025 17:08:27 +0800 Subject: [PATCH 30/34] =?UTF-8?q?refactor:=20=E5=A2=9E=E5=8A=A0=E6=89=A9?= =?UTF-8?q?=E5=B1=95=E6=96=B9=E6=B3=95=E6=8F=90=E9=AB=98=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=E5=A4=8D=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/BootstrapBlazor/Components/TreeView/TreeView.razor.cs | 4 +--- src/BootstrapBlazor/Components/TreeView/TreeViewRow.razor.cs | 2 +- src/BootstrapBlazor/Extensions/TreeViewExtensions.cs | 2 ++ 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/BootstrapBlazor/Components/TreeView/TreeView.razor.cs b/src/BootstrapBlazor/Components/TreeView/TreeView.razor.cs index 1f33071b7f0..3c72caeaa07 100644 --- a/src/BootstrapBlazor/Components/TreeView/TreeView.razor.cs +++ b/src/BootstrapBlazor/Components/TreeView/TreeView.razor.cs @@ -23,8 +23,6 @@ public partial class TreeView : IModelEqualityComparer .AddClassFromAttributes(AdditionalAttributes) .Build(); - private bool CanTriggerClickNode(TreeViewItem item) => !IsDisabled && (CanExpandWhenDisabled || !item.IsDisabled); - private TreeViewItem? _activeItem; /// @@ -549,7 +547,7 @@ private async Task>> GetChildrenRowAsync(Tree private async Task OnClick(TreeViewItem item) { _activeItem = item; - if (ClickToggleNode && CanTriggerClickNode(item)) + if (ClickToggleNode && item.CanTriggerClickNode(IsDisabled, CanExpandWhenDisabled)) { await OnToggleNodeAsync(item); } diff --git a/src/BootstrapBlazor/Components/TreeView/TreeViewRow.razor.cs b/src/BootstrapBlazor/Components/TreeView/TreeViewRow.razor.cs index 22a32789b9c..1fb98e685dc 100644 --- a/src/BootstrapBlazor/Components/TreeView/TreeViewRow.razor.cs +++ b/src/BootstrapBlazor/Components/TreeView/TreeViewRow.razor.cs @@ -260,7 +260,7 @@ private async Task OnContextMenu(MouseEventArgs e) return $"--bb-tree-view-level: {level};"; } - private bool CanTriggerClickNode => !IsDisabled && (CanExpandWhenDisabled || !Item.IsDisabled); + private bool CanTriggerClickNode => Item.CanTriggerClickNode(IsDisabled, CanExpandWhenDisabled); private bool ItemDisabledState => Item.IsDisabled || IsDisabled; diff --git a/src/BootstrapBlazor/Extensions/TreeViewExtensions.cs b/src/BootstrapBlazor/Extensions/TreeViewExtensions.cs index 3e7ee82ab0f..d232ff923fa 100644 --- a/src/BootstrapBlazor/Extensions/TreeViewExtensions.cs +++ b/src/BootstrapBlazor/Extensions/TreeViewExtensions.cs @@ -68,4 +68,6 @@ public static List> ToFlat(this IEnumerable(this TreeViewItem item, bool isDisabled, bool canExpandWhenDisabled) => !isDisabled && (canExpandWhenDisabled || !item.IsDisabled); } From f240e266b74ce051a2174bfa8dcbc692683e61d8 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Fri, 14 Mar 2025 17:08:46 +0800 Subject: [PATCH 31/34] =?UTF-8?q?refactor:=20=E5=A2=9E=E5=8A=A0=20LoadingI?= =?UTF-8?q?con=20=E5=8F=82=E6=95=B0=E8=AE=BE=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/BootstrapBlazor/Components/TreeView/TreeView.razor | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/BootstrapBlazor/Components/TreeView/TreeView.razor b/src/BootstrapBlazor/Components/TreeView/TreeView.razor index 5738cd2ab2c..a479ef8eac0 100644 --- a/src/BootstrapBlazor/Components/TreeView/TreeView.razor +++ b/src/BootstrapBlazor/Components/TreeView/TreeView.razor @@ -67,7 +67,8 @@ else @code { RenderFragment RenderRow(TreeViewItem item) => @ Date: Fri, 14 Mar 2025 17:09:00 +0800 Subject: [PATCH 32/34] =?UTF-8?q?doc:=20=E6=9B=B4=E6=96=B0=E6=96=87?= =?UTF-8?q?=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/BootstrapBlazor/Components/TreeView/TreeView.razor.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/BootstrapBlazor/Components/TreeView/TreeView.razor.cs b/src/BootstrapBlazor/Components/TreeView/TreeView.razor.cs index 3c72caeaa07..1bea8c3904a 100644 --- a/src/BootstrapBlazor/Components/TreeView/TreeView.razor.cs +++ b/src/BootstrapBlazor/Components/TreeView/TreeView.razor.cs @@ -39,7 +39,7 @@ public partial class TreeView : IModelEqualityComparer public bool ShowToolbar { get; set; } /// - /// A callback method that determines whether to show the toolbar of the tree view item. + /// Gets or sts A callback method that determines whether to show the toolbar of the tree view item. /// [Parameter] public Func, Task>? ShowToolbarCallback { get; set; } From b9a8feb5fe7d85a93b96dbdf20de45d133af9c99 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Fri, 14 Mar 2025 17:09:14 +0800 Subject: [PATCH 33/34] =?UTF-8?q?doc:=20=E7=A7=BB=E9=99=A4=E4=B8=8D?= =?UTF-8?q?=E4=BD=BF=E7=94=A8=E7=9A=84=E5=8F=82=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/TreeView/TreeViewRow.razor.cs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/BootstrapBlazor/Components/TreeView/TreeViewRow.razor.cs b/src/BootstrapBlazor/Components/TreeView/TreeViewRow.razor.cs index 1fb98e685dc..39c5e453b13 100644 --- a/src/BootstrapBlazor/Components/TreeView/TreeViewRow.razor.cs +++ b/src/BootstrapBlazor/Components/TreeView/TreeViewRow.razor.cs @@ -30,12 +30,6 @@ public partial class TreeViewRow [Parameter, NotNull] public TreeViewItem? Item { get; set; } - /// - /// Gets or sets the child content of the tree node. Default is null. - /// - [Parameter, NotNull] - public RenderFragment>? ChildContent { get; set; } - /// /// Gets or sets the loading icon for tree nodes. /// From 1368209533bdf53d33f65a2c3820cae968e7a8db Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Fri, 14 Mar 2025 17:09:22 +0800 Subject: [PATCH 34/34] =?UTF-8?q?doc:=20=E4=BB=A3=E7=A0=81=E6=A0=BC?= =?UTF-8?q?=E5=BC=8F=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/BootstrapBlazor/Components/TreeView/TreeViewRow.razor | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/BootstrapBlazor/Components/TreeView/TreeViewRow.razor b/src/BootstrapBlazor/Components/TreeView/TreeViewRow.razor index cf24e05efdf..0ee10125677 100644 --- a/src/BootstrapBlazor/Components/TreeView/TreeViewRow.razor +++ b/src/BootstrapBlazor/Components/TreeView/TreeViewRow.razor @@ -2,7 +2,9 @@ @typeparam TItem @inherits ComponentBase -
+