using System; using System.Collections.Generic; using System.Linq; using System.ComponentModel; using System.ComponentModel.DataAnnotations; using System.Linq.Expressions; using System.Reflection; using AntDesign.Core.Reflection; using AntDesign.Internal; using AntDesign.TableModels; using Microsoft.AspNetCore.Components; using System.Globalization; namespace AntDesign { public partial class Column : ColumnBase, IFieldColumn { [CascadingParameter(Name = "ItemType")] public Type ItemType { get; set; } [Parameter] public EventCallback FieldChanged { get; set; } [Parameter] public Expression> FieldExpression { get; set; } [Parameter] public RenderFragment CellRender { get; set; } [Parameter] public TData Field { get { return GetValue != null ? GetValue(RowData) : _field; } set { if (GetValue == null) { _field = value; } } } private TData _field; [Parameter] public string DataIndex { get; set; } [Parameter] public string Format { get; set; } [Parameter] public bool Sortable { get; set; } [Parameter] public Func SorterCompare { get; set; } [Parameter] public int SorterMultiple { get; set; } [Parameter] public bool ShowSorterTooltip { get; set; } = true; [Parameter] public SortDirection[] SortDirections { get; set; } [Parameter] public SortDirection DefaultSortOrder { get; set; } [Parameter] public Func> OnCell { get; set; } [Parameter] public Func> OnHeaderCell { get; set; } [Parameter] public bool Filterable { get; set; } [Parameter] public IEnumerable> Filters { get; set; } [Parameter] public bool FilterMultiple { get; set; } = true; /// /// Function that determines if the row is displayed when filtered /// /// Parameter 1: The value of the filter item /// /// /// Parameter 2: The value of the column /// /// [Parameter] public Expression> OnFilter { get; set; } private TableFilterType _columnFilterType; private Type _columnDataType; public string? DisplayName { get; private set; } public string FieldName { get; private set; } public ITableSortModel SortModel { get; private set; } public ITableFilterModel FilterModel { get; private set; } private SortDirection _sortDirection; public Func GetValue { get; private set; } public LambdaExpression GetFieldExpression { get; private set; } void IFieldColumn.ClearSorter() { SetSorter(SortDirection.None); if (FieldExpression == null) { StateHasChanged(); } } private static readonly EventCallbackFactory _callbackFactory = new EventCallbackFactory(); private bool _filterOpened; private bool _hasFilterSelected; private string[] _selectedFilterValues; private ElementReference _filterTriggerRef; protected override void OnInitialized() { base.OnInitialized(); Sortable = Sortable || SorterMultiple != default || SorterCompare != default || DefaultSortOrder != default || SortDirections?.Any() == true; if (IsHeader) { if (FieldExpression != null) { if (FieldExpression.Body is not MemberExpression memberExp) { throw new ArgumentException("'Field' parameter must be child member"); } var paramExp = Expression.Parameter(ItemType); var bodyExp = Expression.MakeMemberAccess(paramExp, memberExp.Member); GetFieldExpression = Expression.Lambda(bodyExp, paramExp); } else if (DataIndex != null) { (_, GetFieldExpression) = ColumnDataIndexHelper.GetDataIndexConfig(this); } if (GetFieldExpression != null) { var member = ColumnExpressionHelper.GetReturnMemberInfo(GetFieldExpression); DisplayName = member?.GetCustomAttribute(true)?.DisplayName ?? member?.GetCustomAttribute(true)?.GetName() ?? member?.Name; FieldName = DataIndex ?? member?.Name; } if (Sortable && GetFieldExpression != null) { SortModel = new SortModel(GetFieldExpression, FieldName, SorterMultiple, DefaultSortOrder, SorterCompare); } } else if (IsBody) { SortModel = Context.HeaderColumns[ColIndex] is IFieldColumn fieldColumn ? fieldColumn.SortModel : null; (GetValue, _) = ColumnDataIndexHelper.GetDataIndexConfig(this); } SortDirections ??= Table.SortDirections; Sortable = Sortable || SortModel != null; _sortDirection = SortModel?.SortDirection ?? DefaultSortOrder ?? SortDirection.None; if (Filters?.Any() == true) { Filterable = true; _columnFilterType = TableFilterType.List; } else if (Filterable) { _columnDataType = THelper.GetUnderlyingType(); if (_columnDataType == typeof(bool)) { _columnFilterType = TableFilterType.List; Filters = new List>(); var trueFilterOption = GetNewFilter(); trueFilterOption.Text = Table.Locale.FilterOptions.True; trueFilterOption.Value = THelper.ChangeType(true); ((List>)Filters).Add(trueFilterOption); var falseFilterOption = GetNewFilter(); falseFilterOption.Text = Table.Locale.FilterOptions.False; falseFilterOption.Value = THelper.ChangeType(false); ((List>)Filters).Add(falseFilterOption); } else { _columnFilterType = TableFilterType.FieldType; InitFilters(); } } ClassMapper .If("ant-table-column-has-sorters", () => Sortable) .If($"ant-table-column-sort", () => Sortable && SortModel != null && SortModel.SortDirection.IsIn(SortDirection.Ascending, SortDirection.Descending)); } private string NumberFormatter(TData value) { if (value == null) return null; return Convert.ToDouble(value).ToString(Format); } private void HandleSort() { if (Sortable) { SetSorter(NextSortDirection()); Table.ColumnSorterChange(this); } } private string SorterTooltip { get { var next = NextSortDirection(); return next?.Value switch { 0 => Table.Locale.CancelSort, 1 => Table.Locale.TriggerAsc, 2 => Table.Locale.TriggerDesc, _ => Table.Locale.CancelSort }; } } private SortDirection NextSortDirection() { if (_sortDirection == SortDirection.None) { return SortDirections[0]; } else { var index = Array.IndexOf(SortDirections, _sortDirection); if (index >= SortDirections.Length - 1) { return SortDirection.None; } return SortDirections[index + 1]; } } private void SetSorter(SortDirection sortDirection) { _sortDirection = sortDirection; SortModel?.SetSortDirection(sortDirection); } private void ToggleTreeNode() { bool expandValueBeforeChange = RowData.Expanded; RowData.Expanded = !RowData.Expanded; Table?.OnExpandChange(RowData.CacheKey); if (RowData.Expanded != expandValueBeforeChange) Table?.Refresh(); } private void SetFilterCompareOperator(TableFilter filter, TableFilterCompareOperator compareOperator) { filter.FilterCompareOperator = compareOperator; if (compareOperator == TableFilterCompareOperator.IsNull || compareOperator == TableFilterCompareOperator.IsNotNull) filter.Selected = true; } private void SetFilterCondition(TableFilter filter, TableFilterCondition filterCondition) { filter.FilterCondition = filterCondition; } private void SetFilterValue(TableFilter filter, TData value) { filter.Value = value; filter.Selected = true; } private void SetFilterValue(TableFilter filter, DateTime? value) { if (value == null) { filter.Value = default; filter.Selected = false; } else { filter.Value = (TData)Convert.ChangeType(value, typeof(DateTime), CultureInfo.InvariantCulture); filter.Selected = true; } } private DateTime? FilterDateTimeValue(TableFilter filter) { if (EqualityComparer.Default.Equals(filter.Value, default(TData))) { return null; } else { return Convert.ToDateTime(filter.Value); } } private void FilterSelected(TableFilter filter) { if (_columnFilterType == TableFilterType.FieldType) return; if (!FilterMultiple) { Filters.ForEach(x => x.Selected = false); filter.Selected = true; } else { filter.Selected = !filter.Selected; } _selectedFilterValues = Filters.Where(x => x.Selected).Select(x => x.Value.ToString()).ToArray(); StateHasChanged(); } private void FilterConfirm(bool isReset = false) { _filterOpened = false; if (!isReset && _columnFilterType == TableFilterType.FieldType) Filters?.ForEach(f => { if (!f.Selected && f.Value != null) f.Selected = true; }); _hasFilterSelected = Filters?.Any(x => x.Selected) == true; FilterModel = _hasFilterSelected ? new FilterModel(GetFieldExpression, FieldName, OnFilter, Filters.Where(x => x.Selected).ToList(), _columnFilterType) : null; Table?.ReloadAndInvokeChange(); } private void ResetFilters() { if (_columnFilterType == TableFilterType.List) { Filters.ForEach(x => x.Selected = false); } else { InitFilters(); } FilterConfirm(true); } private void AddFilter() { ((List>)Filters).Add(GetNewFilter()); } private void RemoveFilter(TableFilter filter) { ((List>)Filters).Remove(filter); } private TableFilter GetNewFilter() { return new TableFilter() { FilterCondition = TableFilterCondition.And, FilterCompareOperator = _columnDataType == typeof(string) ? TableFilterCompareOperator.Contains : TableFilterCompareOperator.Equals }; } private void InitFilters() { Filters = new List>() { GetNewFilter() }; } } }