Open Kerminator1973 opened 6 months ago
Типовое использование:
SortKeySelector="item => item.DOJ"
Определение:
/// <summary>
/// Selector function of sorting key. To be used for automatic in-memory sorting.
/// </summary>
public Expression<Func<TItem, IComparable>> SortKeySelector { get; }
"blazorbootstrap\blazorbootstrap\Models\SortingItem.cs" можно исключать из рассмотрения, т.к. это просто контейнер свойств (sealed).
С высокой вероятностью, смотреть нужно реализацию класса GridColumn:
public partial class GridColumn<TItem> : BlazorBootstrapComponentBase
Перспективными для анализа кажется private RenderFragment? headerTemplate;
с которым связан публичный параметр HeaderContent.
Однако, в официальной документации, в разделе "Custom column headers" указывается, что когда мы определяем содержимое заголовка, фильтрация и сортировка отключаются в колонке. Т.е. это совсем не то, что нам нужно.
Код, в котором определены условия отбора:
public static IEnumerable<FilterOperatorInfo> GetDateFilterOperators()
{
List<FilterOperatorInfo> result = new()
{
new FilterOperatorInfo("=", "Equals", FilterOperator.Equals),
new FilterOperatorInfo("!=", "Not equals", FilterOperator.NotEquals),
new FilterOperatorInfo("<", "Less than", FilterOperator.LessThan),
new FilterOperatorInfo("<=", "Less than or equals", FilterOperator.LessThanOrEquals),
new FilterOperatorInfo(">", "Greater than", FilterOperator.GreaterThan),
new FilterOperatorInfo(">=", "Greater than or equals", FilterOperator.GreaterThanOrEquals),
new FilterOperatorInfo("x", "Clear", FilterOperator.Clear)
};
return result;
}
Решение проблемы выглядит следующим: создаются два невидимых поля с датой и для этих полей устанавливается фильтры: для первого - Greater than or equals, а для второго - Less than or equals. Третье поле с датами делается видимым, но по нему блокируется фильтрация. Наша задача, устанавливать условия отбора данных в невидимых полях по значениям во внешних полях.
Попробовать скрыть колонку можно установив ColumnClass в hidden значение.
Нужно научиться устанавливать свойства заголовка Grid-а и его отдельных колонок. Нас интересуют FilterValue
<GridColumn TItem="Employee1"
HeaderText="Active"
PropertyName="IsActive"
SortKeySelector="item => item.IsActive"
ColumnClass="@(x => x.IsActive ? "table-success" : "table-danger")">
Вот ещё перспективное поле RowClass.
Мы можем спрятать колонку таблицы через F12 Developer Console, если установить свойство у th: style="display:none
, то скроется только заголовок колонки.
Если выполнить вот такой код:
.column-hidden {
visibility: collapse
}
<GridColumn TItem="Employee1"
ColumnClass="@(x => true ? "column-hidden" : "column-hidden")"
HeaderText="DOJ" PropertyName="DOJ" SortKeySelector="item => item.DOJ">
То скроется только колонка, но без заголовка и блока фильтрации.
Такое ощущение, что ColumnClass применяется только к ячейкам с данными.
Проблема в том, что у Grid есть два блока th для каждой колонки. Одна для названия заголовка, а вторая для условия - они находятся в разным tr. Сами данные - в td.
Однако, вот такой вариант сработает успешно (нужно будет только добавить стиль конкретной таблицы, чтобы не прятать всё):
tr > *:nth-child(4) {
display: none;
}
Вот такое комбинированное решение работает:
tr > *:nth-child(5) {
display: none;
}
tr > *:nth-child(6) {
display: none;
}
<GridColumn TItem="Employee1" Filterable="false" HeaderText="DOJ" PropertyName="DOJ" SortKeySelector="item => item.DOJ">
@context.DOJ
</GridColumn>
<GridColumn TItem="Employee1" FilterOperator="FilterOperator.LessThanOrEquals" FilterValue="1995.1.1" HeaderText="DOJ" PropertyName="DOJ" SortKeySelector="item => item.DOJ">
@context.DOJ
</GridColumn>
<GridColumn TItem="Employee1" FilterOperator="FilterOperator.GreaterThanOrEquals" FilterValue="1980.1.1" HeaderText="DOJ" PropertyName="DOJ" SortKeySelector="item => item.DOJ">
@context.DOJ
</GridColumn>
Нужно только придумать, как устанавливать FilterValue динамически.
Инициализация фильтра внешним параметром работает (см. @beginDataFilter), но я пока не понимаю, как сделать динамическую привязку...
<div class="mb-3">
<strong>Begin Date:</strong>:
</div>
<div class="mb-3">
<DateInput TValue="DateOnly" @bind-Value="@BeginDate" Placeholder="Enter Date" />
<Button Color="ButtonColor.Primary" Size="Size.Medium" @onclick="ChangeFilter">Set Filter</Button>
</div>
@code {
public DateOnly BeginDate = DateOnly.FromDateTime(DateTime.Now.AddYears(-64));
private void ChangeFilter() {
// Устанавливаем данные фильтра начала даты пересчёта
beginDataFilter = BeginDate.ToString("yyyy/MM/dd");
// В GridColumn есть private member:
//private async Task OnFilterValueChangedAsync(ChangeEventArgs args)
//<input class="form-control" style="@filterStyle" type="datetime-local" value="@filterValue" @oninput="@(async args => await OnFilterValueChangedAsync(args))"/>
// FilterValue - Это публичный параметр. Если его найти, то его можно изменить
}
private string beginDataFilter = "1980.1.1";
}
<GridColumn TItem="Employee1" FilterOperator="FilterOperator.GreaterThanOrEquals" FilterValue="@beginDataFilter" HeaderText="DOJ" PropertyName="DOJ" SortKeySelector="item => item.DOJ">
@context.DOJ
</GridColumn>
Используя JS-код можно установить значение поля, но это не повлияет на фильтрацию (экспериментально доказано):
<script>
window.updateFilterValue = (filterValue) => {
console.log('Filter value: ' + filterValue);
const elem = document.querySelector("table>thead>tr:nth-child(2)>th:nth-child(2)>div>input");
console.dir(elem);
if (elem) {
elem.value = filterValue;
}
};
</script>
@code {
public DateOnly BeginDate = DateOnly.FromDateTime(DateTime.Now.AddYears(-64));
private async void ChangeFilter() {
// Устанавливаем данные фильтра начала даты пересчёта
beginDataFilter = BeginDate.ToString("yyyy/MM/dd");
// В GridColumn есть private member:
//private async Task OnFilterValueChangedAsync(ChangeEventArgs args)
//<input class="form-control" style="@filterStyle" type="datetime-local" value="@filterValue" @oninput="@(async args => await OnFilterValueChangedAsync(args))"/>
// FilterValue - Это публичный параметр. Если его найти, то его можно изменить
await JS.InvokeVoidAsync("updateFilterValue", beginDataFilter);
}
private string beginDataFilter = "1980.1.1";
}
Получить доступ к фильтрам можно через GridSetting, но только на чтение, не ко всем полям и только при изменении какого-то другого фильтра:
private async Task OnGridSettingsChanged(GridSettings settings)
{
Settings = settings;
}
JSON, с которым умеет работать Settings, может выглядеть так:
{
"PageNumber": 1,
"PageSize": 8,
"Filters": [
{
"PropertyName": "Name",
"Value": "Ron",
"Operator": 7,
"StringComparison": 5
},
{
"PropertyName": "DOJ",
"Value": "1995.1.1",
"Operator": 4,
"StringComparison": 5
},
{
"PropertyName": "DOJ",
"Value": "1980.1.1",
"Operator": 6,
"StringComparison": 5
}
]
}
Работает вот такой вариант:
<script>
window.updateFilterValue = (filterValue) => {
console.log('Filter value: ' + filterValue);
const elem = document.querySelector("table>thead>tr:nth-child(2)>th:nth-child(2)>div>input");
if (elem) {
elem.value = filterValue;
var event = new Event('input', {
bubbles: true,
});
elem.dispatchEvent(event);
}
};
</script>
Если мы не используем дату, для видимого поля всё работает как нужно:
<div class="mb-3">
<strong>Begin Date:</strong>:
</div>
<div class="mb-3">
<input TValue="string" @bind-value="@BeginDate" Placeholder="Enter Date" />
<Button Color="ButtonColor.Primary" Size="Size.Medium" @onclick="ChangeFilter">Set Filter</Button>
</div>
<script>
window.updateFilterValue = (filterValue) => {
const elem = document.querySelector("table>thead>tr:nth-child(2)>th:nth-child(2)>div>input");
if (elem) {
elem.value = filterValue;
var event = new Event('input', {
bubbles: true,
});
elem.dispatchEvent(event);
}
};
</script>
@code {
//public DateOnly BeginDate = DateOnly.FromDateTime(DateTime.Now.AddYears(-64));
public String BeginDate = "";
private async void ChangeFilter() {
await JS.InvokeVoidAsync("updateFilterValue", BeginDate);
}
private string beginDataFilter = "1980.1.1";
}
С невидимым полем всё работает отлично:
tr > *:nth-child(2) {
display: none;
}
Т.е. проблема с датами, вероятно, в формате даты.
Вот такой вариант работает как нужно:
@code {
public DateOnly BeginDate = DateOnly.FromDateTime(DateTime.Now.AddYears(-64));
private async void ChangeFilter() {
// Устанавливаем данные фильтра начала даты пересчёта
beginDataFilter = BeginDate.ToString("yyyy-MM-dd");
await JS.InvokeVoidAsync("updateFilterValue", beginDataFilter);
}
private string beginDataFilter = "1980.1.1";
}
В целом, задача решена.
Начальная точка поиска - свойство SortKeySelector.
Скачал исходники Blazor Bootstrap, начинаю исследование кода.