Лучший способ обмена данными между двумя дочерними компонентами в Blazor - PullRequest
1 голос
/ 27 мая 2020

У меня есть этот код.

<ParentComponent>
    <ChildComponet>
         @renderFragment
    </ChildComponent>
    <ChildComponetn>
       <GridComponent Data="@dataList"/>
    </ChildComponent>
</ParentComponent>

где @renderFragment - это динамически отрисовка comp onet, а Grid comp onet - это список некоторых данных с такими действиями, как «добавить новый», «отредактировать запись» , «удалить».

Если мы нажмем «добавить новую», форма для добавления новой записи откроется динамически в @renderFragment, и мы хотим обновить sh данные сетки после формы отправки, но мы не знаем, как для обмена данными между двумя дочерними компонентами. То же самое и с формой редактирования, когда редактируется какая-то запись, нам нужно обновить компонент сетки sh, чтобы отобразить отредактированные данные. Если нужно больше кода и данных о нем, прокомментируйте.

Ответы [ 2 ]

3 голосов
/ 27 мая 2020

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

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

NotifierService.cs

public class NotifierService
{
    private readonly List<string> values = new List<string>();
    public IReadOnlyList<string> ValuesList => values;

    public NotifierService()
    {

    }

    public async Task AddTolist(string value)
    {
        values.Add(value);
        if (Notify != null)
        {
            await Notify?.Invoke();
        }

    }

    public event Func<Task> Notify;
 }

Child1.razor

 @inject NotifierService Notifier
 @implements IDisposable

 <h1>User puts in something</h1>
 <input type="text" @bind="@value" />
 <button @onclick="@AddValue">Add value</button>

 @foreach (var value in Notifier.ValuesList)
 {
    <p>@value</p>
 }


