Blazor создает общий раскрывающийся список

#components #blazor #blazor-server-side

#Компоненты #блейзор #blazor-серверная часть

Вопрос:

Я пытаюсь создать универсальный раскрывающийся компонент для использования в нашей системе. Однако я сталкиваюсь с проблемами при привязке EventCallback при изменении выбранного элемента.

Это мои текущие размышления по поводу общего выпадающего списка:

 lt;div class="inputItem @(SizeClass) dropdown" style="min-width:@(Width);"gt;  lt;SfDropDownList TItem="object" TValue="int" Placeholder="Select a category" DataSource="DataSource" Value="@(SelectedItem)" EnableVirtualization="true"gt;  lt;DropDownListEvents TItem="object" TValue="int" ValueChange="@OnSelectedItemChanged"gt;lt;/DropDownListEventsgt;  lt;DropDownListFieldSettings Text="@(TextField)" Value="@(ValueField)" /gt;  lt;/SfDropDownListgt; lt;/divgt;  @code {  [Parameter]  public IEnumerablelt;objectgt; DataSource { get; set; }   [Parameter]  public EventCallbacklt;ChangeEventArgslt;int, objectgt;gt; OnSelectedItemChanged { get; set; }   [Parameter]  public string Placeholder { get; set; }   [Parameter]  public string TextField { get; set; }   [Parameter]  public int SelectedItem { get; set; }   [Parameter]  public string ValueField { get; set; }   [Parameter]  public string Width { get; set; }   [Parameter]  public string SizeClass { get; set; }  }  

