diff --git a/framework/src/Volo.Abp.AspNetCore.Components.Server/Volo.Abp.AspNetCore.Components.Server.csproj b/framework/src/Volo.Abp.AspNetCore.Components.Server/Volo.Abp.AspNetCore.Components.Server.csproj
index e84d7fa8ea..050c438d11 100644
--- a/framework/src/Volo.Abp.AspNetCore.Components.Server/Volo.Abp.AspNetCore.Components.Server.csproj
+++ b/framework/src/Volo.Abp.AspNetCore.Components.Server/Volo.Abp.AspNetCore.Components.Server.csproj
@@ -11,6 +11,8 @@
+
+
diff --git a/framework/src/Volo.Abp.AspNetCore.Components.Server/Volo/Abp/AspNetCore/Components/Server/AbpAspNetCoreComponentsServerModule.cs b/framework/src/Volo.Abp.AspNetCore.Components.Server/Volo/Abp/AspNetCore/Components/Server/AbpAspNetCoreComponentsServerModule.cs
index 2fa745d9c5..dfd3cafce2 100644
--- a/framework/src/Volo.Abp.AspNetCore.Components.Server/Volo/Abp/AspNetCore/Components/Server/AbpAspNetCoreComponentsServerModule.cs
+++ b/framework/src/Volo.Abp.AspNetCore.Components.Server/Volo/Abp/AspNetCore/Components/Server/AbpAspNetCoreComponentsServerModule.cs
@@ -4,13 +4,17 @@ using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.FileProviders;
using Volo.Abp.AspNetCore.Auditing;
+using Volo.Abp.AspNetCore.Components.Web;
using Volo.Abp.AspNetCore.SignalR;
using Volo.Abp.AspNetCore.Uow;
+using Volo.Abp.Http.Client;
using Volo.Abp.Modularity;
namespace Volo.Abp.AspNetCore.Components.Server
{
[DependsOn(
+ typeof(AbpHttpClientModule),
+ typeof(AbpAspNetCoreComponentsWebModule),
typeof(AbpAspNetCoreSignalRModule)
)]
public class AbpAspNetCoreComponentsServerModule : AbpModule
diff --git a/framework/src/Volo.Abp.AspNetCore.Components.Server/Volo/Abp/AspNetCore/Components/Server/Extensibility/BlazorServerLookupApiRequestService.cs b/framework/src/Volo.Abp.AspNetCore.Components.Server/Volo/Abp/AspNetCore/Components/Server/Extensibility/BlazorServerLookupApiRequestService.cs
new file mode 100644
index 0000000000..b7e2de8364
--- /dev/null
+++ b/framework/src/Volo.Abp.AspNetCore.Components.Server/Volo/Abp/AspNetCore/Components/Server/Extensibility/BlazorServerLookupApiRequestService.cs
@@ -0,0 +1,92 @@
+using System;
+using System.Globalization;
+using System.Linq.Dynamic.Core;
+using System.Net.Http;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Components;
+using Microsoft.AspNetCore.Http;
+using Microsoft.Extensions.Options;
+using Microsoft.Extensions.Primitives;
+using Volo.Abp.AspNetCore.Components.Web.Extensibility;
+using Volo.Abp.DependencyInjection;
+using Volo.Abp.Http.Client;
+using Volo.Abp.Http.Client.Authentication;
+using Volo.Abp.MultiTenancy;
+
+namespace Volo.Abp.AspNetCore.Components.Server.Extensibility
+{
+ public class BlazorServerLookupApiRequestService : ILookupApiRequestService, ITransientDependency
+ {
+ public IHttpClientFactory HttpClientFactory { get; }
+ public IRemoteServiceHttpClientAuthenticator HttpClientAuthenticator { get; }
+
+ public AbpRemoteServiceOptions RemoteServiceOptions { get; }
+
+ public ICurrentTenant CurrentTenant { get; }
+ public IHttpContextAccessor HttpContextAccessor { get; }
+ public NavigationManager NavigationManager { get; }
+
+ public BlazorServerLookupApiRequestService(IHttpClientFactory httpClientFactory,
+ IRemoteServiceHttpClientAuthenticator httpClientAuthenticator,
+ ICurrentTenant currentTenant,
+ IOptions remoteServiceOptions,
+ IHttpContextAccessor httpContextAccessor,
+ NavigationManager navigationManager)
+ {
+ HttpClientFactory = httpClientFactory;
+ HttpClientAuthenticator = httpClientAuthenticator;
+ RemoteServiceOptions = remoteServiceOptions.Value;
+ CurrentTenant = currentTenant;
+ HttpContextAccessor = httpContextAccessor;
+ NavigationManager = navigationManager;
+ }
+
+ public async Task SendAsync(string url)
+ {
+ var client = HttpClientFactory.CreateClient();
+ var requestMessage = new HttpRequestMessage(HttpMethod.Get, url);
+
+ var uri = new Uri(url, UriKind.RelativeOrAbsolute);
+ if (!uri.IsAbsoluteUri)
+ {
+ var baseUrl = string.Empty;
+ try
+ {
+ //Blazor tiered -- mode
+ var remoteServiceConfig = RemoteServiceOptions.RemoteServices.GetConfigurationOrDefault("Default");
+ baseUrl = remoteServiceConfig.BaseUrl;
+ client.BaseAddress = new Uri(baseUrl);
+ AddHeaders(requestMessage);
+ await HttpClientAuthenticator.Authenticate(new RemoteServiceHttpClientAuthenticateContext(client,
+ requestMessage, new RemoteServiceConfiguration(baseUrl), string.Empty));
+ }
+ catch (AbpException) // Blazor-Server mode.
+ {
+ baseUrl = NavigationManager.BaseUri;
+ client.BaseAddress = new Uri(baseUrl);
+ foreach (var header in HttpContextAccessor.HttpContext.Request.Headers)
+ {
+ requestMessage.Headers.Add(header.Key, header.Value.ToArray());
+ }
+ }
+ }
+
+ var response = await client.SendAsync(requestMessage);
+ return await response.Content.ReadAsStringAsync();
+ }
+
+ protected virtual void AddHeaders(HttpRequestMessage requestMessage)
+ {
+ if (CurrentTenant.Id.HasValue)
+ {
+ requestMessage.Headers.Add(TenantResolverConsts.DefaultTenantKey, CurrentTenant.Id.Value.ToString());
+ }
+
+ var currentCulture = CultureInfo.CurrentUICulture.Name ?? CultureInfo.CurrentCulture.Name;
+ if (!currentCulture.IsNullOrEmpty())
+ {
+ requestMessage.Headers.AcceptLanguage.Add(new(currentCulture));
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/framework/src/Volo.Abp.BlazoriseUI/Components/PageHeader.razor b/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Layout/PageHeader.razor
similarity index 81%
rename from framework/src/Volo.Abp.BlazoriseUI/Components/PageHeader.razor
rename to framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Layout/PageHeader.razor
index 4a569cfe95..aec0eada09 100644
--- a/framework/src/Volo.Abp.BlazoriseUI/Components/PageHeader.razor
+++ b/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Layout/PageHeader.razor
@@ -1,4 +1,5 @@
-
+@using Blazorise
+
@@ -31,7 +32,12 @@
}
- @ChildContent
+ @foreach (var toolbarItemRender in ToolbarItemRenders)
+ {
+
+ @toolbarItemRender
+
+ }
-
\ No newline at end of file
+
diff --git a/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Layout/PageHeader.razor.cs b/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Layout/PageHeader.razor.cs
new file mode 100644
index 0000000000..365df5f713
--- /dev/null
+++ b/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/Layout/PageHeader.razor.cs
@@ -0,0 +1,78 @@
+using System;
+using Microsoft.AspNetCore.Components;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using Volo.Abp.AspNetCore.Components.Web.Theming.PageToolbars;
+using Volo.Abp.BlazoriseUI;
+
+namespace Volo.Abp.AspNetCore.Components.Web.Theming.Layout
+{
+ public partial class PageHeader : ComponentBase
+ {
+ protected List ToolbarItemRenders { get; set; }
+
+ public IPageToolbarManager PageToolbarManager { get; set; }
+
+ [Parameter]
+ public string Title { get; set; }
+
+ [Parameter]
+ public bool BreadcrumbShowHome { get; set; } = true;
+
+ [Parameter]
+ public bool BreadcrumbShowCurrent { get; set; } = true;
+
+ [Parameter]
+ public RenderFragment ChildContent { get; set; }
+
+ [Parameter]
+ public List BreadcrumbItems { get; set; }
+
+ [Parameter]
+ public PageToolbar Toolbar { get; set; }
+
+ [Parameter]
+ public string PageName { get; set; }
+
+ public PageHeader()
+ {
+ BreadcrumbItems = new List();
+ ToolbarItemRenders = new List();
+ }
+
+ protected override async Task OnParametersSetAsync()
+ {
+ await base.OnParametersSetAsync();
+ if (Toolbar!=null)
+ {
+ Console.WriteLine("Toolbar is not null");
+ var toolbarItems = await PageToolbarManager.GetItemsAsync(Toolbar);
+ Console.WriteLine($"Toolbar item count:{toolbarItems.Length}");
+ ToolbarItemRenders.Clear();
+
+ foreach (var item in toolbarItems)
+ {
+ var sequence = 0;
+ ToolbarItemRenders.Add(builder =>
+ {
+ builder.OpenComponent(sequence, item.ComponentType);
+ if (item.Arguments != null)
+ {
+ foreach (var argument in item.Arguments)
+ {
+ sequence++;
+ builder.AddAttribute(sequence, argument.Key, argument.Value);
+ }
+ }
+ builder.CloseComponent();
+ });
+ }
+ }
+ }
+
+ protected override async Task OnInitializedAsync()
+ {
+ await base.OnInitializedAsync();
+ }
+ }
+}
diff --git a/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/IPageToolbarContributor.cs b/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/IPageToolbarContributor.cs
new file mode 100644
index 0000000000..dd04c0a1ff
--- /dev/null
+++ b/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/IPageToolbarContributor.cs
@@ -0,0 +1,9 @@
+using System.Threading.Tasks;
+
+namespace Volo.Abp.AspNetCore.Components.Web.Theming.PageToolbars
+{
+ public interface IPageToolbarContributor
+ {
+ Task ContributeAsync(PageToolbarContributionContext context);
+ }
+}
diff --git a/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/IPageToolbarManager.cs b/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/IPageToolbarManager.cs
new file mode 100644
index 0000000000..507fa8070b
--- /dev/null
+++ b/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/IPageToolbarManager.cs
@@ -0,0 +1,9 @@
+using System.Threading.Tasks;
+
+namespace Volo.Abp.AspNetCore.Components.Web.Theming.PageToolbars
+{
+ public interface IPageToolbarManager
+ {
+ Task GetItemsAsync(PageToolbar toolbar);
+ }
+}
diff --git a/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/PageToolbar.cs b/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/PageToolbar.cs
new file mode 100644
index 0000000000..84a9bae7c4
--- /dev/null
+++ b/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/PageToolbar.cs
@@ -0,0 +1,12 @@
+namespace Volo.Abp.AspNetCore.Components.Web.Theming.PageToolbars
+{
+ public class PageToolbar
+ {
+ public PageToolbarContributorList Contributors { get; set; }
+
+ public PageToolbar()
+ {
+ Contributors = new PageToolbarContributorList();
+ }
+ }
+}
diff --git a/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/PageToolbarContributionContext.cs b/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/PageToolbarContributionContext.cs
new file mode 100644
index 0000000000..5544510b71
--- /dev/null
+++ b/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/PageToolbarContributionContext.cs
@@ -0,0 +1,21 @@
+using JetBrains.Annotations;
+using System;
+
+namespace Volo.Abp.AspNetCore.Components.Web.Theming.PageToolbars
+{
+ public class PageToolbarContributionContext
+ {
+ [NotNull]
+ public IServiceProvider ServiceProvider { get; }
+
+ [NotNull]
+ public PageToolbarItemList Items { get; }
+
+ public PageToolbarContributionContext(
+ [NotNull] IServiceProvider serviceProvider)
+ {
+ ServiceProvider = Check.NotNull(serviceProvider, nameof(serviceProvider));
+ Items = new PageToolbarItemList();
+ }
+ }
+}
diff --git a/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/PageToolbarContributor.cs b/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/PageToolbarContributor.cs
new file mode 100644
index 0000000000..3c5196c449
--- /dev/null
+++ b/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/PageToolbarContributor.cs
@@ -0,0 +1,9 @@
+using System.Threading.Tasks;
+
+namespace Volo.Abp.AspNetCore.Components.Web.Theming.PageToolbars
+{
+ public abstract class PageToolbarContributor : IPageToolbarContributor
+ {
+ public abstract Task ContributeAsync(PageToolbarContributionContext context);
+ }
+}
diff --git a/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/PageToolbarContributorList.cs b/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/PageToolbarContributorList.cs
new file mode 100644
index 0000000000..984f4618dc
--- /dev/null
+++ b/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/PageToolbarContributorList.cs
@@ -0,0 +1,8 @@
+using System.Collections.Generic;
+
+namespace Volo.Abp.AspNetCore.Components.Web.Theming.PageToolbars
+{
+ public class PageToolbarContributorList : List
+ {
+ }
+}
diff --git a/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/PageToolbarDictionary.cs b/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/PageToolbarDictionary.cs
new file mode 100644
index 0000000000..2368ab9caf
--- /dev/null
+++ b/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/PageToolbarDictionary.cs
@@ -0,0 +1,9 @@
+using System.Collections.Generic;
+
+namespace Volo.Abp.AspNetCore.Components.Web.Theming.PageToolbars
+{
+ public class PageToolbarDictionary : Dictionary
+ {
+
+ }
+}
diff --git a/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/PageToolbarExtensions.cs b/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/PageToolbarExtensions.cs
new file mode 100644
index 0000000000..3879e27e3c
--- /dev/null
+++ b/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/PageToolbarExtensions.cs
@@ -0,0 +1,71 @@
+using Blazorise;
+using System;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using Volo.Abp.BlazoriseUI.Components;
+using Volo.Abp.Localization;
+
+namespace Volo.Abp.AspNetCore.Components.Web.Theming.PageToolbars
+{
+ public static class PageToolbarExtensions
+ {
+ public static PageToolbar AddComponent(
+ this PageToolbar toolbar,
+ Dictionary arguments = null,
+ int order = 0,
+ string requiredPolicyName = null)
+ {
+ return toolbar.AddComponent(
+ typeof(TComponent),
+ arguments,
+ order,
+ requiredPolicyName
+ );
+ }
+
+ public static PageToolbar AddComponent(
+ this PageToolbar toolbar,
+ Type componentType,
+ Dictionary arguments = null,
+ int order = 0,
+ string requiredPolicyName = null)
+ {
+ toolbar.Contributors.Add(
+ new SimplePageToolbarContributor(
+ componentType,
+ arguments,
+ order,
+ requiredPolicyName
+ )
+ );
+
+ return toolbar;
+ }
+
+ public static PageToolbar AddButton(
+ this PageToolbar toolbar,
+ string text,
+ Func clicked,
+ object icon = null,
+ Color color = Color.Primary,
+ bool disabled = false,
+ int order = 0,
+ string requiredPolicyName = null)
+ {
+ toolbar.AddComponent(
+ new Dictionary
+ {
+ { nameof(ToolbarButton.Color), color},
+ { nameof(ToolbarButton.Text), text},
+ { nameof(ToolbarButton.Disabled), disabled},
+ { nameof(ToolbarButton.Icon), icon},
+ { nameof(ToolbarButton.Clicked),clicked},
+ },
+ order,
+ requiredPolicyName
+ );
+
+ return toolbar;
+ }
+ }
+}
diff --git a/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/PageToolbarItem.cs b/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/PageToolbarItem.cs
new file mode 100644
index 0000000000..0e1650a803
--- /dev/null
+++ b/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/PageToolbarItem.cs
@@ -0,0 +1,27 @@
+using JetBrains.Annotations;
+using System;
+using System.Collections.Generic;
+
+namespace Volo.Abp.AspNetCore.Components.Web.Theming.PageToolbars
+{
+ public class PageToolbarItem
+ {
+ [NotNull]
+ public Type ComponentType { get; }
+
+ [CanBeNull]
+ public Dictionary Arguments { get; set; }
+
+ public int Order { get; set; }
+
+ public PageToolbarItem(
+ [NotNull] Type componentType,
+ [CanBeNull] Dictionary arguments = null,
+ int order = 0)
+ {
+ ComponentType = Check.NotNull(componentType, nameof(componentType));
+ Arguments = arguments;
+ Order = order;
+ }
+ }
+}
diff --git a/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/PageToolbarItemList.cs b/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/PageToolbarItemList.cs
new file mode 100644
index 0000000000..7042b2ed05
--- /dev/null
+++ b/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/PageToolbarItemList.cs
@@ -0,0 +1,9 @@
+using System.Collections.Generic;
+
+namespace Volo.Abp.AspNetCore.Components.Web.Theming.PageToolbars
+{
+ public class PageToolbarItemList : List
+ {
+
+ }
+}
diff --git a/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/PageToolbarManager.cs b/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/PageToolbarManager.cs
new file mode 100644
index 0000000000..adcd72f25e
--- /dev/null
+++ b/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/PageToolbarManager.cs
@@ -0,0 +1,40 @@
+using Microsoft.Extensions.Options;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using Volo.Abp.DependencyInjection;
+
+namespace Volo.Abp.AspNetCore.Components.Web.Theming.PageToolbars
+{
+ public class PageToolbarManager : IPageToolbarManager, ITransientDependency
+ {
+ protected IHybridServiceScopeFactory ServiceScopeFactory { get; }
+
+ public PageToolbarManager(
+ IHybridServiceScopeFactory serviceScopeFactory)
+ {
+ ServiceScopeFactory = serviceScopeFactory;
+ }
+
+ public virtual async Task GetItemsAsync(PageToolbar toolbar)
+ {
+ if (toolbar == null || !toolbar.Contributors.Any())
+ {
+ return Array.Empty();
+ }
+
+ using (var scope = ServiceScopeFactory.CreateScope())
+ {
+ var context = new PageToolbarContributionContext(scope.ServiceProvider);
+
+ foreach (var contributor in toolbar.Contributors)
+ {
+ await contributor.ContributeAsync(context);
+ }
+
+ return context.Items.OrderBy(i => i.Order).ToArray();
+ }
+ }
+ }
+}
diff --git a/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/SimplePageToolbarContributor.cs b/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/SimplePageToolbarContributor.cs
new file mode 100644
index 0000000000..82afe19f7f
--- /dev/null
+++ b/framework/src/Volo.Abp.AspNetCore.Components.Web.Theming/PageToolbars/SimplePageToolbarContributor.cs
@@ -0,0 +1,53 @@
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.Extensions.DependencyInjection;
+using System;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+
+namespace Volo.Abp.AspNetCore.Components.Web.Theming.PageToolbars
+{
+ public class SimplePageToolbarContributor : IPageToolbarContributor
+ {
+ public Type ComponentType { get; }
+
+ public Dictionary Arguments { get; set; }
+
+ public int Order { get; }
+
+ public string RequiredPolicyName { get; }
+
+ public SimplePageToolbarContributor(
+ Type componentType,
+ Dictionary arguments = null,
+ int order = 0,
+ string requiredPolicyName = null)
+ {
+ ComponentType = componentType;
+ Arguments = arguments;
+ Order = order;
+ RequiredPolicyName = requiredPolicyName;
+ }
+
+ public async Task ContributeAsync(PageToolbarContributionContext context)
+ {
+ if (await ShouldAddComponentAsync(context))
+ {
+ context.Items.Add(new PageToolbarItem(ComponentType, Arguments, Order));
+ }
+ }
+
+ protected virtual async Task ShouldAddComponentAsync(PageToolbarContributionContext context)
+ {
+ if (RequiredPolicyName != null)
+ {
+ var authorizationService = context.ServiceProvider.GetRequiredService();
+ if (!await authorizationService.IsGrantedAsync(RequiredPolicyName))
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+ }
+}
diff --git a/framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/Extensibility/EntityActions/EntityAction.cs b/framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/Extensibility/EntityActions/EntityAction.cs
new file mode 100644
index 0000000000..61bea5c27a
--- /dev/null
+++ b/framework/src/Volo.Abp.AspNetCore.Components.Web/Volo/Abp/AspNetCore/Components/Web/Extensibility/EntityActions/EntityAction.cs
@@ -0,0 +1,20 @@
+using System;
+using System.Threading.Tasks;
+
+namespace Volo.Abp.AspNetCore.Components.Web.Extensibility.EntityActions
+{
+ public class EntityAction : IEquatable
+ {
+ public string Text { get; set; }
+ public Func