如何使在通用组件中创建的属性可用于定义渲染片段内容
我是blazor的新手,正在尝试基于下面显示的模型制作一个通用CRUD组件。我的许多其他类都继承了这个模型,并且没有添加任何字段
public class BasicCatalogModel
{
[Key]
public virtual long Id { get; set; }
public virtual String Name { get; set; }
public virtual String Description { get; set; }
public virtual bool Enabled { get; set; }
}
然后我有一个通用的数据服务,它有一个这样的签名:
public class BasicCatalogService<T>: ICatalogService<T> where T: BasicCatalogModel
该服务被注入到";通用的";在我的CustomModelCRUD中创建的组件。我需要做的是为那些需要添加一两个额外字段的模型添加自定义列和自定义字段
<BasicCatalogCRUD TItem="CustomModel" DataService="@CustomService" CrudTitle="@modelLocalizer["Custom.crud.title"]">
<CustomColumns>
<div>HERE are my custom columns and this works since I don´t need to add a reference to the current item</div>
</CustomColumns>
<CustomFields>
I need to add a custom field where I use the currentItem created in BasicCatalogCRUD
I need to make the field visible here to add a custom Field to the form
<input value="currentItem.CustomField">
<CustomFields>
</BasicCatalogCRUD>
这是通用CRUD的一部分,因为它现在是
@inject IStringLocalizer<ModelResource> modelLocalizer
@inject NotificationService NotificationService
@inject DialogService DialogService
@typeparam TItem
<h1>@CrudTitle</h1>
<Columns>
//Columns Before
@CustomColumns
//Colums After
</Columns>
</div>
@code {
/// <summary>
/// The item I need to access in the RenderFragment CustomFields
/// </summary>
TItem currentItem;
[Parameter] public BasicCatalogoService<TItem> DataService { get; set; }
[Parameter] public String CrudTitle { get; set; }
[Parameter] public RenderFragment CustomColumns { get; set; }
///I also need to pass the CustomFields value to the Dialog
[Parameter] public RenderFragment CustomFields { get; set; }
/// <summary>
/// Here we load the generic Form on to a RadzedDialog
/// </summary>
void LoadDataOnForm(TItem objectInstance)
{
currentItem = objectInstance;
Dictionary<string, object> parameters = new Dictionary<string, object>();
parameters.Add("CurrentItem", objectInstance);
parameters.Add("FieldTitle", GetActionLabel());
parameters.Add("ItemGrid", itemGrid);
parameters.Add("LabelBuilder", labelBuilder);
parameters.Add("DataService", DataService);
//I add the parameter to the parameters and send it to the dialog.
parameters.Add("CustomFields", CustomFields);
DialogOptions dialogOptions = new DialogOptions() { Width = "700px", Height = "600px" };
DialogService.Open<BasicCatalogoForm<TItem>>(GetActionLabel(), parameters, dialogOptions);
}
}
最后是形式的代码
@inject IStringLocalizer<ModelResource> modelLocalizer
@inject IStringLocalizer<AppResource> appLocalizer
@inject NotificationService NotificationService
@inject DialogService DialogService
@typeparam TItem
@if (CurrentItem != null)
{
<RadzenTemplateForm TItem="TItem" Data="@CurrentItem" Submit=@OnSubmit InvalidSubmit=@OnInvalidSubmit>
<FluentValidationValidator />
<RadzenFieldset>
//Fields Before ...
//The fields should be inserted here
@CustomFields
</RadzenFieldset>
<RadzenButton ButtonType="ButtonType.Submit" Icon="save" Text="@appLocalizer["button.save.label"]" />
</RadzenTemplateForm>
}
@code {
[Parameter] public String FieldTitle { get; set; }
[Parameter] public TItem CurrentItem { get; set; }
[Parameter] public BasicCatalogoService<TItem> DataService { get; set; }
[Parameter] public RenderFragment CustomFields { get; set; }
}
我目前正在研究将数据传递到渲染片段(据我所知,这似乎并不能解决我的问题(和级联值(似乎也不是正确的选项(。那么,如何使currentItem在CustomModelCRUD中可用?
所以,我实际上错了,您可以使用RenderFragments来完成这一点。
首先,有必要将呈现片段添加到通用表单中。查找HERE:注释以查看它是在哪里添加的。通过这种方式,我们可以将类型为TItem的值传递给呈现片段
@typeparam TItem
@if (CurrentItem != null)
{
<RadzenTemplateForm TItem="TItem" Data="@CurrentItem" Submit=@OnSubmit InvalidSubmit=@OnInvalidSubmit>
<FluentValidationValidator />
<RadzenFieldset>
//Fields Before ...
//HERE : The fields should be inserted here but we need to check if
//we are receiving the fragment and if the currentItem is set.
//Adding the nullchecks also allows us to make the customFields an
//optional thing
@if (CustomFields != null && CurrentItem != null)
{
@CustomFields(CurrentItem)
}
//... Fields After
</RadzenFieldset>
<RadzenButton ButtonType="ButtonType.Submit" Icon="save" Text="@appLocalizer["button.save.label"]" />
</RadzenTemplateForm>
}
@code {
[Parameter] public String FieldTitle { get; set; }
[Parameter] public TItem CurrentItem { get; set; }
[Parameter] public BasicCatalogoService<TItem> DataService { get; set; }
[Parameter] public RenderFragment<TItem> CustomFields { get; set; } //HERE: This is how I added the render fragment
}
之后,我们需要将片段添加到Generic CRUD中。再次查找此处:评论。
@inject IStringLocalizer<ModelResource> modelLocalizer
@inject NotificationService NotificationService
@inject DialogService DialogService
@typeparam TItem
<h1>@CrudTitle</h1>
<Columns>
//Columns Before
//HERE: We also need to to a null check for the custom
//columns to make them optional
@if (CustomColumns != null)
{
@CustomColumns
}
//Colums After
</Columns>
</div>
@code {
/// <summary>
/// The item I need to access in the RenderFragment CustomFields
/// </summary>
TItem currentItem;
[Parameter] public BasicCatalogoService<TItem> DataService { get; set; }
[Parameter] public String CrudTitle { get; set; }
//HERE: the custom colums stay as they are.
[Parameter] public RenderFragment CustomColumns { get; set; }
//HERE: We add the RenderFragment. The fragment MUST have the same signature
//as the one in the Generic Form above
[Parameter] public RenderFragment<TItem> CustomFields { get; set; }
/// <summary>
/// Here we load the generic Form on to a RadzedDialog
/// </summary>
void LoadDataOnForm(TItem objectInstance)
{
currentItem = objectInstance;
Dictionary<string, object> parameters = new Dictionary<string, object>();
parameters.Add("CurrentItem", objectInstance);
parameters.Add("FieldTitle", GetActionLabel());
parameters.Add("ItemGrid", itemGrid);
parameters.Add("LabelBuilder", labelBuilder);
parameters.Add("DataService", DataService);
//HERE: The super important part. it is necessary to do a null check, and pass the CustomFields to the
//generic form. DO NOT do it like this: parameters.Add("CustomFields", CustomFields(CurrentItem));
if (CustomFields != null)
{
parameters.Add("CustomFields", CustomFields);
}
DialogOptions dialogOptions = new DialogOptions() { Width = "700px", Height = "600px" };
DialogService.Open<BasicCatalogoForm<TItem>>(GetActionLabel(), parameters, dialogOptions);
}
}
最后,我们需要在CustomModelCRUD 中声明片段
<BasicCatalogCRUD TItem="CustomModel" DataService="@CustomModelService" CrudTitle="Custom Model CRUD">
@*HERE: this is optional and the models that follow the BasicCatalogModel don´t need to add this.*@
<CustomColumns>
<RadzenGridColumn TItem="CustomModel" Property="CustomProperty" Title="Custom Property" />
</CustomColumns>
@*HERE: this is optional and the models that follow the BasicCatalogModel don´t need to add this.*@
<CustomFields>
@*HERE: we can access the value of the CurrentItem in the BasicCatalogCRUD using the context keyword*@
@*but we must Make a NullCheck because when the BasicCatalogCRUD is initialized there might be no*@
@*current Item set and a nullPointer Exception could be thrown. *@
@if (context != null)
{
<div class="row">
<div class="col-md-4 align-items-center">
<RadzenLabel Text="@modelLocalizer["prioridad.field.CustomProperty.label"]" />
</div>
<div class="col-md-8">
<RadzenNumeric TValue="int" Min="1" Max="100" @bind-Value="context.CustomProperty" />
<span class="field-error-message"><ValidationMessage For="@(() => context.CustomProperty)" /></span>
</div>
</div>
}
</CustomFields>
</BasicCatalogCRUD>
由于CRUD和DialogForm是通用的,我们也可以在不需要CustomColums
和CustomFields
标签的情况下创建其他CRUD
<BasicCatalogCRUD TItem="NormalModel" DataService="@NormalModelService" CrudTitle="Custom Model CRUD"></BasicCatalogCRUD>
这样,我终于得到了通用CRUD和通用表单对话框,它们可以根据我的需要添加可选的列和字段。