И вот один пример компонента, который назвал бы это:

 @page "/news/create" @inject NavigationManager NavManager; @using Microsoft.EntityFrameworkCore; @inject IDbContextFactorylt;FIS2_DbContextgt; contextFactory; @inject IFileService fileService; @using FIS2withSyncfusion.Controls; @using FIS2withSyncfusion.Models; @using FIS2withSyncfusion.Utility; @using Syncfusion.Blazor.RichTextEditor; @using System.Collections.Generic; @using System.Threading.Tasks; @using Newtonsoft.Json;  lt;div class="dashWrapper"gt;  lt;SfDashboardLayout AllowDragging="false" AllowFloating="false" AllowResizing="false" CellAspectRatio="2.5" CellSpacing="@(new double[]{20,20})" Columns="3"gt;  lt;DashboardLayoutPanelsgt;  lt;DashboardLayoutPanel Column="0" Row="0" SizeX="2" SizeY="2" Id="createNews"gt;  lt;HeaderTemplategt;  lt;h3gt;Create A News Itemlt;/h3gt;  lt;/HeaderTemplategt;  lt;ContentTemplategt;  lt;div class="form-wrapper"gt;  lt;div class="inputRow"gt;  lt;TextBox AutoComplete="@(Syncfusion.Blazor.Inputs.AutoComplete.Off)" Placeholder="Title" Text="@(title)" HTMLAttributes="@textboxValidation" Width="450px" SizeClass="half-width"gt;lt;/TextBoxgt;  lt;DropDownList DataSource="categories" Placeholder="Select a category" SizeClass="half-width" Width="450px" TextField="name" ValueField="id" SelectedItem="@(itemModel.Category)" OnSelectedItemChanged="@(OnSelectedItemChanged)"gt;lt;/DropDownListgt;  @*lt;SfDropDownList TItem="spGetNewsCategoriesResult" TValue="int" Placeholder="Select a category" @ref="sfDropDown" DataSource="categories" CssClass="inputItem half-width" @bind-Value="@(itemModel.Category)"gt;  lt;DropDownListFieldSettings Text="name" Value="id" /gt;  lt;/SfDropDownListgt;*@  lt;/divgt;  lt;div class="inputRow"gt;  lt;CheckBox Checked="isChecked" Label="Suggest Dates This Should Be Active?" OnCheckChange="@(OnCheckChange)" SizeClass="one-third" Width="300px"gt;lt;/CheckBoxgt;  @if (isChecked)  {  lt;DateTimePicker Label="Active From:" SelectedDate="@activeFrom" Width="450px" SizeClass="one-third"gt;lt;/DateTimePickergt;  lt;DateTimePicker Label="Active To:" SelectedDate="@activeTo" Width="450px" SizeClass="one-third"gt;lt;/DateTimePickergt;  }  lt;/divgt;  lt;div class="inputRow"gt;  lt;FileUploader MaxSize="@(MaxSize)" OnClearFiles="OnClearFiles" OnFileRemove="OnFileRemove" OnFileUpload="OnFileUpload" SizeClass="full-width" Width="400px"gt;lt;/FileUploadergt;  lt;/divgt;  lt;RichTextEditor DeniedAttributes="@DeniedAttributes" text=@(itemModel.Content) Height="400px" Width="1600px"gt;lt;/RichTextEditorgt;  lt;/divgt;  lt;/ContentTemplategt;  lt;/DashboardLayoutPanelgt;  lt;/DashboardLayoutPanelsgt;  lt;/SfDashboardLayoutgt; lt;/divgt;  @if (ShowDialog) {  lt;Dialog Title="Create News Item" message="@Message" OKText="@OKText" cancelText="@CancelText" OnClose="OnDialogClose"gt;  lt;/Dialoggt; }  @code {  [CascadingParameter]  Tasklt;AuthenticationStategt; authenticationStateTask { get; set; }   public string userName { get; set; }   private int MaxSize { get; set; }   private string title { get; set; }  private int selectedCategory { get; set; }  private string content { get; set; }  int count { get; set; }   private bool ShowDialog { get; set; } = false;  private string Message { get; set; } = "";  private string OKText { get; set; } = "";  private string CancelText { get; set; } = "";   public DateTime activeTo { get; set; }  public DateTime activeFrom { get; set; }   private bool isChecked { get; set; }   SaveNewsItemModel itemModel = new SaveNewsItemModel();   Listlt;stringgt; DeniedAttributes = new Listlt;stringgt;() {  "id", "title", "style"  };   Dictionarylt;string, objectgt; textboxValidation = new Dictionarylt;string, objectgt;(){  {"maxlength", "100"}  };   Listlt;spGetNewsCategoriesResultgt; categories = new Listlt;spGetNewsCategoriesResultgt;();   private async Task OnCheckChange(bool check)  {  isChecked = check;  StateHasChanged();  }   protected override async Task OnAfterRenderAsync(bool firstRender)  {  if (firstRender)  {  var authState = await authenticationStateTask;  var user = authState.User;  userName = user.Identity.Name;  var context = contextFactory.CreateDbContext();  var procedures = context.Procedures;   categories = await procedures.spGetNewsCategoriesAsync();   MaxSize = 15 * 1024 * 1024;  }  }   private Listlt;ToolbarItemModelgt; Tools = new Listlt;ToolbarItemModelgt;() {  new ToolbarItemModel()  {  Command = ToolbarCommand.Bold  },  new ToolbarItemModel()  {  Command = ToolbarCommand.Italic  },  new ToolbarItemModel()  {  Command= ToolbarCommand.Underline  },  new ToolbarItemModel()  {  Command= ToolbarCommand.Separator  },  new ToolbarItemModel()  {  Command = ToolbarCommand.Undo  },  new ToolbarItemModel()  {  Command = ToolbarCommand.Redo  },  new ToolbarItemModel()  {  Command= ToolbarCommand.Separator  },  new ToolbarItemModel()  {  Command = ToolbarCommand.OrderedList  },  new ToolbarItemModel()  {  Command = ToolbarCommand.UnorderedList  },  new ToolbarItemModel()  {  Command = ToolbarCommand.Separator  },  new ToolbarItemModel()  {  Command = ToolbarCommand.FontColor  },  new ToolbarItemModel()  {  Command = ToolbarCommand.CreateLink  },  new ToolbarItemModel()  {  Command = ToolbarCommand.RemoveLink  }  };   private async Task OnFileUpload(UploadChangeEventArgs args)  {  foreach (var file in args.Files)  {  var fileName = file.FileInfo.Name;  using (var ms = file.Stream)  {  System.IO.FileInfo fileInfo = new System.IO.FileInfo(fileName);  int count = 1;  string tempFileName = fileName;  while (fileService.TempFileExists(tempFileName))  {  tempFileName = $"({count}) {fileName}";  count  ;  }   var bytes = ms.ToArray();  await fileService.SaveFileToTempAsync(bytes, tempFileName);  var mimetype = fileInfo.Extension;  itemModel.AddFile(fileName, mimetype, tempFileName, contextFactory);  }  }  }   private async Task OnClearFiles(ClearingEventArgs args)  {  foreach (var file in args.FilesData)  {  var fileName = file.Name;  System.IO.FileInfo fileInfo = new System.IO.FileInfo(fileName);  itemModel.RemoveFile(fileName, fileInfo.Extension, contextFactory, fileService);  }  }   private async Task OnFileRemove(RemovingEventArgs args)  {  foreach (var file in args.FilesData)  {  var fileName = file.Name;  System.IO.FileInfo fileInfo = new System.IO.FileInfo(fileName);  itemModel.RemoveFile(fileName, fileInfo.Extension, contextFactory, fileService);  }  }   private async Task OnSelectedItemChanged(ChangeEventArgslt;int, spGetNewsCategoriesResultgt; eventArgs)  {  itemModel.Category = eventArgs.Value;  StateHasChanged();  }   private async Task OnSave()  {  if (isChecked)  {  itemModel.RequestDates(activeFrom, activeTo);  }   var context = contextFactory.CreateDbContext();  var procedures = context.Procedures;  var addedFiles = await procedures.spCreateNewsItemAsync(JsonConvert.SerializeObject(itemModel), userName);   if (addedFiles.Count gt; 0)  {  foreach (var file in addedFiles)  {  await fileService.MoveTempToNewsAsync(file.fileName, file.newsID, file.fileID);  }  }   Message = "This has been successfully saved and is now pending review; pressing OK will refresh the page.";  OKText = "OK";  ShowDialog = true;  }   private async Task OnDialogClose(bool r)  {  ShowDialog = false;  NavManager.NavigateTo(NavManager.Uri, true);  } }  

