[英]Blazor pass data on navigating
我想在不同頁面之間交換數據(剃刀
我有 2 頁:list.razor view.razor
在 view.razor 中,有一個表單調用有效提交的方法。 此方法將引導警報添加到我的服務 AlertService。
list.razor 從服務中讀取所有條目,並為每個警報創建一個警報 razor 組件。
@foreach (var alert in AlertService.GetAlerts())
{
<Alert AlertBox="alert" />
}
我現在面臨的問題是,一旦我從服務中刪除消息,razor 組件就會自行刷新,我的警報就消失了。 但我想連續顯示。 一旦用戶重新加載或切換頁面,它就會消失。
我已經嘗試從我的服務創建警報的副本,但它似乎不是這里的解決方案。
public List<IAlert> GetAlerts()
{
var tmp = Alerts.ToList();
Alerts = new List<IAlert>();
return tmp;
}
我在啟動時添加了我的服務:
services.AddSingleton<AlertService>();
有沒有辦法解決這個問題? 我在這里做錯了什么? 提前致謝。
看起來這里的問題是您的警報呈現硬連線到您的 AlertService singleton,但您需要的行為是您的視圖響應服務但獨立存儲信息。
從服務設置中讀取列表的方式是,它使用服務中的列表作為它正在呈現的列表,這會將所有內容聯系在一起,因為它們是引用類型。 服務列表中的任何變化都會自然地反映在頁面中,無論好壞。 您提出問題的方式是,我假設您希望警報僅針對頁面加載后添加的列表項顯示。 您需要一種機制來將服務中的警報與頁面上顯示的內容分離。 因此,也許更好的方法是使用該服務僅將警報信息作為事件傳遞。 以這種方式設置實際上相當簡單,並且需要在 4 個地方進行設置。
字符串事件參數.cs
這是擴展基本 EventArgs class 以允許在事件調用中傳遞字符串。 此StringEventArgs
類型稍后將在我們的AlertService
、 View.razor
和List.razor
類中使用。
public class StringEventArgs : EventArgs
{
public string Value { get; set; }
}
這就像EventArgs
一樣工作,但它允許設置Value
屬性並使用它發送一個字符串值。 (這也可以與您要發送的任何其他值一起使用,甚至可以用於復雜的 object 類型。只需擴展EventArgs
以滿足您的需要。)
警報服務.cs
如果您使用此方法,您的服務 class 可以非常簡單,因為它所做的只是充當消息中心來傳遞信息。
public class AlertService
{
public Func<object, StringEventArgs, Task> SendAlert;
public Task OnAlertRequested(object sender, StringEventArgs e)
{
SendAlert?.Invoke(sender, e);
return Task.CompletedTask;
}
}
這里非常標准的基於事件的東西,只是使用StringEventArgs
而不是標准的EventArgs
。
查看.Razor
您需要在此文件中更改的唯一一件事是在您提交有效表單時通過您的服務傳遞消息。 您提到您有一個在有效提交表單時調用的方法,該方法將警報添加到列表中。 所以該方法應該看起來像這樣。 請注意,我展示了注入服務以澄清名稱。
[Inject] public AlertService Service { get; set;}
void HandleValidSubmit(string alertMessage, other params...)
{
// code to handle other params
Service.OnAlertRequested(this, new StringEventArgs() { Value = alertMessage});
}
這樣做是調用服務中觸發事件的方法,使用傳遞警報值的新 StringEventArgs 實例。只要服務中的SendAlert
事件有任何訂閱者,服務就會調用任何訂閱的方法,我們接下來要做的。
列表.Razor
這是您需要包含的最后一項功能,所有這些都將開始工作。 我們將列出每次加載新頁面時初始化的警報值列表,並在通過服務發送警報消息時填充它。
@implements IDisposable
@foreach (var alert in AlertList)
{
<Alert AlertBox="alert" />
}
@code {
[Inject] public AlertService Service { get; set;}
// Always initializes to a fresh list on component start
public List<string> AlertList { get; set; } = new List<string>();
//This handler will be called whenever the event defined in AlertService
//triggers, and will accept StringEventArgs which can be passed from the event caller
//Note that this needs to be ASYNC so you can await the 'InvokeAsync' call below
private async Task OnAlertReceived(object sender, StringEventArgs e)
{
AlertList.Add(e.Value);
await InvokeAsync(StateHasChanged);
}
//Triggered when the page builds and renders
protected override void OnInitialized()
{
//Unsubsribe once to make sure you only have one event subscription
//This prevents event propogation, and won't do anything unless you are
//already subscribed for some reason
Service.SendAlert -= OnAlertReceived;
//Subscribe to the event
Service.SendAlert += OnAlertReceived;
}
//IMPORTANT - add Dispose and unsubscribe on teardown
//prevents event propogation and memory leaks.
public void Dispose()
{
Service.SendAlert -= OnAlertReceived;
}
}
這樣做是在您的列表中為您提供一個名為OnAlertReceived
的方法,以響應來自服務的SendAlert
通知,然后使用OnInitialized
注冊該方法以在服務調用它時觸發。 該方法接收 StringEventArgs object,並將Value
屬性添加到AlertList
列表中。 警報列表現在完全獨立於服務,並且僅存在於List.razor
組件中,因此您的列表組件的每個實例將僅顯示在其初始化后生成的警報。 最后, Dispose
方法確保事件訂閱在您完成后被刪除,因此您沒有 memory 泄漏。
這應該讓你動起來,但要指出一件事。 Because you have your service registered as a singleton, the alert will go out to all users in all separate windows they have open, as long as List.razor
is included in whatever is in that window. 如果您只希望它為單個用戶工作,您可以使用范圍服務,並確保您沒有從OwningComponentBase
繼承。 進一步閱讀這里。 我還有一個演示項目發布在 Github 上,如果你想要一些可以下載和瀏覽的東西。
希望這可以幫助!
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.