mirror of
https://gitee.com/LongbowEnterprise/BootstrapBlazor.git
synced 2024-11-30 02:58:37 +08:00
feat(TreeView): add MaxSelectedCount OnMaxSelectedCountExceed parameter (#4007)
* feat: 增加 OnBeforeStateChanged 回调方法 * feat: 增加 MaxSelectedCount 参数 * refactor: 通过 OnBeforeStateChanged 实现逻辑 * refactor: 增加 OnMaxSelectedCountExceed 回调执行逻辑 * refactor: 增加客户端阻止逻辑 * refactor: 增加阻止继承标签 * doc: 更新文档 * refactor: 更新注释 * refactor: 精简代码 * test: 增加单元测试 * refactor: 重构代码 * test: 更新单元测试 * test: 更新单元测试 * doc: 更新文档 * doc: 增加多选最大值示例
This commit is contained in:
parent
fbfa97c528
commit
debdabce33
@ -94,7 +94,8 @@ public sealed partial class Checkboxs
|
|||||||
ValueList = " — ",
|
ValueList = " — ",
|
||||||
DefaultValue = " — "
|
DefaultValue = " — "
|
||||||
},
|
},
|
||||||
new(){
|
new()
|
||||||
|
{
|
||||||
Name = "IsDisabled",
|
Name = "IsDisabled",
|
||||||
Description = Localizer["Att4"],
|
Description = Localizer["Att4"],
|
||||||
Type = "boolean",
|
Type = "boolean",
|
||||||
@ -102,14 +103,13 @@ public sealed partial class Checkboxs
|
|||||||
DefaultValue = "false"
|
DefaultValue = "false"
|
||||||
},
|
},
|
||||||
new()
|
new()
|
||||||
|
|
||||||
{
|
{
|
||||||
Name = "State",
|
Name = "State",
|
||||||
Description = Localizer["Att5"],
|
Description = Localizer["Att5"],
|
||||||
Type = "CheckboxState",
|
Type = "CheckboxState",
|
||||||
ValueList = "Mixed / Checked / UnChecked",
|
ValueList = "Mixed / Checked / UnChecked",
|
||||||
DefaultValue = "UnChecked"
|
DefaultValue = "UnChecked"
|
||||||
},
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -182,6 +182,14 @@
|
|||||||
<TreeView TItem="TreeFoo" Items="@SearchItems" ShowSearch="true" OnSearchAsync="@OnSearchAsync" IsFixedSearch="true" style="height: 180px;"></TreeView>
|
<TreeView TItem="TreeFoo" Items="@SearchItems" ShowSearch="true" OnSearchAsync="@OnSearchAsync" IsFixedSearch="true" style="height: 180px;"></TreeView>
|
||||||
</DemoBlock>
|
</DemoBlock>
|
||||||
|
|
||||||
|
<DemoBlock Title="@Localizer["TreeViewMaxSelectedCountTitle"]"
|
||||||
|
Introduction="@Localizer["TreeViewMaxSelectedCountIntro"]"
|
||||||
|
Name="MaxSelectedCount">
|
||||||
|
<section ignore>@((MarkupString)Localizer["TreeViewMaxSelectedCountDesc"].Value)</section>
|
||||||
|
<TreeView TItem="TreeFoo" Items="@SearchItems" ShowCheckbox="true" AutoCheckChildren="true" AutoCheckParent="true"
|
||||||
|
MaxSelectedCount="2" OnMaxSelectedCountExceed="OnMaxSelectedCountExceed"></TreeView>
|
||||||
|
</DemoBlock>
|
||||||
|
|
||||||
<AttributeTable Items="@GetAttributes()"></AttributeTable>
|
<AttributeTable Items="@GetAttributes()"></AttributeTable>
|
||||||
|
|
||||||
<AttributeTable Items="@GetTreeItemAttributes()" Title="@Localizer["TreeViewsAttribute"]"></AttributeTable>
|
<AttributeTable Items="@GetTreeItemAttributes()" Title="@Localizer["TreeViewsAttribute"]"></AttributeTable>
|
||||||
|
@ -81,6 +81,14 @@ public sealed partial class TreeViews
|
|||||||
new("False", "Keep")
|
new("False", "Keep")
|
||||||
];
|
];
|
||||||
|
|
||||||
|
[Inject, NotNull]
|
||||||
|
private ToastService? ToastService { get; set; }
|
||||||
|
|
||||||
|
private Task OnMaxSelectedCountExceed()
|
||||||
|
{
|
||||||
|
return ToastService.Information(Localizer["OnMaxSelectedCountExceedTitle"], Localizer["OnMaxSelectedCountExceedContent", 2]);
|
||||||
|
}
|
||||||
|
|
||||||
private Task OnTreeItemChecked(List<TreeViewItem<TreeFoo>> items)
|
private Task OnTreeItemChecked(List<TreeViewItem<TreeFoo>> items)
|
||||||
{
|
{
|
||||||
Logger2.Log($"当前共选中{items.Count}项");
|
Logger2.Log($"当前共选中{items.Count}项");
|
||||||
@ -119,7 +127,7 @@ public sealed partial class TreeViews
|
|||||||
{
|
{
|
||||||
var ret = TreeFoo.GetCheckedTreeItems();
|
var ret = TreeFoo.GetCheckedTreeItems();
|
||||||
ret[0].IsExpand = true;
|
ret[0].IsExpand = true;
|
||||||
ret[0].Items= TreeFoo.GetCheckedTreeItems();
|
ret[0].Items = TreeFoo.GetCheckedTreeItems();
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -235,7 +243,7 @@ public sealed partial class TreeViews
|
|||||||
builder.AddAttribute(2, nameof(Button.Text), "Click");
|
builder.AddAttribute(2, nameof(Button.Text), "Click");
|
||||||
builder.AddAttribute(3, nameof(Button.OnClick), EventCallback.Factory.Create<MouseEventArgs>(this, e =>
|
builder.AddAttribute(3, nameof(Button.OnClick), EventCallback.Factory.Create<MouseEventArgs>(this, e =>
|
||||||
{
|
{
|
||||||
ToastService.Warning("自定义 TreeItem", "测试 TreeItem 按钮点击事件");
|
ToastService.Warning("自定义 TreeViewItem", "测试 TreeViewItem 按钮点击事件");
|
||||||
}));
|
}));
|
||||||
builder.CloseComponent();
|
builder.CloseComponent();
|
||||||
}
|
}
|
||||||
@ -251,9 +259,9 @@ public sealed partial class TreeViews
|
|||||||
{
|
{
|
||||||
Name = "Items",
|
Name = "Items",
|
||||||
Description = "menu data set",
|
Description = "menu data set",
|
||||||
Type = "IEnumerable<TreeItem>",
|
Type = "IEnumerable<TreeViewItem>",
|
||||||
ValueList = " — ",
|
ValueList = " — ",
|
||||||
DefaultValue = "new List<TreeItem>(20)"
|
DefaultValue = "new List<TreeViewItem>(20)"
|
||||||
},
|
},
|
||||||
new()
|
new()
|
||||||
{
|
{
|
||||||
@ -291,7 +299,7 @@ public sealed partial class TreeViews
|
|||||||
{
|
{
|
||||||
Name = nameof(TreeView<string>.OnTreeItemClick),
|
Name = nameof(TreeView<string>.OnTreeItemClick),
|
||||||
Description = "Callback delegate when tree control node is clicked",
|
Description = "Callback delegate when tree control node is clicked",
|
||||||
Type = "Func<TreeItem, Task>",
|
Type = "Func<TreeViewItem, Task>",
|
||||||
ValueList = " — ",
|
ValueList = " — ",
|
||||||
DefaultValue = " — "
|
DefaultValue = " — "
|
||||||
},
|
},
|
||||||
@ -299,7 +307,7 @@ public sealed partial class TreeViews
|
|||||||
{
|
{
|
||||||
Name = nameof(TreeView<string>.OnTreeItemChecked),
|
Name = nameof(TreeView<string>.OnTreeItemChecked),
|
||||||
Description = "Callback delegate when tree control node is selected",
|
Description = "Callback delegate when tree control node is selected",
|
||||||
Type = "Func<TreeItem, Task>",
|
Type = "Func<TreeViewItem, Task>",
|
||||||
ValueList = " — ",
|
ValueList = " — ",
|
||||||
DefaultValue = " — "
|
DefaultValue = " — "
|
||||||
},
|
},
|
||||||
@ -307,7 +315,7 @@ public sealed partial class TreeViews
|
|||||||
{
|
{
|
||||||
Name = nameof(TreeView<string>.OnExpandNodeAsync),
|
Name = nameof(TreeView<string>.OnExpandNodeAsync),
|
||||||
Description = "Tree control node expand callback delegate",
|
Description = "Tree control node expand callback delegate",
|
||||||
Type = "Func<TreeItem, Task>",
|
Type = "Func<TreeViewItem, Task>",
|
||||||
ValueList = " — ",
|
ValueList = " — ",
|
||||||
DefaultValue = " — "
|
DefaultValue = " — "
|
||||||
},
|
},
|
||||||
@ -326,6 +334,22 @@ public sealed partial class TreeViews
|
|||||||
Type = "bool",
|
Type = "bool",
|
||||||
ValueList = "true|false",
|
ValueList = "true|false",
|
||||||
DefaultValue = "false"
|
DefaultValue = "false"
|
||||||
|
},
|
||||||
|
new()
|
||||||
|
{
|
||||||
|
Name = nameof(TreeView<string>.MaxSelectedCount),
|
||||||
|
Description = "The maximum count of selected node",
|
||||||
|
Type = "int",
|
||||||
|
ValueList = " — ",
|
||||||
|
DefaultValue = "0"
|
||||||
|
},
|
||||||
|
new()
|
||||||
|
{
|
||||||
|
Name = nameof(TreeView<string>.OnMaxSelectedCountExceed),
|
||||||
|
Description = "Select the callback method when the maximum number of nodes is reached",
|
||||||
|
Type = "Func<Task>",
|
||||||
|
ValueList = " — ",
|
||||||
|
DefaultValue = " — "
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
@ -335,7 +359,7 @@ public sealed partial class TreeViews
|
|||||||
{
|
{
|
||||||
Name = nameof(TreeViewItem<TreeFoo>.Items),
|
Name = nameof(TreeViewItem<TreeFoo>.Items),
|
||||||
Description = "Child node data source",
|
Description = "Child node data source",
|
||||||
Type = "List<TreeItem<TItem>>",
|
Type = "List<TreeViewItem<TItem>>",
|
||||||
ValueList = " — ",
|
ValueList = " — ",
|
||||||
DefaultValue = "new ()"
|
DefaultValue = "new ()"
|
||||||
},
|
},
|
||||||
|
@ -630,15 +630,15 @@
|
|||||||
"TreeViewsTitle": "Tree tree control",
|
"TreeViewsTitle": "Tree tree control",
|
||||||
"TreeViewsDescription": "Present information in a clear hierarchy that can be expanded or collapsed",
|
"TreeViewsDescription": "Present information in a clear hierarchy that can be expanded or collapsed",
|
||||||
"TreeViewsTips1": "If the component is a generic component, you need to use <code>TItem</code> to specify the bound data model. In this example, the model is <code>TreeFoo</code> and needs to be set",
|
"TreeViewsTips1": "If the component is a generic component, you need to use <code>TItem</code> to specify the bound data model. In this example, the model is <code>TreeFoo</code> and needs to be set",
|
||||||
"TreeViewsTips2": "Set <code>TreeItem</code> its <code>IsExpand</code> parameter to control whether the current child node is expanded",
|
"TreeViewsTips2": "Set <code>TreeViewItem</code> its <code>IsExpand</code> parameter to control whether the current child node is expanded",
|
||||||
"TreeViewsTips3": "When clicking on the small arrow to expand the child item, obtain the child item data collection through the <code>OnExpandNodeAsync</code> callback delegate method",
|
"TreeViewsTips3": "When clicking on the small arrow to expand the child item, obtain the child item data collection through the <code>OnExpandNodeAsync</code> callback delegate method",
|
||||||
"TreeViewsTips4": "Keep the node state fallback mechanism, <code>ModelEqualityComparer</code> <code>CustomKeyAttribute</code> <code>IEqualityComparer<TItem></code> <code>Equals</code> overloaded method",
|
"TreeViewsTips4": "Keep the node state fallback mechanism, <code>ModelEqualityComparer</code> <code>CustomKeyAttribute</code> <code>IEqualityComparer<TItem></code> <code>Equals</code> overloaded method",
|
||||||
"TreeViewsTips5": "The component will remain in the <code>expanded</code> <code>collapsed</code> <code>selected</code> state",
|
"TreeViewsTips5": "The component will remain in the <code>expanded</code> <code>collapsed</code> <code>selected</code> state",
|
||||||
"TreeViewsTips6": "Set whether the node is <b>expanded</b> state through <code>TreeItem<TItem>.IsExpand</code>",
|
"TreeViewsTips6": "Set whether the node is <b>expanded</b> state through <code>TreeViewItem<TItem>.IsExpand</code>",
|
||||||
"TreeViewsTips7": "Set whether the node is <b>selected</b> state through <code>TreeItem<TItem>.IsActive</code>",
|
"TreeViewsTips7": "Set whether the node is <b>selected</b> state through <code>TreeViewItem<TItem>.IsActive</code>",
|
||||||
"TreeViewsTips8": "Through <code>TreeItem<TItem>.Checked</code>, set whether the node is in <b>checked/single selection</b> state",
|
"TreeViewsTips8": "Through <code>TreeViewItem<TItem>.Checked</code>, set whether the node is in <b>checked/single selection</b> state",
|
||||||
"TreeViewsTips9": "Step 1: Set the <code>TItem</code> generic model",
|
"TreeViewsTips9": "Step 1: Set the <code>TItem</code> generic model",
|
||||||
"TreeViewsTips10": "Step 2: Set <code>Items</code> to get the component data source <b>Note</b> The data source type is <code>IEnumerable<TreeItem<TItem>></code>",
|
"TreeViewsTips10": "Step 2: Set <code>Items</code> to get the component data source <b>Note</b> The data source type is <code>IEnumerable<TreeViewItem<TItem>></code>",
|
||||||
"TreeViewsTips11": "Step 3: Set the <code>OnExpandNodeAsync</code> callback delegate to expand the response node to get the child data source collection",
|
"TreeViewsTips11": "Step 3: Set the <code>OnExpandNodeAsync</code> callback delegate to expand the response node to get the child data source collection",
|
||||||
"TreeViewsTips12": "Step 4: Set <code>ModelEqualityComparer</code> to provide a component identification model comparison delegate method, <b>Note</b> This setting is optional. Perform downgrade search through the fallback mechanism explained above",
|
"TreeViewsTips12": "Step 4: Set <code>ModelEqualityComparer</code> to provide a component identification model comparison delegate method, <b>Note</b> This setting is optional. Perform downgrade search through the fallback mechanism explained above",
|
||||||
"TreeViewNormalTitle": "Basic usage",
|
"TreeViewNormalTitle": "Basic usage",
|
||||||
@ -654,19 +654,19 @@
|
|||||||
"TreeViewCheckboxButtonText": "refresh",
|
"TreeViewCheckboxButtonText": "refresh",
|
||||||
"TreeViewTreeDisableTitle": "Disabled state",
|
"TreeViewTreeDisableTitle": "Disabled state",
|
||||||
"TreeViewTreeDisableIntro": "Some nodes of the Tree can be set to disabled state",
|
"TreeViewTreeDisableIntro": "Some nodes of the Tree can be set to disabled state",
|
||||||
"TreeViewTreeDisableDescription": "By setting the <code>Disabled</code> property of the data source <code>TreeItem</code> object, you can control whether this node can be checked or not. When set to <code>false</code>, it will not affect the node expansion. /shrink function",
|
"TreeViewTreeDisableDescription": "By setting the <code>Disabled</code> property of the data source <code>TreeViewItem</code> object, you can control whether this node can be checked or not. When set to <code>false</code>, it will not affect the node expansion. /shrink function",
|
||||||
"TreeViewAccordionModelTitle": "Accordion mode",
|
"TreeViewAccordionModelTitle": "Accordion mode",
|
||||||
"TreeViewAccordionModelIntro": "For nodes of the same level, only one can be expanded at a time",
|
"TreeViewAccordionModelIntro": "For nodes of the same level, only one can be expanded at a time",
|
||||||
"TreeViewAccordionModelDescription": "Enable the accordion effect by setting the <code>IsAccordion</code> property of the <code>Tree</code> component",
|
"TreeViewAccordionModelDescription": "Enable the accordion effect by setting the <code>IsAccordion</code> property of the <code>Tree</code> component",
|
||||||
"TreeViewDefaultExpandTitle": "Expanded by default and selected by default",
|
"TreeViewDefaultExpandTitle": "Expanded by default and selected by default",
|
||||||
"TreeViewDefaultExpandIntro": "Some nodes of <code>Tree</code> can be set to be expanded or selected by default",
|
"TreeViewDefaultExpandIntro": "Some nodes of <code>Tree</code> can be set to be expanded or selected by default",
|
||||||
"TreeViewDefaultExpandDescription": "By setting the <code>IsExpand</code> property of the <code>TreeItem</code> object, you can control whether this node is in the expanded state by default. In this example, <b>navigation 2</b> is in the expanded state by default, and the rest Node defaults to contracted state",
|
"TreeViewDefaultExpandDescription": "By setting the <code>IsExpand</code> property of the <code>TreeViewItem</code> object, you can control whether this node is in the expanded state by default. In this example, <b>navigation 2</b> is in the expanded state by default, and the rest Node defaults to contracted state",
|
||||||
"TreeViewTreeDisplayIconTitle": "Show icon",
|
"TreeViewTreeDisplayIconTitle": "Show icon",
|
||||||
"TreeViewTreeDisplayIconIntro": "Control whether the component displays the icon by setting <code>ShowIcon</code>",
|
"TreeViewTreeDisplayIconIntro": "Control whether the component displays the icon by setting <code>ShowIcon</code>",
|
||||||
"TreeViewTreeDisplayIconDescription": "By setting the <code>ShowIcon</code> property of the <code>TreeItem</code> object, you can control whether this node displays the icon or not",
|
"TreeViewTreeDisplayIconDescription": "By setting the <code>ShowIcon</code> property of the <code>TreeViewItem</code> object, you can control whether this node displays the icon or not",
|
||||||
"TreeViewTreeClickExpandTitle": "Click on the node to expand and contract",
|
"TreeViewTreeClickExpandTitle": "Click on the node to expand and contract",
|
||||||
"TreeViewTreeClickExpandIntro": "By setting <code>ClickToggleNode</code> to control whether to expand and contract when the node is clicked",
|
"TreeViewTreeClickExpandIntro": "By setting <code>ClickToggleNode</code> to control whether to expand and contract when the node is clicked",
|
||||||
"TreeViewTreeClickExpandDescription": "By setting the <code>ClickToggleNode</code> property of the <code>TreeItem</code> object, you can control whether this node can be expanded and contracted by clicking",
|
"TreeViewTreeClickExpandDescription": "By setting the <code>ClickToggleNode</code> property of the <code>TreeViewItem</code> object, you can control whether this node can be expanded and contracted by clicking",
|
||||||
"TreeViewTreeValidationFormTitle": "The Tree component is built into the validation form",
|
"TreeViewTreeValidationFormTitle": "The Tree component is built into the validation form",
|
||||||
"TreeViewTreeValidationFormIntro": "<code>Tree</code> can be enabled inside the component <code>Checkbox</code> will be displayed when it is built into the validation form <code>DisplayName</code> This function needs to be disabled in the tree component",
|
"TreeViewTreeValidationFormIntro": "<code>Tree</code> can be enabled inside the component <code>Checkbox</code> will be displayed when it is built into the validation form <code>DisplayName</code> This function needs to be disabled in the tree component",
|
||||||
"TreeViewTreeValidationFormDescription": "Show <code>Checkbox</code> built into validation component <code>ValidateForm</code> by setting <code>ShowCheckbox</code> property does not show <code>DisplayName</code>",
|
"TreeViewTreeValidationFormDescription": "Show <code>Checkbox</code> built into validation component <code>ValidateForm</code> by setting <code>ShowCheckbox</code> property does not show <code>DisplayName</code>",
|
||||||
@ -674,9 +674,9 @@
|
|||||||
"TreeViewTreeLazyLoadingIntro": "Dynamically add child nodes when expanding a node",
|
"TreeViewTreeLazyLoadingIntro": "Dynamically add child nodes when expanding a node",
|
||||||
"TreeViewTreeLazyLoadingDescription": "By setting the node <code>HasChildNode</code> to control whether to display the small arrow picture of the node. Add nodes through Tree's <code>OnExpandNodeAsync</code> delegate",
|
"TreeViewTreeLazyLoadingDescription": "By setting the node <code>HasChildNode</code> to control whether to display the small arrow picture of the node. Add nodes through Tree's <code>OnExpandNodeAsync</code> delegate",
|
||||||
"TreeViewTreeCustomNodeTitle": "Custom node",
|
"TreeViewTreeCustomNodeTitle": "Custom node",
|
||||||
"TreeViewTreeCustomNodeIntro": "Implement your own node template by setting <code>TreeItem</code> <code>Template</code>",
|
"TreeViewTreeCustomNodeIntro": "Implement your own node template by setting <code>TreeViewItem</code> <code>Template</code>",
|
||||||
"TreeViewTreeNodeColorTitle": "Node color",
|
"TreeViewTreeNodeColorTitle": "Node color",
|
||||||
"TreeViewTreeNodeColorIntro": "Implement your own node style by setting <code>TreeItem</code> <code>CssClass</code>",
|
"TreeViewTreeNodeColorIntro": "Implement your own node style by setting <code>TreeViewItem</code> <code>CssClass</code>",
|
||||||
"TreeViewCheckedItemsTitle": "Get all selected nodes",
|
"TreeViewCheckedItemsTitle": "Get all selected nodes",
|
||||||
"TreeViewCheckedItemsIntro": "Get all nodes by setting the <code>OnTreeItemChecked</code> callback delegate",
|
"TreeViewCheckedItemsIntro": "Get all nodes by setting the <code>OnTreeItemChecked</code> callback delegate",
|
||||||
"TreeViewCustomCheckedItemsTitle": "Customize the selected node",
|
"TreeViewCustomCheckedItemsTitle": "Customize the selected node",
|
||||||
@ -692,9 +692,14 @@
|
|||||||
"TreeViewSetActiveTitle": "Set Active Node",
|
"TreeViewSetActiveTitle": "Set Active Node",
|
||||||
"TreeViewSetActiveIntro": "Set the currently active node by calling the <code>SetActiveItem</code> method",
|
"TreeViewSetActiveIntro": "Set the currently active node by calling the <code>SetActiveItem</code> method",
|
||||||
"TreeViewSetActiveDisplayText": "Current Active Node",
|
"TreeViewSetActiveDisplayText": "Current Active Node",
|
||||||
"TreeViewsAttribute": "TreeItem property",
|
"TreeViewsAttribute": "TreeViewItem property",
|
||||||
"TreeViewsDisableWholeTreeView": "Whole TreeView disable",
|
"TreeViewsDisableWholeTreeView": "Whole TreeView disable",
|
||||||
"TreeViewsWhetherToExpandWhenDisable": "Whether to expand when the control node is disabled"
|
"TreeViewsWhetherToExpandWhenDisable": "Whether to expand when the control node is disabled",
|
||||||
|
"OnMaxSelectedCountExceedTitle": "Maximum Info",
|
||||||
|
"OnMaxSelectedCountExceedContent": "You can select at most {0} items",
|
||||||
|
"TreeViewMaxSelectedCountTitle": "MaxSelectedCount",
|
||||||
|
"TreeViewMaxSelectedCountIntro": "Control the maximum number of selectable items by setting the <code>MaxSelectedCount</code> property, and handle the logic through the <code>OnMaxSelectedCountExceed</code> callback",
|
||||||
|
"TreeViewMaxSelectedCountDesc": "When more than 2 nodes are selected, a <code>Toast</code> prompt bar will pop up"
|
||||||
},
|
},
|
||||||
"BootstrapBlazor.Server.Components.Samples.Trees": {
|
"BootstrapBlazor.Server.Components.Samples.Trees": {
|
||||||
"TreeIntro": "<p>Obsolete,The <a href=\"treeviews\" alt=\"treeview\">TreeView</a> provides more functions",
|
"TreeIntro": "<p>Obsolete,The <a href=\"treeviews\" alt=\"treeview\">TreeView</a> provides more functions",
|
||||||
|
@ -630,15 +630,15 @@
|
|||||||
"TreeViewsTitle": "Tree 树形控件",
|
"TreeViewsTitle": "Tree 树形控件",
|
||||||
"TreeViewsDescription": "用清晰的层级结构展示信息,可展开或折叠",
|
"TreeViewsDescription": "用清晰的层级结构展示信息,可展开或折叠",
|
||||||
"TreeViewsTips1": "组件为泛型组件需要使用 <code>TItem</code> 指定绑定的数据模型,本例中模型为 <code>TreeFoo</code> 需要设置",
|
"TreeViewsTips1": "组件为泛型组件需要使用 <code>TItem</code> 指定绑定的数据模型,本例中模型为 <code>TreeFoo</code> 需要设置",
|
||||||
"TreeViewsTips2": "设置 <code>TreeItem</code> 其 <code>IsExpand</code> 参数控制当前子节点是否展开",
|
"TreeViewsTips2": "设置 <code>TreeViewItem</code> 其 <code>IsExpand</code> 参数控制当前子节点是否展开",
|
||||||
"TreeViewsTips3": "点击子项展开小箭头时,通过 <code>OnExpandNodeAsync</code> 回调委托方法获取子项数据集合",
|
"TreeViewsTips3": "点击子项展开小箭头时,通过 <code>OnExpandNodeAsync</code> 回调委托方法获取子项数据集合",
|
||||||
"TreeViewsTips4": "保持节点状态回落机制,<code>ModelEqualityComparer</code> <code>CustomKeyAttribute</code> <code>IEqualityComparer<TItem></code> <code>Equals</code> 重载方法",
|
"TreeViewsTips4": "保持节点状态回落机制,<code>ModelEqualityComparer</code> <code>CustomKeyAttribute</code> <code>IEqualityComparer<TItem></code> <code>Equals</code> 重载方法",
|
||||||
"TreeViewsTips5": "组件将会保持 <code>展开</code> <code>收缩</code> <code>选中</code> 状态",
|
"TreeViewsTips5": "组件将会保持 <code>展开</code> <code>收缩</code> <code>选中</code> 状态",
|
||||||
"TreeViewsTips6": "通过 <code>TreeItem<TItem>.IsExpand</code> 设置节点是否 <b>展开</b> 状态",
|
"TreeViewsTips6": "通过 <code>TreeViewItem<TItem>.IsExpand</code> 设置节点是否 <b>展开</b> 状态",
|
||||||
"TreeViewsTips7": "通过 <code>TreeItem<TItem>.IsActive</code> 设置节点是否 <b>选中</b> 状态",
|
"TreeViewsTips7": "通过 <code>TreeViewItem<TItem>.IsActive</code> 设置节点是否 <b>选中</b> 状态",
|
||||||
"TreeViewsTips8": "通过 <code>TreeItem<TItem>.Checked</code> 设置节点是否 <b>复选/单选</b> 状态",
|
"TreeViewsTips8": "通过 <code>TreeViewItem<TItem>.Checked</code> 设置节点是否 <b>复选/单选</b> 状态",
|
||||||
"TreeViewsTips9": "第一步:设置 <code>TItem</code> 泛型模型",
|
"TreeViewsTips9": "第一步:设置 <code>TItem</code> 泛型模型",
|
||||||
"TreeViewsTips10": "第二步:设置 <code>Items</code> 获得组件数据源 <b>注意</b> 数据源类型为 <code>IEnumerable<TreeItem<TItem>></code>",
|
"TreeViewsTips10": "第二步:设置 <code>Items</code> 获得组件数据源 <b>注意</b> 数据源类型为 <code>IEnumerable<TreeViewItem<TItem>></code>",
|
||||||
"TreeViewsTips11": "第三步:设置 <code>OnExpandNodeAsync</code> 回调委托响应节点展开获取子项数据源集合",
|
"TreeViewsTips11": "第三步:设置 <code>OnExpandNodeAsync</code> 回调委托响应节点展开获取子项数据源集合",
|
||||||
"TreeViewsTips12": "第四步:设置 <code>ModelEqualityComparer</code> 提供组件识别模型比较委托方法,<b>注意</b> 本设置为可选项 通过上面讲解的回落机制进行降级搜索",
|
"TreeViewsTips12": "第四步:设置 <code>ModelEqualityComparer</code> 提供组件识别模型比较委托方法,<b>注意</b> 本设置为可选项 通过上面讲解的回落机制进行降级搜索",
|
||||||
"TreeViewNormalTitle": "基础用法",
|
"TreeViewNormalTitle": "基础用法",
|
||||||
@ -654,19 +654,19 @@
|
|||||||
"TreeViewCheckboxButtonText": "刷新",
|
"TreeViewCheckboxButtonText": "刷新",
|
||||||
"TreeViewTreeDisableTitle": "禁用状态",
|
"TreeViewTreeDisableTitle": "禁用状态",
|
||||||
"TreeViewTreeDisableIntro": "可将 Tree 的某些节点设置为禁用状态",
|
"TreeViewTreeDisableIntro": "可将 Tree 的某些节点设置为禁用状态",
|
||||||
"TreeViewTreeDisableDescription": "通过设置数据源 <code>TreeItem</code> 对象的 <code>Disabled</code> 属性,来控制此节点是否可以进行勾选动作,设置为 <code>false</code> 时不影响节点展开/收缩功能",
|
"TreeViewTreeDisableDescription": "通过设置数据源 <code>TreeViewItem</code> 对象的 <code>Disabled</code> 属性,来控制此节点是否可以进行勾选动作,设置为 <code>false</code> 时不影响节点展开/收缩功能",
|
||||||
"TreeViewAccordionModelTitle": "手风琴模式",
|
"TreeViewAccordionModelTitle": "手风琴模式",
|
||||||
"TreeViewAccordionModelIntro": "对于同一级的节点,每次只能展开一个",
|
"TreeViewAccordionModelIntro": "对于同一级的节点,每次只能展开一个",
|
||||||
"TreeViewAccordionModelDescription": "通过设置 <code>Tree</code> 组件的 <code>IsAccordion</code> 属性开启手风琴效果",
|
"TreeViewAccordionModelDescription": "通过设置 <code>Tree</code> 组件的 <code>IsAccordion</code> 属性开启手风琴效果",
|
||||||
"TreeViewDefaultExpandTitle": "默认展开和默认选中",
|
"TreeViewDefaultExpandTitle": "默认展开和默认选中",
|
||||||
"TreeViewDefaultExpandIntro": "可将 <code>Tree</code> 的某些节点设置为默认展开或默认选中",
|
"TreeViewDefaultExpandIntro": "可将 <code>Tree</code> 的某些节点设置为默认展开或默认选中",
|
||||||
"TreeViewDefaultExpandDescription": "通过设置 <code>TreeItem</code> 对象的 <code>IsExpand</code> 属性,来控制此节点是否默认为展开状态,本例中 <b>导航二</b> 默认为展开状态,其余节点默认为收缩状态",
|
"TreeViewDefaultExpandDescription": "通过设置 <code>TreeViewItem</code> 对象的 <code>IsExpand</code> 属性,来控制此节点是否默认为展开状态,本例中 <b>导航二</b> 默认为展开状态,其余节点默认为收缩状态",
|
||||||
"TreeViewTreeDisplayIconTitle": "显示图标",
|
"TreeViewTreeDisplayIconTitle": "显示图标",
|
||||||
"TreeViewTreeDisplayIconIntro": "通过设置 <code>ShowIcon</code> 来控制组件是否显示图标",
|
"TreeViewTreeDisplayIconIntro": "通过设置 <code>ShowIcon</code> 来控制组件是否显示图标",
|
||||||
"TreeViewTreeDisplayIconDescription": "通过设置 <code>TreeItem</code> 对象的 <code>ShowIcon</code> 属性,来控制此节点是否显示图标",
|
"TreeViewTreeDisplayIconDescription": "通过设置 <code>TreeViewItem</code> 对象的 <code>ShowIcon</code> 属性,来控制此节点是否显示图标",
|
||||||
"TreeViewTreeClickExpandTitle": "点击节点展开收缩功能",
|
"TreeViewTreeClickExpandTitle": "点击节点展开收缩功能",
|
||||||
"TreeViewTreeClickExpandIntro": "通过设置 <code>ClickToggleNode</code> 来控制点击节点时是否进行展开收缩操作",
|
"TreeViewTreeClickExpandIntro": "通过设置 <code>ClickToggleNode</code> 来控制点击节点时是否进行展开收缩操作",
|
||||||
"TreeViewTreeClickExpandDescription": "通过设置 <code>TreeItem</code> 对象的 <code>ClickToggleNode</code> 属性,来控制此节点是否通过点击来实现展开收缩操作",
|
"TreeViewTreeClickExpandDescription": "通过设置 <code>TreeViewItem</code> 对象的 <code>ClickToggleNode</code> 属性,来控制此节点是否通过点击来实现展开收缩操作",
|
||||||
"TreeViewTreeValidationFormTitle": "Tree 组件内置到验证表单中",
|
"TreeViewTreeValidationFormTitle": "Tree 组件内置到验证表单中",
|
||||||
"TreeViewTreeValidationFormIntro": "<code>Tree</code> 组件内部可开启 <code>Checkbox</code> 内置到验证表单时会显示 <code>DisplayName</code> 此功能在树状组件内需要禁止",
|
"TreeViewTreeValidationFormIntro": "<code>Tree</code> 组件内部可开启 <code>Checkbox</code> 内置到验证表单时会显示 <code>DisplayName</code> 此功能在树状组件内需要禁止",
|
||||||
"TreeViewTreeValidationFormDescription": "通过设置 <code>ShowCheckbox</code> 属性显示 <code>Checkbox</code> 内置到验证组件 <code>ValidateForm</code> 中不显示 <code>DisplayName</code>",
|
"TreeViewTreeValidationFormDescription": "通过设置 <code>ShowCheckbox</code> 属性显示 <code>Checkbox</code> 内置到验证组件 <code>ValidateForm</code> 中不显示 <code>DisplayName</code>",
|
||||||
@ -674,9 +674,9 @@
|
|||||||
"TreeViewTreeLazyLoadingIntro": "展开节点时动态添加子节点",
|
"TreeViewTreeLazyLoadingIntro": "展开节点时动态添加子节点",
|
||||||
"TreeViewTreeLazyLoadingDescription": "通过设置节点 <code>HasChildNode</code> 控制是否显示节点小箭头图片 。通过Tree的 <code>OnExpandNodeAsync</code> 委托添加节点",
|
"TreeViewTreeLazyLoadingDescription": "通过设置节点 <code>HasChildNode</code> 控制是否显示节点小箭头图片 。通过Tree的 <code>OnExpandNodeAsync</code> 委托添加节点",
|
||||||
"TreeViewTreeCustomNodeTitle": "自定义节点",
|
"TreeViewTreeCustomNodeTitle": "自定义节点",
|
||||||
"TreeViewTreeCustomNodeIntro": "通过设置 <code>TreeItem</code> <code>Template</code> 来实现自己的节点模板",
|
"TreeViewTreeCustomNodeIntro": "通过设置 <code>TreeViewItem</code> <code>Template</code> 来实现自己的节点模板",
|
||||||
"TreeViewTreeNodeColorTitle": "节点颜色",
|
"TreeViewTreeNodeColorTitle": "节点颜色",
|
||||||
"TreeViewTreeNodeColorIntro": "通过设置 <code>TreeItem</code> <code>CssClass</code> 来实现自己的节点样式",
|
"TreeViewTreeNodeColorIntro": "通过设置 <code>TreeViewItem</code> <code>CssClass</code> 来实现自己的节点样式",
|
||||||
"TreeViewCheckedItemsTitle": "获取所有选中节点",
|
"TreeViewCheckedItemsTitle": "获取所有选中节点",
|
||||||
"TreeViewCheckedItemsIntro": "通过设置 <code>OnTreeItemChecked</code> 回调委托获取所有节点",
|
"TreeViewCheckedItemsIntro": "通过设置 <code>OnTreeItemChecked</code> 回调委托获取所有节点",
|
||||||
"TreeViewCustomCheckedItemsTitle": "自定义选中节点",
|
"TreeViewCustomCheckedItemsTitle": "自定义选中节点",
|
||||||
@ -692,9 +692,14 @@
|
|||||||
"TreeViewSetActiveTitle": "设置激活节点",
|
"TreeViewSetActiveTitle": "设置激活节点",
|
||||||
"TreeViewSetActiveIntro": "通过调用 <code>SetActiveItem</code> 方法设置当前激活节点",
|
"TreeViewSetActiveIntro": "通过调用 <code>SetActiveItem</code> 方法设置当前激活节点",
|
||||||
"TreeViewSetActiveDisplayText": "当前激活节点",
|
"TreeViewSetActiveDisplayText": "当前激活节点",
|
||||||
"TreeViewsAttribute": "TreeItem 属性",
|
"TreeViewsAttribute": "TreeViewItem 属性",
|
||||||
"TreeViewsDisableWholeTreeView": "是否禁用整个TreeView",
|
"TreeViewsDisableWholeTreeView": "是否禁用整个 TreeView",
|
||||||
"TreeViewsWhetherToExpandWhenDisable": "禁用时候是否可以展开或折叠子节点"
|
"TreeViewsWhetherToExpandWhenDisable": "禁用时候是否可以展开或折叠子节点",
|
||||||
|
"OnMaxSelectedCountExceedTitle": "可选最大数量提示",
|
||||||
|
"OnMaxSelectedCountExceedContent": "最多只能选择 {0} 项",
|
||||||
|
"TreeViewMaxSelectedCountTitle": "最大选择数量",
|
||||||
|
"TreeViewMaxSelectedCountIntro": "通过设置 <code>MaxSelectedCount</code> 属性控制最大可选数量,通过 <code>OnMaxSelectedCountExceed</code> 回调处理逻辑",
|
||||||
|
"TreeViewMaxSelectedCountDesc": "选中节点超过 2 个时,弹出 <code>Toast</code> 提示栏"
|
||||||
},
|
},
|
||||||
"BootstrapBlazor.Server.Components.Samples.Trees": {
|
"BootstrapBlazor.Server.Components.Samples.Trees": {
|
||||||
"TreeIntro": "<p>本组件已弃用,请使用新组件 <a href=\"treeviews\" alt=\"treeview\">TreeView</a> 提供更多功能",
|
"TreeIntro": "<p>本组件已弃用,请使用新组件 <a href=\"treeviews\" alt=\"treeview\">TreeView</a> 提供更多功能",
|
||||||
|
@ -164,8 +164,6 @@ public partial class Checkbox<TValue> : ValidateBase<TValue>
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 触发 OnBeforeStateChanged 回调方法 由 JavaScript 调用
|
/// 触发 OnBeforeStateChanged 回调方法 由 JavaScript 调用
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="v"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
[JSInvokable]
|
[JSInvokable]
|
||||||
public async Task TriggerOnBeforeStateChanged()
|
public async Task TriggerOnBeforeStateChanged()
|
||||||
{
|
{
|
||||||
|
@ -63,6 +63,7 @@ else
|
|||||||
{
|
{
|
||||||
<Checkbox Value="@item.CheckedState" IsDisabled="GetItemDisabledState(item)" SkipValidate="true"
|
<Checkbox Value="@item.CheckedState" IsDisabled="GetItemDisabledState(item)" SkipValidate="true"
|
||||||
ShowLabel="false" ShowAfterLabel="false" @bind-State="@item.CheckedState"
|
ShowLabel="false" ShowAfterLabel="false" @bind-State="@item.CheckedState"
|
||||||
|
OnBeforeStateChanged="_onBeforeStateChangedCallback"
|
||||||
OnStateChanged="(state, v) => OnCheckStateChanged(item, true)" StopPropagation="true" />
|
OnStateChanged="(state, v) => OnCheckStateChanged(item, true)" StopPropagation="true" />
|
||||||
}
|
}
|
||||||
<DynamicElement class="@GetNodeClassString(item)" TriggerClick="TriggerNodeLabel(item)" OnClick="() => OnClick(item)">
|
<DynamicElement class="@GetNodeClassString(item)" TriggerClick="TriggerNodeLabel(item)" OnClick="() => OnClick(item)">
|
||||||
|
@ -184,6 +184,18 @@ public partial class TreeView<TItem> : IModelEqualityComparer<TItem>
|
|||||||
[Parameter]
|
[Parameter]
|
||||||
public bool ShowCheckbox { get; set; }
|
public bool ShowCheckbox { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获得/设置 最多选中数量
|
||||||
|
/// </summary>
|
||||||
|
[Parameter]
|
||||||
|
public int MaxSelectedCount { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获得/设置 超过最大选中数量时回调委托
|
||||||
|
/// </summary>
|
||||||
|
[Parameter]
|
||||||
|
public Func<Task>? OnMaxSelectedCountExceed { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 获得/设置 是否显示 Icon 图标 默认 false 不显示
|
/// 获得/设置 是否显示 Icon 图标 默认 false 不显示
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -271,6 +283,8 @@ public partial class TreeView<TItem> : IModelEqualityComparer<TItem>
|
|||||||
|
|
||||||
private string? _searchText;
|
private string? _searchText;
|
||||||
|
|
||||||
|
private Func<CheckboxState, Task<bool>>? _onBeforeStateChangedCallback;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -332,6 +346,9 @@ public partial class TreeView<TItem> : IModelEqualityComparer<TItem>
|
|||||||
ActiveItem ??= Items.FirstOrDefaultActiveItem();
|
ActiveItem ??= Items.FirstOrDefaultActiveItem();
|
||||||
ActiveItem?.SetParentExpand<TreeViewItem<TItem>, TItem>(true);
|
ActiveItem?.SetParentExpand<TreeViewItem<TItem>, TItem>(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_onBeforeStateChangedCallback = (ShowCheckbox && MaxSelectedCount > 0) ? new Func<CheckboxState, Task<bool>>(OnBeforeStateChanged)
|
||||||
|
: null;
|
||||||
}
|
}
|
||||||
|
|
||||||
async Task CheckExpand(IEnumerable<TreeViewItem<TItem>> nodes)
|
async Task CheckExpand(IEnumerable<TreeViewItem<TItem>> nodes)
|
||||||
@ -488,6 +505,22 @@ public partial class TreeView<TItem> : IModelEqualityComparer<TItem>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task<bool> OnBeforeStateChanged(CheckboxState state)
|
||||||
|
{
|
||||||
|
var ret = true;
|
||||||
|
if (state == CheckboxState.Checked)
|
||||||
|
{
|
||||||
|
var items = GetCheckedItems().Where(i => i.HasChildren == false).ToList();
|
||||||
|
ret = items.Count < MaxSelectedCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ret && OnMaxSelectedCountExceed != null)
|
||||||
|
{
|
||||||
|
await OnMaxSelectedCountExceed();
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 节点 Checkbox 状态改变时触发此方法
|
/// 节点 Checkbox 状态改变时触发此方法
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -496,8 +529,6 @@ public partial class TreeView<TItem> : IModelEqualityComparer<TItem>
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
private async Task OnCheckStateChanged(TreeViewItem<TItem> item, bool shouldRender = false)
|
private async Task OnCheckStateChanged(TreeViewItem<TItem> item, bool shouldRender = false)
|
||||||
{
|
{
|
||||||
//item.CheckedState = ToggleCheckState(item.CheckedState);
|
|
||||||
|
|
||||||
if (AutoCheckChildren)
|
if (AutoCheckChildren)
|
||||||
{
|
{
|
||||||
// 向下级联操作
|
// 向下级联操作
|
||||||
|
@ -206,6 +206,65 @@ public class TreeViewTest : BootstrapBlazorTestBase
|
|||||||
cut.WaitForAssertion(() => cut.Contains("fa-solid fa-font-awesome"));
|
cut.WaitForAssertion(() => cut.Contains("fa-solid fa-font-awesome"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task OnMaxSelectedCountExceed_Ok()
|
||||||
|
{
|
||||||
|
bool max = false;
|
||||||
|
var items = TreeFoo.CascadingTree(new List<TreeFoo>()
|
||||||
|
{
|
||||||
|
new() { Text = "navigation one", Id = "1010", Icon = "fa-solid fa-font-awesome" },
|
||||||
|
new() { Text = "Navigation two", Id = "1020", Icon = "fa-solid fa-font-awesome" },
|
||||||
|
new() { Text = "Navigation three", Id = "1030", Icon = "fa-solid fa-font-awesome" }
|
||||||
|
});
|
||||||
|
|
||||||
|
var cut = Context.RenderComponent<TreeView<TreeFoo>>(pb =>
|
||||||
|
{
|
||||||
|
pb.Add(a => a.ShowCheckbox, true);
|
||||||
|
pb.Add(a => a.MaxSelectedCount, 2);
|
||||||
|
pb.Add(a => a.Items, items);
|
||||||
|
pb.Add(a => a.OnMaxSelectedCountExceed, () =>
|
||||||
|
{
|
||||||
|
max = true;
|
||||||
|
return Task.CompletedTask;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
var checkboxes = cut.FindComponents<Checkbox<CheckboxState>>();
|
||||||
|
Assert.Equal(3, checkboxes.Count);
|
||||||
|
|
||||||
|
await cut.InvokeAsync(async () =>
|
||||||
|
{
|
||||||
|
await checkboxes[0].Instance.TriggerOnBeforeStateChanged();
|
||||||
|
});
|
||||||
|
Assert.Equal(CheckboxState.Checked, checkboxes[0].Instance.State);
|
||||||
|
|
||||||
|
await cut.InvokeAsync(async () =>
|
||||||
|
{
|
||||||
|
await checkboxes[1].Instance.TriggerOnBeforeStateChanged();
|
||||||
|
});
|
||||||
|
Assert.Equal(CheckboxState.Checked, checkboxes[1].Instance.State);
|
||||||
|
|
||||||
|
// 选中第三个由于限制无法选中
|
||||||
|
await cut.InvokeAsync(async () =>
|
||||||
|
{
|
||||||
|
await checkboxes[2].Instance.TriggerOnBeforeStateChanged();
|
||||||
|
});
|
||||||
|
Assert.Equal(CheckboxState.Checked, checkboxes[0].Instance.State);
|
||||||
|
Assert.Equal(CheckboxState.Checked, checkboxes[1].Instance.State);
|
||||||
|
Assert.Equal(CheckboxState.UnChecked, checkboxes[2].Instance.State);
|
||||||
|
Assert.True(max);
|
||||||
|
|
||||||
|
// 取消选择第一个
|
||||||
|
max = false;
|
||||||
|
await cut.InvokeAsync(async () =>
|
||||||
|
{
|
||||||
|
await checkboxes[0].Instance.TriggerOnBeforeStateChanged();
|
||||||
|
});
|
||||||
|
Assert.Equal(CheckboxState.UnChecked, checkboxes[0].Instance.State);
|
||||||
|
Assert.Equal(CheckboxState.Checked, checkboxes[1].Instance.State);
|
||||||
|
Assert.Equal(CheckboxState.UnChecked, checkboxes[2].Instance.State);
|
||||||
|
Assert.False(max);
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void Template_Ok()
|
public void Template_Ok()
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user