Компонент Blazor должен изменить значение родительского компонента - PullRequest
0 голосов
/ 23 апреля 2020

В моем приложении Blazor есть следующие два компонента:

Component1.razor:

<CascadingValue Value=this>
    <Component2/>
</CascadingValue>

<p>@DisplayedText</p>

@code {
    public string DisplayedText = string.Empty;
}

Component2.razor:

<button @onclick=@(e => { C1.DisplayedText = "testing"; })>Set DisplayedText</button>

@code {
    [CascadingParameter]
    public Component1 C1 { get; set; }
}

Когда я нажимаю " Установить DisplayedText ", текст в элементе p в Component1 должен измениться на testing, но это не так. Как я могу это исправить?

Ответы [ 3 ]

2 голосов
/ 24 апреля 2020

Merlin04, следующий фрагмент кода демонстрирует, как вы можете это сделать. Обратите внимание, что это действительно очень простой пример, но он показывает, как вам следует кодировать, когда требуется связь между удаленными компонентами.

Вот код, скопируйте и запустите его, и если у вас есть дополнительные вопросы, не стесняйтесь спросить.

MessageService.cs

 public class MessageService
{
    private string message;
    public string Message
    {
        get => message;
        set
        {
            if (message != value)
            {
                message = value;
                if (Notify != null)
                {
                     Notify?.Invoke();
                }

            }
        }
    }

    public event Action Notify;
}

Примечание. Служба является обычным классом ... Она предоставляет службы другим объектам и должна быть добавлена ​​в контейнер DI при запуске. Метод .ConfigureServices, чтобы сделать его доступным для запрашивающих клиентов. Добавьте это: в метод ConfigureServices:

 services.AddScoped<MessageService>();

Примечание. Как видите, я определяю делегат события типа Action, который вызывается из метода доступа set свойства, когда пользователь вводит текст в текст коробка в Компоненте3. При запуске этого делегата текст, введенный Components3, будет отображаться в компоненте Index, который является родительским для Component2 (см. Код ниже).

Index.razor

@page "/"

@inject MessageService MessageService
@implements IDisposable

<p>I'm the parent of Component2. I've got a message from my grand child: 
                                            @MessageService.Message</p>

<Component2 />

@code {
protected override void OnInitialized()
{
    MessageService.Notify += OnNotify;
}

public void OnNotify()
{
    InvokeAsync(() =>
    {
        StateHasChanged();
    });
 }

 public void Dispose()
 {
    MessageService.Notify -= OnNotify;
 }
}

Обратите внимание, что мы непосредственно привязать к свойству MessageService.Message, но метод StateHasChanged должен быть вызван для обновления sh отображения текста.

Component2.razor

<h3>Component2: I'm the parent of component three</h3>
<Component3/>

@code {

}

Component3.razor

@inject MessageService MessageService

<p>This is component3. Please type a message to my grand parent</p>
<input placeholder="Type a message to grandpa..." type="text" 
@bind="@MessageService.Message" @bind:event="oninput" />

Обратите внимание, что в Component3 мы связываем MessageService.Message с текстовым полем, и привязка происходит каждый раз, когда вы нажимаете клавиатуру (событие ввода или событие изменения).

Вот и все, надеюсь, что это поможет, и не стесняйтесь задавать любые вопросы.

1 голос
/ 23 апреля 2020

@ Merlin04, это злоупотребление и неправильное использование функции каскадного значения. Обычно родительский компонент связывается со своим дочерним элементом через параметры компонента.

Невозможно обновить каскадное значение от потомка.

Неверно ...

Следующий фрагмент кода демонстрирует лучшее решение на основе на то, что вы делаете, хотя это не оптимально, потому что ваш код и мой также обновляют свойство из метода, тогда как на самом деле мы должны изменить значение свойства напрямую, а не через код посредника (то есть метод)

Component2.razor

<button @onclick="@(() => SetDisplayedText.InvokeAsync("testing"))">Set 
                                                 DisplayedText</button>

@code {
   [Parameter]
   public EventCallback<string> SetDisplayedText { get; set; }
}

Component1.razor

<Component2 SetDisplayedText="@SetDisplayedText"/>

<p>@DisplayedText</p>

@code {
    private string DisplayedText = string.Empty;

    public void SetDisplayedText(string newText)
   {
       DisplayedText = newText;
   }
}

Обратите внимание, что вызывать метод StateHasChanged не нужно, поскольку это бонус, который вы получаете при использовании EventCallback 'делегат'

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

0 голосов
/ 23 апреля 2020

См. enet ответ вместо этого

Вы не можете обновить каскадное значение от потомка.

Вместо этого создайте метод в родительском (Component1) для установки значение:

public void SetDisplayedText(string newText) {
    DisplayedText = newText;
    StateHasChanged();
}

Затем вы можете вызвать это в потомке:

<button @onclick=@(e => { C1.SetDisplayedText("testing"); })>Set DisplayedText</button>
...