有没有办法通过单击在 Blazor 中触发两个连续的事件?
Is there a way to trigger two consecutive events in Blazor with a single click?
背景
我在 Blazor WASM 中创建了名为 SET 的纸牌游戏。在这个游戏中,您点击 3 张牌,这可能会导致 SET 成功或错误提交。它运行良好,现在我想添加一个额外的功能来表示提交的结果。
想要的结果
第一种方法:单击第 3 张卡片后,这 3 张卡片应该获得绿色(正确)或红色(错误)背景,并且在 x 时间后(比如 1 秒)第二种方法应该火。
第二种方法:如果设置正确,用3张新卡替换3张卡。如果设置为 false,将背景颜色重置为白色并将边框颜色重置为黑色。
当前实际结果
目前发生的情况是第一种方法(green/red 背景)的结果没有显示,因为只有一个回调事件。所以它确实被执行了,但是直到第二种方法也被执行时它才会变得可见,此时卡片已经被替换,或者 backgroundcolor/bordercolor 已经被重置。
目前已尝试
我试图在@onclick 事件中分离这两个方法,但仍然只有一个 eventcallback,到目前为止我找不到另一种方法来做到这一点,也没有堆栈溢出。
@onclick="() => { ProcessSelection(uniqueCardCombinations[index]); ProcessSetReplacement(); }
The most notable difference is that EventCallback is a single-cast
event handler, whereas .NET events are multi-cast. Blazor
EventCallback is meant to be assigned a single value and can only
call back a single method. https://blazor-university.com/components/component-events/
我也尝试了 Chris Sainty 在这里描述的“状态容器”,但它只是重新渲染它,我无法根据我的情况调整它(不确定这是否可能 tbh):
https://chrissainty.com/3-ways-to-communicate-between-components-in-blazor/
代码
我确实打算在代码开始工作后对其进行清理,使其更具描述性并将 ProcessSetReplacement 拆分得更多一些,但我想让它先工作。
如果您需要更多 background/code 信息,请告诉我,或者您可以在此处找到整个存储库:https://github.com/John-Experimental/GamesInBlazor/tree/21_AddSetValidationVisualisation
SetPage.razor:
<div class="cardsContainer">
@for (int i = 0; i < numberOfCardsVisible; i++)
{
var index = i;
<div class="card @lineClass" style="background-color:@uniqueCardCombinations[index].BackGroundColor;
border-color:@uniqueCardCombinations[index].BorderColor;"
@onclick="() => { ProcessSelection(uniqueCardCombinations[index]); ProcessSetReplacement(); }">
@for (int j = 0; j < uniqueCardCombinations[i].Count; j++)
{
<div class="@uniqueCardCombinations[i].Shape @uniqueCardCombinations[i].Color @uniqueCardCombinations[i].Border"></div>
}
</div>
}
</div>
SetPage.razor.cs 的相关部分(代码隐藏)
private void ProcessSelection(SetCardUiModel setCard)
{
numberOfSelected += _uiHelperService.ProcessCardSelection(setCard);
if (numberOfSelected == 3)
{
var setSubmission = uniqueCardCombinations.Where(card => card.BackGroundColor == "yellow").ToList();
var potentialSet = _mapper.Map<List<SetCardUiModel>, List<SetCard>>(setSubmission);
var isSet = _cardHelperService.VerifySet(potentialSet);
_uiHelperService.SignalSetSubmissionOutcome(setSubmission, isSet);
};
}
private void ProcessSetReplacement()
{
// If it wasn't a set submission, you do nothing
if (numberOfSelected == 3)
{
var redBorderedCards = uniqueCardCombinations.Where(card => card.BorderColor == "red").ToList();
var countGreenBorders = uniqueCardCombinations.Count(card => card.BorderColor == "green");
// The while ensures that the 'ProcessSelection' function, which is also called, has run first
while (redBorderedCards.Count == 0 && countGreenBorders == 0)
{
Thread.Sleep(125);
redBorderedCards = uniqueCardCombinations.Where(card => card.BorderColor == "red").ToList();
countGreenBorders = uniqueCardCombinations.Count(card => card.BorderColor == "green");
}
// Wait 1.5 seconds so that the user can see the set outcome from 'ProcessSelection' before removing it
Thread.Sleep(1500);
if (countGreenBorders == 3)
{
// Replace the set by removing the set submission entirely from the list
uniqueCardCombinations.RemoveAll(card => card.BackGroundColor == "yellow");
numberOfSelected = 0;
// Check if the field currently shows more cards than normal (can happen if there was no set previously)
// If there are more cards, then remove 3 cards again to bring it back down to 'normal'
numberOfCardsVisible -= numberOfCardsVisible > settings.numberOfCardsVisible ? 3 : 0;
EnsureSetExistsOnField();
}
else
{
foreach (var card in redBorderedCards)
{
card.BackGroundColor = "white";
card.BorderColor = "black";
}
}
};
}
不要调用 onclick
中的两种方法。
- 调用
ProcessSelection
,处理结果并在那里设置 red/green。
- 致电
StateHasChanged()
- 在
ProcessSelection
中将计时器设置为一秒。使用来自 System.Timers
. 的计时器
- 在计时器调用结束时
ProcessSetReplacement
。
当您需要在一个事件中执行多个定时操作时,async
是您的主要工具。
Blazor 将识别异步事件处理程序:
//private void ProcessSelection(SetCardUiModel setCard)
private async Task ProcessSelection(SetCardUiModel setCard)
{
... // old code
await Task.Delay(1000);
ProcessSetReplacement();
}
当您有多个 Task.Delay() 时,请在它们之前添加 StateHasChanged()
个调用。
在标记部分:
@onclick="() => ProcessSelection(uniqueCardCombinations[index])"
背景
我在 Blazor WASM 中创建了名为 SET 的纸牌游戏。在这个游戏中,您点击 3 张牌,这可能会导致 SET 成功或错误提交。它运行良好,现在我想添加一个额外的功能来表示提交的结果。
想要的结果
第一种方法:单击第 3 张卡片后,这 3 张卡片应该获得绿色(正确)或红色(错误)背景,并且在 x 时间后(比如 1 秒)第二种方法应该火。
第二种方法:如果设置正确,用3张新卡替换3张卡。如果设置为 false,将背景颜色重置为白色并将边框颜色重置为黑色。
当前实际结果
目前发生的情况是第一种方法(green/red 背景)的结果没有显示,因为只有一个回调事件。所以它确实被执行了,但是直到第二种方法也被执行时它才会变得可见,此时卡片已经被替换,或者 backgroundcolor/bordercolor 已经被重置。
目前已尝试
我试图在@onclick 事件中分离这两个方法,但仍然只有一个 eventcallback,到目前为止我找不到另一种方法来做到这一点,也没有堆栈溢出。
@onclick="() => { ProcessSelection(uniqueCardCombinations[index]); ProcessSetReplacement(); }
The most notable difference is that EventCallback is a single-cast event handler, whereas .NET events are multi-cast. Blazor EventCallback is meant to be assigned a single value and can only call back a single method. https://blazor-university.com/components/component-events/
我也尝试了 Chris Sainty 在这里描述的“状态容器”,但它只是重新渲染它,我无法根据我的情况调整它(不确定这是否可能 tbh): https://chrissainty.com/3-ways-to-communicate-between-components-in-blazor/
代码
我确实打算在代码开始工作后对其进行清理,使其更具描述性并将 ProcessSetReplacement 拆分得更多一些,但我想让它先工作。
如果您需要更多 background/code 信息,请告诉我,或者您可以在此处找到整个存储库:https://github.com/John-Experimental/GamesInBlazor/tree/21_AddSetValidationVisualisation
SetPage.razor:
<div class="cardsContainer">
@for (int i = 0; i < numberOfCardsVisible; i++)
{
var index = i;
<div class="card @lineClass" style="background-color:@uniqueCardCombinations[index].BackGroundColor;
border-color:@uniqueCardCombinations[index].BorderColor;"
@onclick="() => { ProcessSelection(uniqueCardCombinations[index]); ProcessSetReplacement(); }">
@for (int j = 0; j < uniqueCardCombinations[i].Count; j++)
{
<div class="@uniqueCardCombinations[i].Shape @uniqueCardCombinations[i].Color @uniqueCardCombinations[i].Border"></div>
}
</div>
}
</div>
SetPage.razor.cs 的相关部分(代码隐藏)
private void ProcessSelection(SetCardUiModel setCard)
{
numberOfSelected += _uiHelperService.ProcessCardSelection(setCard);
if (numberOfSelected == 3)
{
var setSubmission = uniqueCardCombinations.Where(card => card.BackGroundColor == "yellow").ToList();
var potentialSet = _mapper.Map<List<SetCardUiModel>, List<SetCard>>(setSubmission);
var isSet = _cardHelperService.VerifySet(potentialSet);
_uiHelperService.SignalSetSubmissionOutcome(setSubmission, isSet);
};
}
private void ProcessSetReplacement()
{
// If it wasn't a set submission, you do nothing
if (numberOfSelected == 3)
{
var redBorderedCards = uniqueCardCombinations.Where(card => card.BorderColor == "red").ToList();
var countGreenBorders = uniqueCardCombinations.Count(card => card.BorderColor == "green");
// The while ensures that the 'ProcessSelection' function, which is also called, has run first
while (redBorderedCards.Count == 0 && countGreenBorders == 0)
{
Thread.Sleep(125);
redBorderedCards = uniqueCardCombinations.Where(card => card.BorderColor == "red").ToList();
countGreenBorders = uniqueCardCombinations.Count(card => card.BorderColor == "green");
}
// Wait 1.5 seconds so that the user can see the set outcome from 'ProcessSelection' before removing it
Thread.Sleep(1500);
if (countGreenBorders == 3)
{
// Replace the set by removing the set submission entirely from the list
uniqueCardCombinations.RemoveAll(card => card.BackGroundColor == "yellow");
numberOfSelected = 0;
// Check if the field currently shows more cards than normal (can happen if there was no set previously)
// If there are more cards, then remove 3 cards again to bring it back down to 'normal'
numberOfCardsVisible -= numberOfCardsVisible > settings.numberOfCardsVisible ? 3 : 0;
EnsureSetExistsOnField();
}
else
{
foreach (var card in redBorderedCards)
{
card.BackGroundColor = "white";
card.BorderColor = "black";
}
}
};
}
不要调用 onclick
中的两种方法。
- 调用
ProcessSelection
,处理结果并在那里设置 red/green。 - 致电
StateHasChanged()
- 在
ProcessSelection
中将计时器设置为一秒。使用来自System.Timers
. 的计时器
- 在计时器调用结束时
ProcessSetReplacement
。
当您需要在一个事件中执行多个定时操作时,async
是您的主要工具。
Blazor 将识别异步事件处理程序:
//private void ProcessSelection(SetCardUiModel setCard)
private async Task ProcessSelection(SetCardUiModel setCard)
{
... // old code
await Task.Delay(1000);
ProcessSetReplacement();
}
当您有多个 Task.Delay() 时,请在它们之前添加 StateHasChanged()
个调用。
在标记部分:
@onclick="() => ProcessSelection(uniqueCardCombinations[index])"