【问题标题】:How do I pass data between Razor components on the same Blazor page?如何在同一 Blazor 页面上的 Razor 组件之间传递数据?
【发布时间】:2020-02-18 23:36:54
【问题描述】:

我有这个 Blazor 页面

@page "/bearoffdata"
@using BlazorBoinq.Components

<h3>Bearoff Data</h3>

<Position_Hex_IdPair />

<PositionData />

@code {

}

使用这两个 Razor 组件:

@using BlazorBoinq.Data
@using BgBearoffCoreNamespace;
@inject BgBearoffService BoService

<label>Position</label>

<input type="text" spellcheck="false" @bind-value="@PositionText" @bind-value:event="oninput" />

<span> = </span>

<input type="number" step="1" @bind-value="@PositionId" @bind-value:event="oninput" />

<label>Id</label>

@code {

    BgBearoffCore BgBo;

    protected override async Task OnInitializedAsync()
    {
        BgBo = await BoService.GetBgBearoffAsync();
    }

    private Int64 positionId;
    private String positionText;

    protected Int64 PositionId
    {
        get => positionId;
        set
        {
            positionId = value;
            if (positionId > 0 && positionId <= BgBo.MaxId)
            {
                positionText = BgBearoffCore.menOnPointToHexString(BgBo.getMenOnPointFromInvariantId(positionId));
            }
            else
                positionText = "";
        }
    }

    protected String PositionText
    {
        get => positionText;
        set
        {
            positionText = value;
            if (BgBo.IsValidHexPosition(positionText))
                positionId = BgBo.getInvariantIdFromPosition(positionText);
            else
                positionId = 0;
        }
    }
}

@using BlazorBoinq.Data
@using BgBearoffCoreNamespace;
@inject BgBearoffService BoService

<button class="btn btn-primary" @onclick="ShowBearoffInfo">Show Data</button>

<br>

<textarea cols="36" rows="36" readonly @bind="@BearoffInfo" />


@code {
    BgBearoffCore BgBo;

    protected override async Task OnInitializedAsync()
    {
        BgBo = await BoService.GetBgBearoffAsync();
    }


    private String bearoffInfo = "";
    public String BearoffInfo
    {
        get => bearoffInfo;
        set { }
    }
    protected void ShowBearoffInfo()
    {
        bearoffInfo = BgBo.getPositionInformationText(86);
    }
}

我想将第一个组件的PositionId 传递给第二个组件,所以我可以将最后一行中的硬编码86 替换为PositionId 参数。当我尝试发布此内容时出现错误

看起来您的帖子主要是代码;请添加更多详细信息。

我不太确定添加哪些细节可以帮助某人回答这个问题。

