Skip to content

Commit cebcfe3

Browse files
authored
Merge pull request #25479 from abpframework/auto-merge/rel-10-4/4584
Merge branch dev with rel-10.4
2 parents ee2f86d + 868c729 commit cebcfe3

37 files changed

Lines changed: 265 additions & 73 deletions

File tree

Directory.Packages.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
<PackageVersion Include="Blazorise.Components" Version="2.0.4" />
2424
<PackageVersion Include="Blazorise.DataGrid" Version="2.0.4" />
2525
<PackageVersion Include="Blazorise.Snackbar" Version="2.0.4" />
26-
<PackageVersion Include="MudBlazor" Version="8.0.0" />
26+
<PackageVersion Include="MudBlazor" Version="9.4.0" />
2727
<PackageVersion Include="Castle.Core" Version="5.2.1" />
2828
<PackageVersion Include="Castle.Core.AsyncInterceptor" Version="2.1.0" />
2929
<PackageVersion Include="CommonMark.NET" Version="0.15.1" />

docs/en/framework/ui/blazor/forms-validation.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,4 +138,33 @@ protected override Task OnCreatingEntityAsync()
138138

139139
> Check the [MudBlazor documentation](https://mudblazor.com/components/form) for the full list of validation modes and the [MudBlazor inputs reference](https://mudblazor.com/components/textfield).
140140
141+
### Modal Focus Behavior
142+
143+
By default a `MudFocusTrap` inside `<MudDialog>` focuses the first tabbable child element after the dialog opens. When the dialog contains a `<MudTabs>` as the first child, that "first tabbable element" is the tab button — not the first input on the active tab — so the user has to click into the field manually.
144+
145+
For dialogs that contain a `<MudTabs>`, use this three-part setup to focus the intended input automatically:
146+
147+
```razor
148+
<MudDialog DefaultFocus="DefaultFocus.None" @ref="_createDialog" Options="@CreateDialogOptions">
149+
<DialogContent>
150+
<MudForm @ref="@CreateFormRef" Model="@NewEntity">
151+
<MudTabs @bind-ActivePanelIndex="@_createTabIndex" KeepPanelsAlive="true">
152+
<MudTabPanel Text="@L["UserInformations"]">
153+
<MudTextField @bind-Value="@NewEntity.UserName"
154+
Label="@L["UserName"]"
155+
AutoFocus="true"
156+
Required="true" />
157+
...
158+
</MudTabPanel>
159+
...
160+
```
161+
162+
- `DefaultFocus="DefaultFocus.None"` on the `<MudDialog>` disables the focus trap's automatic focus so it doesn't grab the tab button.
163+
- `KeepPanelsAlive="true"` on the `<MudTabs>` mounts every tab panel up front, so the first input's `firstRender` happens at dialog-open time (otherwise inactive panels are mounted later, and `AutoFocus` runs after the dialog is already visible).
164+
- `AutoFocus="true"` on the first input asks MudBlazor to focus that field on its first render.
165+
166+
`DialogOptions.DefaultFocus` is ignored for inline dialogs (`<MudDialog @ref> + ShowAsync()`), so always set `DefaultFocus` directly on the `<MudDialog>` element.
167+
168+
For a dialog without `<MudTabs>` (first child is the input), `DefaultFocus="DefaultFocus.FirstChild"` (the MudBlazor default) is enough and you don't need `AutoFocus`.
169+
141170
{{end}}

docs/en/framework/ui/blazor/page-header.md

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,23 @@
1414

1515
# Blazor UI: Page Header
1616

17-
You can use the`PageHeader` component to set the page title, the breadcrumb items and the toolbar items for a page. Before using the `PageHeader` component, you need to add a using statement for the `Volo.Abp.AspNetCore.Components.Web.Theming.Layout` namespace.
17+
You can use the `PageHeader` component to set the page title, the breadcrumb items and the toolbar items for a page. Before using the `PageHeader` component, you need to add a using statement for the namespace:
18+
19+
{{if BlazorUI == "Blazorise"}}
20+
21+
```razor
22+
@using Volo.Abp.AspNetCore.Components.Web.Theming.Layout
23+
```
24+
25+
{{end}}
26+
27+
{{if BlazorUI == "MudBlazor"}}
28+
29+
```razor
30+
@using Volo.Abp.AspNetCore.Components.Web.Theming.MudBlazor.Layout
31+
```
32+
33+
{{end}}
1834

1935
Once you add the `PageHeader` component to your page, you can control the related values using the parameters.
2036

docs/en/package-version-changes.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,12 @@
77

88
# Package Version Changes
99

10+
## 10.4.1
11+
12+
| Package | Old Version | New Version | PR |
13+
|---------|-------------|-------------|-----|
14+
| MudBlazor | 8.0.0 | 9.4.0 | #25393 |
15+
1016
## 10.4.0-rc.2
1117

1218
| Package | Old Version | New Version | PR |

framework/src/Volo.Abp.AspNetCore.Components.MauiBlazor.Theming.MudBlazor.Bundling/MauiBlazorMudBlazorScriptContributor.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ public class MauiBlazorMudBlazorScriptContributor : BundleContributor
88
public override void ConfigureBundle(BundleConfigurationContext context)
99
{
1010
context.Files.AddIfNotContains("_content/MudBlazor/MudBlazor.min.js");
11+
context.Files.AddIfNotContains("_content/Volo.Abp.MudBlazorUI/abp-mud-popover-patch.js");
1112
context.Files.AddIfNotContains("_content/Volo.Abp.AspNetCore.Components.Web/libs/abp/js/abp.js");
1213
context.Files.AddIfNotContains("_content/Volo.Abp.AspNetCore.Components.Web/libs/abp/js/lang-utils.js");
1314
}

framework/src/Volo.Abp.AspNetCore.Components.Server.Theming.MudBlazor/Bundling/BlazorServerMudBlazorScriptContributor.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ public override void ConfigureBundle(BundleConfigurationContext context)
1616
context.Files.AddIfNotContains("/_framework/blazor.server.js");
1717
}
1818
context.Files.AddIfNotContains("/_content/MudBlazor/MudBlazor.min.js");
19+
context.Files.AddIfNotContains("/_content/Volo.Abp.MudBlazorUI/abp-mud-popover-patch.js");
1920
context.Files.AddIfNotContains("/_content/Volo.Abp.AspNetCore.Components.Web/libs/abp/js/abp.js");
2021
context.Files.AddIfNotContains("/_content/Volo.Abp.AspNetCore.Components.Web/libs/abp/js/authentication-state-listener.js");
2122
}

