首页 > 解决方案 > Blazor:如何将 ViewModel 从子组件传递到父组件,反之亦然

问题描述

如何在 Blazor 中将 ViewModel 从子组件传递到父组件,反之亦然

我正在使用 MVVM 模式来构建 Blazor 应用程序。

尝试以下代码但无法正常工作

[Parameter]
public ViewModel viewModel { get; set; }

标签: blazorblazor-server-sideblazor-client-side

解决方案


我写了一篇关于 Blazor 中父子通信的博客文章。

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

我创建了一个 Nuget 包来简化此操作:

DataJuggler.Blazor.Components

我创建父子通信的方式是通过您的父组件或页面实现此 IBlazorComponentParent 接口:

#region using statements

using System.Collections.Generic;

#endregion

namespace DataJuggler.Blazor.Components.Interfaces
{

    #region interface IBlazorComponentParent
    /// <summary>
    /// This interface is used to host IBlazorComponent objects
    /// </summary>
    public interface IBlazorComponentParent
    {

        #region Methods

            #region FindChildByName(string name)
            /// <summary>
            /// This method is used to find a child component that has registered with the parent.
            /// </summary>
            /// <param name="name"></param>
            /// <returns></returns>
            IBlazorComponent FindChildByName(string name);
            #endregion

            #region ReceiveData(Message message)
            /// <summary>
            /// This method is used to send data from a child component to the parent component or page.
            /// </summary>
            /// <param name="data"></param>
            void ReceiveData(Message message);
            #endregion

            #region Refresh()
            /// <summary>
            /// This method will call StateHasChanged to refresh the UI
            /// </summary>
            void Refresh();
            #endregion

            #region Register(IBlazorComponent component)
            /// <summary>
            /// This method is called by the Sprite to a subscriber so it can register with the subscriber, and 
            /// receiver events after that.
            /// </summary>
            void Register(IBlazorComponent component);    
            #endregion

        #endregion

        #region Properties

            #region Children
            /// <summary>
            /// This property gets or sets the value for Children.
            /// </summary>
            public List<IBlazorComponent> Children { get; set; }
            #endregion

        #endregion

    }
    #endregion

}

然后你的子组件实现 IBlazorComponent

#region using statements

using System.Collections.Generic;

#endregion

namespace DataJuggler.Blazor.Components.Interfaces
{

    #region interface IBlazorComponent
    /// <summary>
    /// This interface allows communication between a blazor componetn and a parent component or page.
    /// </summary>
    public interface IBlazorComponent
    {

        #region Methods

            #region ReceiveData(Message message)
            /// <summary>
            /// This method is used to send data from a child component to the parent component or page.
            /// </summary>
            /// <param name="data"></param>
            void ReceiveData(Message message);
            #endregion

        #endregion

        #region Properties

            #region Name
            /// <summary>
            /// This property gets or sets the Name.
            /// </summary>
            public string Name { get; set; }
            #endregion

            #region Parent
            /// <summary>
            /// This property gets or sets the Parent componet or page for this object.
            /// </summary>
            public IBlazorComponentParent Parent { get; set; }
            #endregion

        #endregion

    }
    #endregion

}

然后当你实现你的组件时,你设置 Parent=this:

<div class="galleryimages">
    @if (SelectedArtist.HasImages)
    { 
        @foreach (Image image in SelectedArtist.Images)
        {  
            <ImageButton Image=image Parent=this></ImageButton>
        }
    }
</div>

在我的 Image 组件的 Parent 的 setter 属性中,我向父级注册:

private IBlazorComponentParent parent;

[Parameter]
public IBlazorComponentParent Parent
{
    get { return parent; }
    set 
    { 
       // store the parent
       parent = value;

       // if the value for HasParent is true
       if (HasParent)
       {
           // Register with the parent
           Parent.Register(this);
       }
   }

在我的索引页面上,我的注册方法如下所示:

public void Register(IBlazorComponent component)
{
    // If the component object exists
    if (NullHelper.Exists(component, Children))
    {
        // If this is the Login component
        if (component.Name == "Login")
        {
            // Set the Signup control
            this.Login = component as Login;
        }

        // add this child
        Children.Add(component);
    }
}

现在,Parent 和 Child 都有一个 ReceiveData 方法,您可以在其中发送我称为 MessageObject 的内容。

    // Create a message
    Message message = new Message();

    // Send a clear message
    message.Text = "";

    // Send data
    NamedParameter parameter = new NamedParameter();

    // set the properties and add new parameter
    parameter.Name = "MyData";
    parameter.Value = myData;
    message.Parameters.Add(parameter);
}

在您的接收数据方法中,读取您的参数并进行更新。

这是我的 Blazor Image Gallery 示例项目的示例,我在用户登录后读取了参数:

public void ReceiveData(Message message)
{
    // If the message object exists
    if (NullHelper.Exists(message))
    {
        // if a NewArtist signed up or Logged In
        if (message.Text == "Artist Logged In"
        {
            // if the parameters collection exists
            if (message.HasParameters)
            {
                // iterate the parameters                            
                foreach (NamedParameter parameter in message.Parameters)                                           
                {
                    // if this is the name
                    if (parameter.Name == "Artist")
                    {
                        // Get the login response
                        LoginResponse loginResponse = parameter.Value as LoginResponse;

                        // If the loginResponse object exists
                        if (NullHelper.Exists(loginResponse))
                        {
                            // Update the UI that we have a login
                            LoginComplete(loginResponse);
                        }
                    }
                 }
              }
            }
            else
            {
                // Set the message text
                this.Message = message.Text;

                // Update the UI
                Refresh();
            }
        }
    }

如果您想查看它,这是一个完整的工作项目: https ://github.com/DataJuggler/BlazorImageGallery

如果你觉得无聊,这里还有一段视频:

https://youtu.be/3xKXJQ4qThQ

也许这会给你一些想法。


推荐阅读