Как передать данные между компонентами Razor на одной странице Blazor? - PullRequest
0 голосов
/ 22 октября 2019

У меня есть эта страница 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. Я получаю сообщение об ошибке, когда пытаюсь опубликовать это сообщение

Похоже, ваше сообщение в основном содержит код;пожалуйста, добавьте еще несколько деталей.

Я не совсем уверен, какие детали добавить, чтобы кто-нибудь ответил на этот вопрос.

Ответы [ 3 ]

1 голос
/ 23 октября 2019

Вот одно из возможных решений, которое может быть осуществимо, потому что у вас есть доступ к коду для компонентов, которые вы используете.

Существует три шага к этому решению:

  1. Определите функцию обратного вызова в вашем первом компоненте.
  2. Определите параметр во втором компоненте.
  3. Определите свойство в родительском компоненте (вашей странице).

Шаг 1. Определите функцию обратного вызова в вашем первом компоненте.

Это позволит вам уведомлять родительский компонент (вашу страницу) об изменении свойства.

Объявите свойство PositionId в качестве открытого параметра. .

[Parameter] public int PositionId

Вы можете оставить свои методы получения и установки такими, как они есть.

Измените свой ввод следующим образом:

<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 .

Надеюсь, это поможет.

0 голосов
/ 23 октября 2019

В качестве альтернативы вы можете использовать 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; }
}

Отправитель: Вы можете зарегистрироватьсяздесь компонент, отправляющий данные

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

0 голосов
/ 22 октября 2019

Да, у вас есть два элемента управления, которые не связаны напрямую, поэтому вы не можете просто передать параметр.

Два варианта:

Каскадные параметры: https://docs.microsoft.com/en-us/aspnet/core/blazor/components?view=aspnetcore-3.0#cascading-values-and-parameters

Или государственное управление. Для управления состоянием это может помочь: Реализация управления состоянием в 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;
    }
...