framework/src/Volo.Abp.AspNetCore.Components.WebAssembly.Theming.MudBlazor.Bundling/BlazorWebAssemblyMudBlazorScriptContributor.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ public override void ConfigureBundle(BundleConfigurationContext context)
99
{
1010
context.Files.AddIfNotContains("_content/Microsoft.AspNetCore.Components.WebAssembly.Authentication/AuthenticationService.js");
1111
context.Files.AddIfNotContains("_content/MudBlazor/MudBlazor.min.js");
12+
context.Files.AddIfNotContains("_content/Volo.Abp.MudBlazorUI/abp-mud-popover-patch.js");
1213
context.Files.AddIfNotContains("_content/Volo.Abp.AspNetCore.Components.Web/libs/abp/js/abp.js");
1314
context.Files.AddIfNotContains("_content/Volo.Abp.AspNetCore.Components.Web/libs/abp/js/lang-utils.js");
1415
context.Files.AddIfNotContains("_content/Volo.Abp.AspNetCore.Components.Web/libs/abp/js/authentication-state-listener.js");

framework/src/Volo.Abp.MudBlazorUI/AbpMudCrudPageBase.cs

Lines changed: 38 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System;
22
using System.Collections.Generic;
33
using System.Linq;
4+
using System.Threading;
45
using System.Threading.Tasks;
56
using Localization.Resources.AbpUi;
67
using Microsoft.AspNetCore.Authorization;
@@ -203,6 +204,9 @@ public abstract class AbpMudCrudPageBase<
203204
protected MudDialog? _createDialog;
204205
protected MudDialog? _editDialog;
205206

207+
protected bool IsCreating { get; set; }
208+
protected bool IsUpdating { get; set; }
209+
206210
protected virtual DialogOptions CreateDialogOptions => new DialogOptions
207211
{
208212
MaxWidth = MaxWidth.Medium,
@@ -329,7 +333,7 @@ protected virtual async Task SearchEntitiesAsync()
329333
}
330334
}
331335