【问题讨论】:

    标签: razor components parameter-passing blazor asp.net-core-3.0


    【解决方案1】:

    是的,您有两个不直接相关的控件,因此您不能只传递一个参数。

    两种选择:

    级联参数:https://docs.microsoft.com/en-us/aspnet/core/blazor/components?view=aspnetcore-3.0#cascading-values-and-parameters

    或状态管理。对于状态管理,这可能会有所帮助: Implementing State Management In Blazor

    你有这样的课程:

    using System;
    public class CounterState
    {
        // _currentCount holds the current counter value
        // for the entire application
        private int _currentCount = 0;
        // StateChanged is an event handler other pages
        // can subscribe to 
        public event EventHandler StateChanged;
        // This method will always return the current count
        public int GetCurrentCount()
        {
            return _currentCount;
        }
        // This method will be called to update the current count
        public void SetCurrentCount(int paramCount)
        {
            _currentCount = paramCount;
            StateHasChanged();
        }
        // This method will allow us to reset the current count
        public void ResetCurrentCount()
        {
            _currentCount = 0;
            StateHasChanged();
        }
        private void StateHasChanged()
        {
            // This will update any subscribers
            // that the counter state has changed
            // so they can update themselves
            // and show the current counter value
            StateChanged?.Invoke(this, EventArgs.Empty);
        }
    }
    

    您可以像这样在您的 startup.cs 文件中注册它:

    services.AddScoped<CounterState>();
    

    您可以像这样在每个 .razor 控件中引用它:

    @inject CounterState CounterState
    

    一个控件可以这样设置一个值:

    // Call the GetCurrentCount() method
    // to get the current count
    int CurrentCount = CounterState.GetCurrentCount();
    // Increase the count
    CurrentCount++;
    // Set Current count on the Session State object
    CounterState.SetCurrentCount(CurrentCount);
    

    位于应用程序中任何位置的另一个控件可以接收如下值:

       // This method is called when the control is initialized
        protected override void OnInitialized()
        {
            // Subscribe to the StateChanged EventHandler
            CounterState.StateChanged +=
            OnCounterStateAdvancedStateChanged;
        }
        // This method is fired when the CounterState object
        // invokes its StateHasChanged() method
        // This will cause this control to invoke its own
        // StateHasChanged() method refreshing the page
        // and displaying the updated counter value
        void OnCounterStateAdvancedStateChanged(
            object sender, EventArgs e) => StateHasChanged();
        void IDisposable.Dispose()
        {
            // When this control is disposed of
            // unsubscribe from the StateChanged EventHandler
            CounterState.StateChanged -=
            OnCounterStateAdvancedStateChanged;
        }
    

    【讨论】:

    • 我发现(即使它是 blazor)使用带有 Blazor 的视图模型是关键。我在处理时间问题上遇到了很多麻烦,事情发生的顺序是你无法预测或检测到的。有时你的变量是空的,因为它还没有被设置,有时 DOM 还没有准备好,等等……用你的属性和方法创建一个视图模型,然后从它创建一个接口,然后使用依赖注入添加它。这让您不再关心事物的顺序,视图模型的生命周期可以设置为 Singleton、Transient 或 Scoped。
    【解决方案2】:

    这是一种可能的解决方案,这可能是可行的,因为您可以访问正在使用的组件的代码。

    此解决方案分为三个步骤:

    1. 在您的第一个组件中定义一个事件回调。
    2. 在您的第二个组件中定义一个参数。
    3. 在您的父组件(您的页面)中定义一个属性。

    第 1 步:在您的第一个组件中定义事件回调。

    这将允许您在属性更改时通知父组件(您的页面)。

    将您的 PositionId 属性声明为公共参数。

    [Parameter] public int PositionId
    

    你可以让你的 getter 和 setter 保持原样。

    将您的输入更改为:

    <input type="text" spellcheck="false" @oninput="OnPositionIdChanged" />
    

    像这样声明一个事件回调:

    [Parameter] public EventCallback<int> PositionIdChanged { get; set; }
    

    然后定义一个方法来处理这样的变化:

    private Task OnPositionIdChanged(ChangeEventArgs e)
    {
        PositionId = int.Parse(e.Value.ToString());
        return PositionIdChanged.InvokeAsync(PositionId);
    }
    

    现在,当输入中的值发生变化时,将引发 EventCallback。

    第 2 步:在您的第二个组件中定义一个参数。

    这将允许您将值从父组件(您的页面)传递到您的第二个组件。

    像这样声明一个公共参数:

    [Parameter] public int APositionId {get; set; }
    

    第 3 步:在您的父组件(您的页面)中定义一个属性。

    在这里,您定义一个属性,当您的第一个组件中的属性值发生变化时更新它,然后将该值提供给您的第二个组件中的参数。

    在您的页面中定义一个属性,如下所示:

    private int SuppliedPosition { get; set; }
    

    将它连接到您的第一个组件中的更改通知器,如下所示:

    <Position_Hex_IdPair @bind-PositionId="SuppliedPosition"  />
    

    将它提供给第二个组件中的参数,如下所示:

    <PositionData APositionId="@SuppliedPosition"/>
    

    我对每个附加属性的命名略有不同,因此希望清楚哪个是哪个。

    就是这样!此解决方案的缺点是它需要您更改组件并向页面添加代码。

    在 Blazor 文档中有关于事件回调和参数的更多信息:Blazor docs

    希望这会有所帮助。

    【讨论】:

    • 我要试试事件回调的方法。我应该提到第二个组件有一个按钮,可以触发从第一个组件检索 id。
    • 谢谢,成功了!我丢弃了 Task OnPositionIdChanged,并从第一个组件的设置器中调用了 PositionIdChanged.InvokeAsync。
    【解决方案3】:

    作为替代方案,您可以使用 Rx.Net。

    您可以使用这样的服务。

    public interface IThemeMessageService<T>
    {
        void SendMessage(ActionMessage<T> message);
    
        IObservable<ActionMessage<T>> GetMessage();
    }
    
    public class ThemeMessageService<T>: IThemeMessageService<T>
    {
        private readonly Subject<ActionMessage<T>> _subject = new Subject<ActionMessage<T>>();
    
        public void SendMessage(ActionMessage<T> message) => _subject.OnNext(message);
    
        public IObservable<ActionMessage<T>> GetMessage() => _subject;
    
    }
    

    发送消息:

    var actionMessage = new ActionMessage<MyData>
    {
        Emitter = ThemeMessageEmitter.Component1,
        Data = data
    };
    
    ThemeMessageService.SendMessage(actionMessage);
    

    接收消息:

     ThemeMessageService.GetMessage().Subscribe(p =>
     {
    
         data= p.Data;
    
     });
    

    消息类:

    public class ActionMessage<T>
    {
        public ThemeMessageEmitter Emitter { get; set; }
        public T Data { get; set; }
    }
    

    Emiter:你可以在这里注册发送数据的组件

    public enum ThemeMessageEmitter
    {
        Component1 = 1,
        Component2 = 2,
    }
    

    别忘了在 Startup 中注册服务

     services.AddSingleton(typeof(IThemeMessageService<MyData>), typeof(ThemeMessageService<MyData>));
    

    您可以在我的 blazor 管理主题中查看所有操作 https://github.com/amuste/BlazorAdminDashboard/tree/master/BlazorAdminDashboard.Client/Shared/Theme

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-06-22
      • 2018-12-16
      • 2018-01-06
      • 2019-09-18
      • 2012-02-25
      • 1970-01-01
      • 2021-06-08
      相关资源
      最近更新 更多