Blazor 创建通用下拉菜单
Posted
技术标签:
【中文标题】Blazor 创建通用下拉菜单【英文标题】:Blazor creating a generic drop-down 【发布时间】:2022-01-12 17:36:37 【问题描述】:我正在尝试创建一个通用的下拉组件,以便在我们的系统中使用。但是,在更改所选项目时绑定EventCallback
时遇到问题。
这是我目前对通用下拉菜单的思考:
<div class="inputItem @(SizeClass) dropdown" style="min-width:@(Width);">
<SfDropDownList TItem="object" TValue="int" Placeholder="Select a category" DataSource="DataSource" Value="@(SelectedItem)" EnableVirtualization="true">
<DropDownListEvents TItem="object" TValue="int" ValueChange="@OnSelectedItemChanged"></DropDownListEvents>
<DropDownListFieldSettings Text="@(TextField)" Value="@(ValueField)" />
</SfDropDownList>
</div>
@code
[Parameter]
public IEnumerable<object> DataSource get; set;
[Parameter]
public EventCallback<ChangeEventArgs<int, object>> 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 IDbContextFactory<FIS2_DbContext> 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;
<div class="dashWrapper">
<SfDashboardLayout AllowDragging="false" AllowFloating="false" AllowResizing="false" CellAspectRatio="2.5" CellSpacing="@(new double[]20,20)" Columns="3">
<DashboardLayoutPanels>
<DashboardLayoutPanel Column="0" Row="0" SizeX="2" SizeY="2" Id="createNews">
<HeaderTemplate>
<h3>Create A News Item</h3>
</HeaderTemplate>
<ContentTemplate>
<div class="form-wrapper">
<div class="inputRow">
<TextBox AutoComplete="@(Syncfusion.Blazor.Inputs.AutoComplete.Off)" Placeholder="Title" Text="@(title)" htmlAttributes="@textboxValidation" Width="450px" SizeClass="half-width"></TextBox>
<DropDownList DataSource="categories" Placeholder="Select a category" SizeClass="half-width" Width="450px" TextField="name" ValueField="id" SelectedItem="@(itemModel.Category)" OnSelectedItemChanged="@(OnSelectedItemChanged)"></DropDownList>
@*<SfDropDownList TItem="spGetNewsCategoriesResult" TValue="int" Placeholder="Select a category" @ref="sfDropDown" DataSource="categories" CssClass="inputItem half-width" @bind-Value="@(itemModel.Category)">
<DropDownListFieldSettings Text="name" Value="id" />
</SfDropDownList>*@
</div>
<div class="inputRow">
<CheckBox Checked="isChecked" Label="Suggest Dates This Should Be Active?" OnCheckChange="@(OnCheckChange)" SizeClass="one-third" Width="300px"></CheckBox>
@if (isChecked)
<DateTimePicker Label="Active From:" SelectedDate="@activeFrom" Width="450px" SizeClass="one-third"></DateTimePicker>
<DateTimePicker Label="Active To:" SelectedDate="@activeTo" Width="450px" SizeClass="one-third"></DateTimePicker>
</div>
<div class="inputRow">
<FileUploader MaxSize="@(MaxSize)" OnClearFiles="OnClearFiles" OnFileRemove="OnFileRemove" OnFileUpload="OnFileUpload" SizeClass="full-width" Width="400px"></FileUploader>
</div>
<RichTextEditor DeniedAttributes="@DeniedAttributes" text=@(itemModel.Content) Height="400px" Width="1600px"></RichTextEditor>
</div>
</ContentTemplate>
</DashboardLayoutPanel>
</DashboardLayoutPanels>
</SfDashboardLayout>
</div>
@if (ShowDialog)
<Dialog Title="Create News Item" message="@Message" OKText="@OKText" cancelText="@CancelText" OnClose="OnDialogClose">
</Dialog>
@code
[CascadingParameter]
Task<AuthenticationState> 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();
List<string> DeniedAttributes = new List<string>()
"id", "title", "style"
;
Dictionary<string, object> textboxValidation = new Dictionary<string, object>()
"maxlength", "100"
;
List<spGetNewsCategoriesResult> categories = new List<spGetNewsCategoriesResult>();
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 List<ToolbarItemModel> Tools = new List<ToolbarItemModel>()
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(ChangeEventArgs<int, spGetNewsCategoriesResult> 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 > 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
<div class="inputItem @(SizeClass) dropdown" style="min-width:@(Width);">
<SfDropDownList TItem="T" TValue="int" Placeholder="Select a category" DataSource="DataSource" Value="@(SelectedItem)" EnableVirtualization="true">
<DropDownListEvents TItem="T" TValue="int" ValueChange="@OnSelectedItemChanged"></DropDownListEvents>
<DropDownListFieldSettings Text="@(TextField)" Value="@(ValueField)" />
</SfDropDownList>
</div>
@code
[Parameter]
public IEnumerable<T> DataSource get; set;
[Parameter]
public EventCallback<Syncfusion.Blazor.DropDowns.ChangeEventArgs<int, T>> 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;
并这样引用它:
<DropDownList DataSource="categories" Placeholder="Select a category" SizeClass="half-width" Width="450px" TextField="name" ValueField="id" SelectedItem="@(itemModel.Category)" OnSelectedItemChanged="@(OnSelectedItemChanged)" T="spGetNewsCategoriesResult"></DropDownList>
错误已解决。决定回答我自己的问题,而不是仅仅删除它,因为我认为它可能会在人们自己搜索时弹出。
【讨论】:
以上是关于Blazor 创建通用下拉菜单的主要内容,如果未能解决你的问题,请参考以下文章