【问题标题】:Blazor pass data on navigatingBlazor 在导航时传递数据
【发布时间】:2020-05-18 11:25:13
【问题描述】:

我想在不同页面之间交换数据(剃须刀

我有 2 页: list.razor view.razor

在 view.razor 中,有一个表单在有效提交时调用方法。此方法将引导警报添加到我的服务 AlertService。

list.razor 从服务中读取所有条目,并为每个警报创建一个 Alert razor 组件。

@foreach (var alert in AlertService.GetAlerts())
    {
        <Alert AlertBox="alert" />
    }

我现在面临的问题是,一旦我从我的服务中删除消息,剃须刀组件就会自行刷新并且我的警报消失了。但我想连续显示。一旦用户重新加载或切换页面,它就会消失。

我已经尝试从我的服务创建警报的副本,但这似乎不是这里的解决方案。

public List<IAlert> GetAlerts()
{
    var tmp = Alerts.ToList();
    Alerts = new List<IAlert>();
    return tmp;
}

我在启动时添加了我的服务:

services.AddSingleton<AlertService>();

有没有办法解决这个问题?我在这里做错了什么? 提前致谢。

【问题讨论】:

  • 这个问题是关于 Blazor、新的 SPA 框架还是 Razor Pages?
  • blazor 服务器端。

标签: c# asp.net-core blazor blazor-server-side


【解决方案1】:

看起来这里的问题是您将警报呈现硬连线到您的 AlertService 单例,但您需要的行为是您的视图响应服务但独立存储信息。

从服务设置中读取列表的方式是,它使用服务中的列表作为它正在呈现的列表,这会将所有内容联系在一起,因为它们是引用类型。服务列表中的任何变化都会自然地反映在页面中,无论好坏。您提出问题的方式是,我假设您希望警报仅针对页面加载后添加的列表项显示。您需要一种机制来将服务中的警报与页面上显示的内容分离。因此,也许更好的方法是使用该服务仅将警报信息作为事件传递。这种方式实际上设置起来相当简单,需要在 4 个地方进行设置。

StringEventArgs.cs

这里扩展了基本的 EventArgs 类,以允许在事件调用中传递字符串。这个StringEventArgs 类型稍后将在我们的AlertServiceView.razorList.razor 类中使用。

public class StringEventArgs : EventArgs
{
    public string Value { get; set; }
}

这就像EventArgs 一样工作,但它允许设置Value 属性并使用它发送一个字符串值。 (这也可以与您想要发送的任何其他值一起使用,甚至可以用于复杂的对象类型。只需扩展 EventArgs 以满足您的需求。)

AlertService.cs

如果您使用此方法,您的服务类可以非常简单,因为它所做的只是充当消息中心来传递信息。

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

View.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 事件有任何订阅者,服务就会调用任何订阅的方法,我们接下来会这样做。

List.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 对象,并将Value 属性添加到AlertList 列表中。警报列表现在完全独立于服务,并且仅存在于List.razor 组件中,因此您的列表组件的每个实例将仅显示在初始化后生成的警报。最后,Dispose 方法确保事件订阅在您完成后被删除,因此您不会发生内存泄漏。

这应该会让你动起来,但要指出一件事。因为您将服务注册为单例,所以只要在该窗口中的任何内容中包含List.razor,警报就会发送给他们打开的所有单独窗口中的所有用户。如果您只希望它为单个用户工作,您可以改用范围服务,并确保您没有从OwningComponentBase 继承。 Further reading here。我还在 Github here 上发布了一个演示项目,如果你想要一些可以下载和浏览的东西。

希望这会有所帮助!

【讨论】:

    猜你喜欢
    • 2019-07-20
    • 2019-10-01
    • 1970-01-01
    • 2022-08-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多