如何在同一 Blazor 页面上的 Razor 组件之间传递数据?
How do I pass data between Razor components on the same Blazor page?
我有这个 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
传递给第二个组件,所以我可以用PositionId
参数替换最后一行硬编码的86。
是的,你有两个不直接相关的控件,所以你不能简单地传递一个参数。
两个选项:
或状态管理。对于状态管理,这可能有助于:
Implementing State Management In Blazor
你有一个像这样的class:
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;
}
这是一种可能的解决方案,它可能是可行的,因为您可以访问您正在使用的组件的代码。
此解决方案分为三个步骤:
- 在您的第一个组件中定义事件回调。
- 在第二个组件中定义一个参数。
- 在您的父组件(您的页面)中定义一个 属性。
第 1 步:在您的第一个组件中定义事件回调。
这将允许您在 属性 更改时通知父组件(您的页面)。
将您的 PositionId 属性 声明为 public 参数。
[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 步:在第二个组件中定义一个参数。
这将允许您将值从父组件(您的页面)传递到第二个组件。
像这样声明一个 public 参数:
[Parameter] public int APositionId {get; set; }
第 3 步:在您的父组件(您的页面)中定义一个 属性。
在这里,您定义一个 属性,让它在第一个组件中 属性 的值发生变化时更新,然后将该值提供给第二个组件中的参数。
像这样在您的页面中定义 属性:
private int SuppliedPosition { get; set; }
像这样将它连接到第一个组件中的更改通知程序:
<Position_Hex_IdPair @bind-PositionId="SuppliedPosition" />
像这样将它提供给第二个组件中的参数:
<PositionData APositionId="@SuppliedPosition"/>
我对每个附加属性的命名都略有不同,因此希望大家清楚哪个是哪个。
就是这样!此解决方案的缺点是它需要您更改您的组件,并将代码添加到您的页面。
Blazor 文档中提供了有关事件回调和参数的更多信息:Blazor docs。
希望这对您有所帮助。
作为替代方法,您可以使用 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;
});
留言class:
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
我有这个 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
传递给第二个组件,所以我可以用PositionId
参数替换最后一行硬编码的86。
是的,你有两个不直接相关的控件,所以你不能简单地传递一个参数。
两个选项:
或状态管理。对于状态管理,这可能有助于: Implementing State Management In Blazor
你有一个像这样的class:
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;
}
这是一种可能的解决方案,它可能是可行的,因为您可以访问您正在使用的组件的代码。
此解决方案分为三个步骤:
- 在您的第一个组件中定义事件回调。
- 在第二个组件中定义一个参数。
- 在您的父组件(您的页面)中定义一个 属性。
第 1 步:在您的第一个组件中定义事件回调。
这将允许您在 属性 更改时通知父组件(您的页面)。
将您的 PositionId 属性 声明为 public 参数。
[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 步:在第二个组件中定义一个参数。
这将允许您将值从父组件(您的页面)传递到第二个组件。
像这样声明一个 public 参数:
[Parameter] public int APositionId {get; set; }
第 3 步:在您的父组件(您的页面)中定义一个 属性。
在这里,您定义一个 属性,让它在第一个组件中 属性 的值发生变化时更新,然后将该值提供给第二个组件中的参数。
像这样在您的页面中定义 属性:
private int SuppliedPosition { get; set; }
像这样将它连接到第一个组件中的更改通知程序:
<Position_Hex_IdPair @bind-PositionId="SuppliedPosition" />
像这样将它提供给第二个组件中的参数:
<PositionData APositionId="@SuppliedPosition"/>
我对每个附加属性的命名都略有不同,因此希望大家清楚哪个是哪个。
就是这样!此解决方案的缺点是它需要您更改您的组件,并将代码添加到您的页面。
Blazor 文档中提供了有关事件回调和参数的更多信息:Blazor docs。
希望这对您有所帮助。
作为替代方法,您可以使用 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;
});
留言class:
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