@code {
    private string value { get; set; }

    public async Task AddValue()
    {
        await Notifier.AddTolist(value);
    }

    public async Task OnNotify()
   {
      await InvokeAsync(() =>
      {
        StateHasChanged();
      });
   }


  protected override void OnInitialized()
  {
     Notifier.Notify += OnNotify;
  }


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

Child2.razor

@inject NotifierService Notifier

<h1>Displays Value from service and lets user put in new value</h1>

<input type="text" @bind="@value" />

<button @onclick="@AddValue">Set Value</button>

@code {
   private string value { get; set; }
   public async Task AddValue()
   {
      await Notifier.AddTolist(value);

   }

 }

Использование

 @page "/"

 <Child1></Child1>
 <Child2></Child2>

Startup.ConfigureServices

services.AddScoped<NotifierService>();

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

0 голосов
/ 27 мая 2020

Есть несколько способов сделать это, я только что научился классному способу, используя класс Singleton.

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

Добавьте этот ввод к обоим вашим компонентам:

@inject Services.SubscriberService SubscriberService



#region using statements

using DataJuggler.UltimateHelper.Core;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Transactions;

#endregion

namespace BlazorChat.Services
{

    #region class SubscriberService
    /// <summary>
    /// This class is used to subscribe to services, so other windows get a notification a new message 
    /// came in.
    /// </summary>
    public class SubscriberService
    {

        #region Private Variables
        private int count;
        private Guid serverId;
        private List<SubscriberCallback> subscribers;
        #endregion

        #region Constructor
        /// <summary>
        /// Create a new instance of a 'SubscriberService' object.
        /// </summary>
        public SubscriberService()
        {
            // Create a new Guid
            this.ServerId = Guid.NewGuid();
            Subscribers = new List<SubscriberCallback>();
        }
        #endregion

        #region Methods

            #region BroadcastMessage(SubscriberMessage message)
            /// <summary>
            /// This method Broadcasts a Message to everyone that ins't blocked.
            /// Note To Self: Add Blocked Feature
            /// </summary>
            public void BroadcastMessage(SubscriberMessage message)
            {
                // if the value for HasSubscribers is true
                if ((HasSubscribers) && (NullHelper.Exists(message)))
                {   
                    // Iterate the collection of SubscriberCallback objects
                    foreach (SubscriberCallback subscriber in Subscribers)
                    {
                        // if the Callback exists
                        if ((subscriber.HasCallback) && (subscriber.Id != message.FromId))
                        {
                            // to do: Add if not blocked

                            // send the message
                            subscriber.Callback(message);
                        }
                    }
                }
            }
            #endregion

            #region GetSubscriberNames()
            /// <summary>
            /// This method returns a list of Subscriber Names ()
            /// </summary>
            public List<string> GetSubscriberNames()
            {
                // initial value
                List<string> subscriberNames = null;

                // if the value for HasSubscribers is true
                if (HasSubscribers)
                {
                    // create the return value
                    subscriberNames = new List<string>();

                    // Get the SubscriberNamesl in alphabetical order
                    List<SubscriberCallback> sortedNames = Subscribers.OrderBy(x => x.Name).ToList();

                    // Iterate the collection of SubscriberService objects
                    foreach (SubscriberCallback subscriber in sortedNames)
                    {
                        // Add this name
                        subscriberNames.Add(subscriber.Name);
                    }
                }

                // return value
                return subscriberNames;
            }
            #endregion

            #region Subscribe(string subscriberName)
            /// <summary>
            /// method returns a message with their id
            /// </summary>
            public SubscriberMessage Subscribe(SubscriberCallback subscriber)
            {
                // initial value
                SubscriberMessage message = null;

                // If the subscriber object exists
                if ((NullHelper.Exists(subscriber)) && (HasSubscribers))
                {
                    // Add this item
                    Subscribers.Add(subscriber);    

                    // return a test message for now
                    message = new SubscriberMessage();

                    // set the message return properties
                    message.FromName = "Subscriber Service";
                    message.FromId = ServerId;
                    message.ToName = subscriber.Name;
                    message.ToId = subscriber.Id;
                    message.Data = Subscribers.Count.ToString();
                    message.Text = "Subscribed";
                }

                // return value
                return message;
            }
            #endregion

            #region Unsubscribe(Guid id)
            /// <summary>
            /// This method Unsubscribe
            /// </summary>
            public void Unsubscribe(Guid id)
            {
                // if the value for HasSubscribers is true
                if ((HasSubscribers) && (Subscribers.Count > 0))
                {
                    // attempt to find this callback
                    SubscriberCallback callback = Subscribers.FirstOrDefault(x => x.Id == id);

                    // If the callback object exists
                    if (NullHelper.Exists(callback))
                    {
                        // Remove this item
                        Subscribers.Remove(callback);

                         // create a new message
                        SubscriberMessage message = new SubscriberMessage();

                        // set the message return properties
                        message.FromId = ServerId;
                        message.FromName = "Subscriber Service";
                        message.Text = callback.Name + " has left the conversation.";
                        message.ToId = Guid.Empty;
                        message.ToName = "Room";

                        // Broadcast the message to everyone
                        BroadcastMessage(message);
                    }
                }
            }
            #endregion

        #endregion

        #region Properties

            #region Count
            /// <summary>
            /// This property gets or sets the value for 'Count'.
            /// </summary>
            public int Count
            {
                get { return count; }
                set { count = value; }
            }
            #endregion

            #region HasSubscribers
            /// <summary>
            /// This property returns true if this object has a 'Subscribers'.
            /// </summary>
            public bool HasSubscribers
            {
                get
                {
                    // initial value
                    bool hasSubscribers = (this.Subscribers != null);

                    // return value
                    return hasSubscribers;
                }
            }
            #endregion

            #region ServerId
            /// <summary>
            /// This property gets or sets the value for 'ServerId'.
            /// </summary>
            public Guid ServerId
            {
                get { return serverId; }
                set { serverId = value; }
            }
            #endregion

            #region Subscribers
            /// <summary>
            /// This property gets or sets the value for 'Subscribers'.
            /// </summary>
            public List<SubscriberCallback> Subscribers
            {
                get { return subscribers; }
                set { subscribers = value; }
            }
            #endregion

        #endregion

    }
    #endregion

}

Для моего приложения чата я хочу, чтобы он был доступен для всех экземпляров, поэтому в вашем методе настройки служб Startup.cs, добавьте Sington:

services.AddSingleton<SubscriberService>();

Чтобы он был доступен только этому экземпляру браузера:

services.AddScoped(SubscriberService);

Теперь из обоих компонентов вы можете вызвать метод или перейти к свойствам на ваш введенный класс:

SubscriptionService.GetSubscribers();

Или, если вы предпочитаете интерфейсы, я написал об этом сообщение в блоге, и я не хочу дублировать текст:

https://datajugglerblazor.blogspot.com/2020/01/how-to-use-interfaces-to-communicate.html

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

...