我正在开发一个布局设计器,想到了用于 Web 组件的 WinForms Designer,并且正处于该项目的最开始阶段。我使用 Blazor Server App,并且由于我需要一般生成控件,所以我使用 DynamicComponents。由于我不希望实际布局组件过于复杂,因此我有一个基类来处理最常见的事情。此外,我创建了一个 Selectable 节点来允许检测组件选择,而无需在每个组件中实现它。
现在选择组件时,我看到删除图标未启用,但代码已正确设置其禁用/启用状态。
但是,我可以调用 StateHasChanged ,这将显示正确的状态,但不幸的是会导致其他问题,很可能与正在使用的 DynamicComponents 有关。
我能够通过一个非常简单的示例重现我的问题,可以在这里找到: https://try.mudblazor.com/snippet/QYcIuybXTEvcExgs
我也会尝试在这里概述代码:
@inherits LayoutComponentBase
<PageTitle>BlazorRepro</PageTitle>
@Counter
<Container @ref="@container">
<div>
@Body
</div>
</Container>
@code {
Container? container;
int Counter { get; set; }
protected override void OnAfterRender(bool firstRender)
{
base.OnAfterRender(firstRender);
if (container != null && firstRender)
container.SelectionChanged += OnSelectionChanged;
}
private void OnSelectionChanged()
{
System.Diagnostics.Trace.WriteLine($"Counter incremented to : {++Counter}");
}
}
这是主要组成部分。它生成一个 Container 实例,该实例又将为所有子级提供 CascadingValue。它还注册 SelectionChanged 事件,并在选择某些内容时增加计数器(= 启用/禁用我的删除按钮)
<div class="container">
<CascadingValue Value="this">
@ChildContent
</CascadingValue>
</div>
@code {
[Parameter]
public RenderFragment? ChildContent { get; set; }
public event Action? SelectionChanged;
public void Select()
{
SelectionChanged?.Invoke();
}
}
容器实施。如前所述,它提供了 CascadingValue 和公共方法,以便能够收到有关新选择的通知。
<div @onclick="Select">
@ChildContent
</div>
@code {
[CascadingParameter]
public Container Container { get; set; }
[Parameter]
public RenderFragment ChildContent { get; set; }
private void Select()
{
Container.Select();
}
}
可选择的实现。当单击某些内容时,就会调用 Container.Select() 方法。
@page "/"
<PageTitle>Index</PageTitle>
<Selectable>
<h1>Click me to select</h1>
</Selectable>
最后,MainLayout 的主体 - 它仅包含一个可选择的文本。
如果单击“单击我进行选择”,我希望主布局上的计数器会增加,但不幸的是,只有当主布局的事件处理程序也调用 StateHasChanged 时才会发生这种情况。
我不太确定问题出在哪里,但我知道,这种绑定通常应该有效。
提前感谢您的帮助和建议!
这是您可以做出的一项可能的改变 - 还有其他方法。
创建一个
CounterDisplay
组件:
@counter
@code {
int counter = 0;
public void Increment()
{
counter++;
StateHasChanged();
}
}
将此组件添加到您的布局中:
<CounterDisplay @ref=counter />
为
@ref
声明本地
CounterDisplay counter;
并更改您的处理程序:
private void OnSelectionChanged()
{
counter?.Increment();
}
现在 CounterDisplay 负责自己的
counter
并且可以在调用 Increment
时调用 StateHasChanged 来独立更新自己