ant-design-blazor/components/descriptions/Descriptions.razor.cs

181 lines
5.5 KiB
C#
Raw Normal View History

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using AntDesign.JsInterop;
using Microsoft.AspNetCore.Components;
using OneOf;
namespace AntDesign
{
using ColumnType = OneOf<int, Dictionary<string, int>>;
public partial class Descriptions : AntDomComponentBase
{
#region Parameters
[Parameter]
public bool Bordered { get; set; } = false;
[Parameter]
public string Layout { get; set; } = DescriptionsLayout.Horizontal;
[Parameter]
public ColumnType Column { get; set; }
[Parameter]
public string Size { get; set; }
[Parameter]
public string Title { get; set; }
[Parameter]
public RenderFragment TitleTemplate { get; set; }
[Parameter]
public bool Colon { get; set; }
#endregion Parameters
[Parameter]
public RenderFragment ChildContent { get; set; }
public IList<IDescriptionsItem> Items { get; } = new List<IDescriptionsItem>();
private List<List<(IDescriptionsItem item, int realSpan)>> _itemMatrix = new List<List<(IDescriptionsItem item, int realSpan)>>();
[Inject]
perf: avoid memory leak issue of event listener (#1857) * perf: avoid memory leak #1834 Avoid memory leak by remove the exclusive parameter and logic in the code block on AddEventListener method in DomEventService class. The following are the components affected: components/affix/Affix.razor.cs components/anchor/Anchor.razor.cs components/carousel/Carousel.razor.cs components/core/Component/Overlay/Overlay.razor.cs components/core/Component/Overlay/OverlayTrigger.razor.cs components/core/JsInterop/DomEventService.cs components/descriptions/Descriptions.razor.cs components/dropdown/DropdownButton.cs components/grid/Row.razor.cs components/input/Input.cs components/input/TextArea.razor.cs components/layout/Sider.razor.cs components/list/ListItem.razor.cs components/select/Select.razor.cs components/select/internal/SelectContent.razor.cs components/slider/Slider.razor.cs components/table/Table.razor.cs components/tabs/Tabs.razor.cs * fix override AddEventListener method in AntDesign.TestKit project * add register/remove event listerner for exclusive use in DomEventService class * move _dotNetObjects to DomEventListerner class/service, so that users not required to maintain it in each component. * * move share/reuse dom event listerner methods to DomEventListerner class * remove method 'AddEventListener' that no longer exists in DomEventService class in AntDesign.TestKit project * * change the component referring to an IDomEventListerner interface instead of a concrete class, so that the component can be tested via a mock TestDomEventListerner. * introduce DisposeShared and Dispose method in DomEventListerner to ease user remove callback from DomEventListerner * register IDomEventListerner into DI container instead of create manually * fix FormatKey * fix FormatKey * fix tests * fix test * fix test Co-authored-by: James Yeung <shunjiey@hotmail.com>
2021-09-09 12:56:11 +08:00
private IDomEventListener DomEventListener { get; set; }
private int _realColumn;
private static Dictionary<string, int> _defaultColumnMap = new Dictionary<string, int>
{
{ "Xxl", 3 },
{ "Xl", 3},
{ "Lg", 3},
{ "Md", 3},
{ "Sm", 2},
{ "Xs", 1}
};
private static readonly List<(int PixelWidth, BreakpointType Breakpoint)> _descriptionsResponsiveMap = new List<(int, BreakpointType)>()
{
(575,BreakpointType.Xs),
(576,BreakpointType.Sm),
(768,BreakpointType.Md),
(992,BreakpointType.Lg),
(1200,BreakpointType.Xl),
(1600,BreakpointType.Xxl)
};
private void SetClassMap()
{
ClassMapper
.Add("ant-descriptions")
.If("ant-descriptions", () => RTL)
.If("ant-descriptions-bordered", () => this.Bordered)
.If("ant-descriptions-middle", () => this.Size == DescriptionsSize.Middle)
.If("ant-descriptions-small", () => this.Size == DescriptionsSize.Small);
}
protected override async Task OnInitializedAsync()
{
SetClassMap();
await base.OnInitializedAsync();
}
protected override void OnAfterRender(bool firstRender)
{
if (firstRender && Column.IsT1)
{
perf: avoid memory leak issue of event listener (#1857) * perf: avoid memory leak #1834 Avoid memory leak by remove the exclusive parameter and logic in the code block on AddEventListener method in DomEventService class. The following are the components affected: components/affix/Affix.razor.cs components/anchor/Anchor.razor.cs components/carousel/Carousel.razor.cs components/core/Component/Overlay/Overlay.razor.cs components/core/Component/Overlay/OverlayTrigger.razor.cs components/core/JsInterop/DomEventService.cs components/descriptions/Descriptions.razor.cs components/dropdown/DropdownButton.cs components/grid/Row.razor.cs components/input/Input.cs components/input/TextArea.razor.cs components/layout/Sider.razor.cs components/list/ListItem.razor.cs components/select/Select.razor.cs components/select/internal/SelectContent.razor.cs components/slider/Slider.razor.cs components/table/Table.razor.cs components/tabs/Tabs.razor.cs * fix override AddEventListener method in AntDesign.TestKit project * add register/remove event listerner for exclusive use in DomEventService class * move _dotNetObjects to DomEventListerner class/service, so that users not required to maintain it in each component. * * move share/reuse dom event listerner methods to DomEventListerner class * remove method 'AddEventListener' that no longer exists in DomEventService class in AntDesign.TestKit project * * change the component referring to an IDomEventListerner interface instead of a concrete class, so that the component can be tested via a mock TestDomEventListerner. * introduce DisposeShared and Dispose method in DomEventListerner to ease user remove callback from DomEventListerner * register IDomEventListerner into DI container instead of create manually * fix FormatKey * fix FormatKey * fix tests * fix test * fix test Co-authored-by: James Yeung <shunjiey@hotmail.com>
2021-09-09 12:56:11 +08:00
DomEventListener.AddShared<object>("window", "resize", OnResize);
}
base.OnAfterRender(firstRender);
}
protected override void Dispose(bool disposing)
{
DomEventListener?.Dispose();
base.Dispose(disposing);
}
private async void OnResize(object o)
{
await SetRealColumn();
PrepareMatrix();
await InvokeAsync(StateHasChanged);
}
protected override async Task OnFirstAfterRenderAsync()
{
await SetRealColumn();
PrepareMatrix();
await InvokeAsync(StateHasChanged);
await base.OnFirstAfterRenderAsync();
}
protected override async Task OnParametersSetAsync()
{
PrepareMatrix();
await InvokeAsync(StateHasChanged);
await base.OnParametersSetAsync();
}
private void PrepareMatrix()
{
List<List<(IDescriptionsItem item, int realSpan)>> itemMatrix = new List<List<(IDescriptionsItem item, int realSpan)>>();
List<(IDescriptionsItem item, int realSpan)> currentRow = new List<(IDescriptionsItem item, int realSpan)>();
var width = 0;
for (int i = 0; i < this.Items.Count; i++)
{
var item = this.Items[i];
width += item.Span;
if (width >= _realColumn)
{
currentRow.Add((item, _realColumn - (width - item.Span)));
FlushRow();
}
else if (i == this.Items.Count - 1)
{
currentRow.Add((item, _realColumn - (width - item.Span)));
FlushRow();
}
else
{
currentRow.Add((item, item.Span));
}
}
this._itemMatrix = itemMatrix;
void FlushRow()
{
itemMatrix.Add(currentRow);
currentRow = new List<(IDescriptionsItem item, int realSpan)>();
width = 0;
}
}
private async Task SetRealColumn()
{
if (Column.IsT0)
{
_realColumn = Column.AsT0 == 0 ? 3 : Column.AsT0;
}
else
{
HtmlElement element = await JsInvokeAsync<HtmlElement>(JSInteropConstants.GetDomInfo, Ref);
var breakpointTuple = _descriptionsResponsiveMap.FirstOrDefault(x => x.PixelWidth > element.ClientWidth);
var bp = breakpointTuple == default ? BreakpointType.Xxl : breakpointTuple.Breakpoint;
_realColumn = Column.AsT1.ContainsKey(bp.ToString()) ? Column.AsT1[bp.ToString()] : _defaultColumnMap[bp.ToString()];
}
}
}
}