Моя проблема в том, что на данный момент я получаю ошибку: OnSelectedItemChanged="@(OnSelectedItemChanged)"

Ошибка в том, что:

Не удается преобразовать из method group в EventCallback

Охота, которую я провел, похоже, подразумевает, что мне нужно явно передать тип в качестве параметра, вместо того, чтобы использовать object и пытаться вывести его во время выполнения — я просто немного запутался в деталях того, как это сделать?

TValue быть собой int -это то, что нигде не должно меняться. Но TItem это может быть что угодно (в данном конкретном сценарии это а spGetNewsCategoriesResult ) — как мне это удовлетворить?

Ответ №1:

После долгих поисков и возни я нашел решение. Изменив компонент на этот:

 @typeparam T  lt;div class="inputItem @(SizeClass) dropdown" style="min-width:@(Width);"gt;  lt;SfDropDownList TItem="T" TValue="int" Placeholder="Select a category" DataSource="DataSource" Value="@(SelectedItem)" EnableVirtualization="true"gt;  lt;DropDownListEvents TItem="T" TValue="int" ValueChange="@OnSelectedItemChanged"gt;lt;/DropDownListEventsgt;  lt;DropDownListFieldSettings Text="@(TextField)" Value="@(ValueField)" /gt;  lt;/SfDropDownListgt; lt;/divgt;  @code {  [Parameter]  public IEnumerablelt;Tgt; DataSource { get; set; }   [Parameter]  public EventCallbacklt;Syncfusion.Blazor.DropDowns.ChangeEventArgslt;int, Tgt;gt; OnSelectedItemChanged { get; set; }   [Parameter]  public string Placeholder { get; set; }   [Parameter]  public string TextField { get; set; }   [Parameter]  public int SelectedItem { get; set; }   [Parameter]  public string ValueField { get; set; }   [Parameter]  public string Width { get; set; }   [Parameter]  public string SizeClass { get; set; }  }  

И ссылаться на него как на таковое:

 lt;DropDownList DataSource="categories" Placeholder="Select a category" SizeClass="half-width" Width="450px" TextField="name" ValueField="id" SelectedItem="@(itemModel.Category)" OnSelectedItemChanged="@(OnSelectedItemChanged)" T="spGetNewsCategoriesResult"gt;lt;/DropDownListgt;  

Ошибка устранена. Решил ответить на свой собственный вопрос, а не просто удалить его, потому что я подумал, что он, вероятно, появится у людей в их собственном поиске.