Blazor 9.0 自定义组件结合TelerikDialog时双向绑定失效问题
Hey there, let's break down what's going wrong with your双向绑定(two-way binding)setup and fix it step by step.
First, Let's Identify the Core Issues
- Incorrect Parameter Handling in CustomDialog: You're directly binding the TelerikDialog's
Visibleto yourIsVisibleparameter, but in Blazor, child components shouldn't modify parameters directly. You need to use an internal state variable and trigger theIsVisibleChangedevent callback to notify the parent component of changes. - Misplaced Property in Consumer: Your
ShowDialogproperty is trapped inside a nestedPersonalAccessTokenManagerclass in the consumer's code-behind, which means the Razor page can't properly access or bind to it.
Fixed Code for CustomDialog
CustomDialog.razor
We'll use an internal private variable to bind the TelerikDialog's visibility, then sync it with the parent's parameter and trigger the change event when needed:
<TelerikDialog @bind-Visible="@_internalIsVisible" @bind-Visible:after="OnInternalVisibilityChanged"> <DialogTitle> Title Text </DialogTitle> <DialogButtons> <TelerikStackLayout Orientation="@StackLayoutOrientation.Horizontal" Spacing="1em" VerticalAlign="@StackLayoutVerticalAlign.Center" HorizontalAlign="@StackLayoutHorizontalAlign.Right"> <TelerikButton OnClick="@(() => _internalIsVisible = false)">Close</TelerikButton> </TelerikStackLayout> </DialogButtons> </TelerikDialog>
CustomDialog.razor.cs
We'll handle parameter syncing and trigger the IsVisibleChanged event when the internal visibility state changes:
public partial class CustomDialog : ComponentBase { [Parameter] public bool IsVisible { get; set; } = false; [Parameter] public EventCallback<bool> IsVisibleChanged { get; set; } private bool _internalIsVisible; protected override void OnParametersSet() { // Sync internal state with parent's parameter when it updates if (_internalIsVisible != IsVisible) { _internalIsVisible = IsVisible; } } private async Task OnInternalVisibilityChanged() { // Notify parent component of state change if (IsVisible != _internalIsVisible) { await IsVisibleChanged.InvokeAsync(_internalIsVisible); } } }
Fixed Code for Consumer Page
Consumer.razor.cs
Move the ShowDialog property to the main Consumer class (remove the unnecessary nested class):
public partial class Consumer : ComponentBase { public bool ShowDialog { get; set; } = false; void Dialog_OnClose() { // You probably don't need to call StateHasChanged() here—Blazor auto-refreshes after @bind-* updates // base.StateHasChanged(); } }
Consumer.razor
Your existing markup is fine once the ShowDialog property is in the right place:
<TelerikButton OnClick="@(() => { this.ShowDialog = true; })">Open Dialog</TelerikButton> <CustomDialog @bind-IsVisible="@this.ShowDialog" @bind-IsVisible:after="@Dialog_OnClose"></CustomDialog> <p>@this.ShowDialog</p>
Why This Works
- Proper Parameter Flow: By using an internal variable for TelerikDialog's visibility, we respect Blazor's one-way data flow rule (child components don't modify parent parameters directly). Instead, we use
IsVisibleChangedto tell the parent to update its own state. - Syncing State: The
OnParametersSetmethod ensures that if the parent updatesIsVisible, our internal state stays in sync. - Correct Property Access: Moving
ShowDialogto the mainConsumerclass makes it accessible to the Razor page, so the binding works as expected.
After these fixes, when you close the dialog, the ShowDialog value in the consumer will update to false, and the <p> tag will reflect that change immediately. The @bind-IsVisible:after event will also fire correctly now.
内容来源于stack exchange