332-
protected virtual async Task<GridData<TListViewModel>> OnDataGridReadAsync(GridState<TListViewModel> state)
336+
protected virtual async Task<GridData<TListViewModel>> OnDataGridReadAsync(GridState<TListViewModel> state, CancellationToken cancellationToken = default)
333337
{
334338
CurrentSorting = state.SortDefinitions
335339
.Select(s => _dataGrid.ResolveSortPropertyName(s) + (s.Descending ? " DESC" : ""))
@@ -452,12 +456,20 @@ protected virtual Task CloseEditDialogAsync()
452456

453457
protected virtual async Task CreateEntityAsync()
454458
{
459+
if (IsCreating)
460+
{
461+
return;
462+
}
463+
455464
try
456465
{
466+
IsCreating = true;
467+
await InvokeAsync(StateHasChanged);
468+
457469
var isValid = true;
458470
if (CreateFormRef != null)
459471
{
460-
await CreateFormRef.Validate();
472+
await CreateFormRef.ValidateAsync();
461473
isValid = CreateFormRef.IsValid;
462474
}
463475

@@ -476,6 +488,11 @@ protected virtual async Task CreateEntityAsync()
476488
{
477489
await HandleErrorAsync(ex);
478490
}
491+
finally
492+
{
493+
IsCreating = false;
494+
await InvokeAsync(StateHasChanged);
495+
}
479496
}
480497

481498
protected virtual Task OnCreatingEntityAsync()
@@ -497,12 +514,20 @@ protected virtual string GetCreateMessage()
497514

498515
protected virtual async Task UpdateEntityAsync()
499516
{
517+
if (IsUpdating)
518+
{
519+
return;
520+
}
521+
500522
try
501523
{
524+
IsUpdating = true;
525+
await InvokeAsync(StateHasChanged);
526+
502527
var isValid = true;
503528
if (EditFormRef != null)
504529
{
505-
await EditFormRef.Validate();
530+
await EditFormRef.ValidateAsync();
506531
isValid = EditFormRef.IsValid;
507532
}
508533

@@ -521,6 +546,11 @@ protected virtual async Task UpdateEntityAsync()
521546
{
522547
await HandleErrorAsync(ex);
523548
}
549+
finally
550+
{
551+
IsUpdating = false;
552+
await InvokeAsync(StateHasChanged);
553+
}
524554
}
525555

526556
protected virtual Task OnUpdatingEntityAsync()
@@ -569,7 +599,10 @@ protected virtual Task OnDeletingEntityAsync()
569599

570600
protected virtual async Task OnDeletedEntityAsync()
571601
{
572-
await _dataGrid.ReloadServerDataAsync();
602+
if (_dataGrid != null)
603+
{
604+
await InvokeAsync(() => _dataGrid.ReloadServerDataAsync());
605+
}
573606
Snackbar.Add(GetDeleteMessage(), Severity.Success);
574607
}
575608

@@ -585,7 +618,7 @@ protected virtual string GetDeleteConfirmationMessage(TListViewModel entity)
585618

586619
protected virtual async Task<bool> ConfirmDeleteAsync(TListViewModel entity)
587620
{
588-
var result = await DialogService.ShowMessageBox(
621+
var result = await DialogService.ShowMessageBoxAsync(
589622
UiLocalizer["AreYouSure"],
590623
GetDeleteConfirmationMessage(entity),
591624
yesText: UiLocalizer["Yes"],

framework/src/Volo.Abp.MudBlazorUI/Components/AbpMudExtensibleDataGrid.razor.cs

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using System.Linq;
55
using System.Reflection;
66
using System.Text.RegularExpressions;
7+
using System.Threading;
78
using System.Threading.Tasks;
89
using Localization.Resources.AbpUi;
910
using Microsoft.AspNetCore.Components;
@@ -28,9 +29,9 @@ public partial class AbpMudExtensibleDataGrid<TItem> : ComponentBase
2829
/// Maps SortBy func references to their corresponding property names.
2930
/// Used to resolve property names from MudBlazor SortDefinition.SortFunc.
3031
/// </summary>
31-
private readonly Dictionary<Func<TItem, object>, string> _sortFuncToPropertyMap = new();
32+
private readonly Dictionary<Func<TItem, object?>, string> _sortFuncToPropertyMap = new();
3233

33-
[Parameter] public Func<GridState<TItem>, Task<GridData<TItem>>>? ServerData { get; set; }
34+
[Parameter] public Func<GridState<TItem>, CancellationToken, Task<GridData<TItem>>>? ServerData { get; set; }
3435

3536
[Parameter] public bool Loading { get; set; }
3637

@@ -192,7 +193,7 @@ protected virtual string GetColumnStyle(TableColumn column)
192193
return string.Empty;
193194
}
194195

195-
protected virtual Func<TItem, object>? GetSortByFunc(TableColumn column)
196+
protected virtual Func<TItem, object?>? GetSortByFunc(TableColumn column)
196197
{
197198
if (!column.Sortable)
198199
{
@@ -221,7 +222,7 @@ protected virtual string GetColumnStyle(TableColumn column)
221222
var parameter = System.Linq.Expressions.Expression.Parameter(typeof(TItem), "x");
222223
System.Linq.Expressions.Expression expression = parameter;
223224

224-
Func<TItem, object>? sortFunc = null;
225+
Func<TItem, object?>? sortFunc = null;
225226
foreach (var prop in properties)
226227
{
227228
var propertyInfo = expression.Type.GetProperty(prop, BindingFlags.Public | BindingFlags.Instance);
@@ -237,7 +238,7 @@ protected virtual string GetColumnStyle(TableColumn column)
237238
if (sortFunc == null)
238239
{
239240
var convertExpression = System.Linq.Expressions.Expression.Convert(expression, typeof(object));
240-
var lambda = System.Linq.Expressions.Expression.Lambda<Func<TItem, object>>(convertExpression, parameter);
241+
var lambda = System.Linq.Expressions.Expression.Lambda<Func<TItem, object?>>(convertExpression, parameter);
241242
sortFunc = lambda.Compile();
242243
}
243244

@@ -247,7 +248,7 @@ protected virtual string GetColumnStyle(TableColumn column)
247248
return sortFunc;
248249
}
249250

250-
protected virtual Func<TItem, object>? GetExtensionPropertySortFunc(TableColumn column)
251+
protected virtual Func<TItem, object?>? GetExtensionPropertySortFunc(TableColumn column)
251252
{
252253
if (!column.Sortable || string.IsNullOrWhiteSpace(column.Data))
253254
{
@@ -261,7 +262,7 @@ protected virtual string GetColumnStyle(TableColumn column)
261262
}
262263

263264
var propertyName = match.Groups[1].Value;
264-
Func<TItem, object> sortFunc = item =>
265+
Func<TItem, object?> sortFunc = item =>
265266
{
266267
var entity = item as IHasExtraProperties;
267268
return entity?.GetProperty(propertyName) ?? string.Empty;

framework/src/Volo.Abp.MudBlazorUI/Components/ObjectExtending/MudTextAreaExtensionProperty.razor

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
Label="@PropertyInfo.GetLocalizedDisplayName(StringLocalizerFactory)"
1010
@bind-Value="@Value"
1111
Lines="3"
12-
AutoGrow="true"
12+
Sizing="InputSizing.Auto"
1313
Disabled="IsReadonlyField"
1414
Validation="@((Func<string?, string?>)Validate)"
1515
Immediate="true" />

0 commit comments

Comments
 (0)