Прикрепите компонент блазора динамически - PullRequest
1 голос
/ 25 февраля 2020

Могу ли я создать экземпляр компонента Blazor в C# и впоследствии присоединить его? В качестве альтернативы можно из кода C# динамически создать компонент в DOM и получить ссылку на него?

Я создаю «всплывающее диалоговое окно», запускаемое из кода C#.

Dialog.razor

<div>
    Dialog Text: @Text
</div>

@code{
    public string Text { get; set; }
}

Неудачная попытка

<div>
    @foreach (var d in List)
    {
        <div>@d</div><!--this doesn't work since d is not a RenderFragment-->
    }
</div>

@code{
    public List<Dialog> List { get; set; } = new List<Dialog>();

    void AddDialog()
    {
        var d = new Dialog();
        d.Text = "Hello " + List.Count;
        List.Add(d);
    }
}

Проблема в том, что я не нашел способ прикрепить экземпляр ComponentBase на DOM. Есть ли способ получить RenderFragment?

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

Ответы [ 2 ]

3 голосов
/ 25 февраля 2020

Это еще один способ сделать это ...

AlertMessage.razor

<div style="border: 1px solid red; width: 500px; height:auto; margin: 3px; 
  padding:0px;">
    <div style="height:auto; width:inherit; padding:5px; border: 1px solid 
    blue; text-align:right;">
        <span style="float:left">@Title</span>
        <a href="#" @onclick="@(() => Close.InvokeAsync(ID))" 
   role="button">X</a>
        <div><input type="text" value="@content" /></div>
    </div>
     <div style="padding:25px; ">@ChildContent</div> 

 </div>

@code {
  [Parameter]
  public int ID { get; set; }
  [Parameter]
  public string Title { get; set; }
  [Parameter]
  public RenderFragment ChildContent { get; set; }
  [Parameter]
  public EventCallback <int> Close {get; set;}

}

AlertMessageGroup.razor

@using Microsoft.AspNetCore.Components.CompilerServices;


<h3>AlertMessageGroup</h3>
@if (alerts.Count > 0)
{
<p>Contains @alerts.Count AlertMessage Components</p>

@foreach (var alert in alerts)
 {
       <p>Alert ID: @alert.ID</p>

 }
}

<div>

    @foreach (var alert in alerts)
    {
        @RenderAlert(alert);

    }


</div>



@code {

List<Alert> alerts = new List<Alert>
        {
            new Alert{ ID = 1, Title = "First Message", Message = "This is my 
                                                            first message" },
            new Alert{ ID = 2, Title = "Second Message", Message = "This is 
                                                        my second message" },
            new Alert{ ID = 3, Title = "Third Message", Message = "This is my 
                                                             third message" }
        };


private RenderFragment RenderAlert(Alert alert) => builder =>
{

    builder.OpenComponent(0, typeof(AlertMessage));
    builder.AddAttribute(1, "ID", alert.ID);
    builder.AddAttribute(2, "Title", alert.Title);


    builder.AddAttribute(3, "ChildContent", (RenderFragment)((builder) =>
    {
        builder.AddContent(4, alert.Message);


    }
    ));

     builder.AddAttribute(5, "Close", EventCallback.Factory.Create<int>
                                          (this, RemoveAlertMessage));
     builder.CloseComponent();

  };



public void RemoveAlertMessage(int ID)
{

    alerts.Remove( alerts.Where(alert => alert.ID == ID).FirstOrDefault());
    StateHasChanged();
}


public class Alert
{
    public int ID { get; set; }
    public string Title { get; set; }
    public string Message { get; set; }

}

}

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

@page "/"

<AlertMessageGroup />
1 голос
/ 25 февраля 2020

Это один из способов сделать это

  1. Создать Placeholder объект и поместить его в список
  2. Из списка страница бритвы создаст новый экземпляр.
  3. Перехватите ссылку на экземпляр и передайте ее вызывающему коду
  4. Подождите, пока OnAfterRender, прежде чем работать с экземпляром.

Dialog.razor
Не знает, что он загружается динамически.

<div>
    Dialog Text: @Text
    <Red @ref="Red"></Red>
</div>

@code{
    public Red Red { get; set; }

    public string Text { get; set; }

    public void SetText(string text)
    {
        this.Text = text;
        StateHasChanged();
    }
}

DynamicWrapper.razor Для уведомления о полной загрузке компонента

@ChildContent

@code{
    [Parameter]
    public RenderFragment ChildContent { get; set; }

    [Parameter]
    public EventCallback AfterFirstRender { get; set; }

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
            await AfterFirstRender.InvokeAsync(null);

        base.OnAfterRender(firstRender);
    }
}

TestPage.razor

<div><button @onclick="AddDialog">Add one more</button></div>

<div>
    @foreach (var p in List)
    {
        <DynamicWrapper AfterFirstRender="p.AfterFirstRender">
            <Dialog @ref="p.Dialog"></Dialog>
        </DynamicWrapper>
    }
</div>

@code{
    public class Placeholder<T>
    {
        public T Dialog { get; set; }

        TaskCompletionSource<T> task = new TaskCompletionSource<T>();

        public void AfterFirstRender(object args)
        {
            task.SetResult(Dialog);
        }

        public Task<T> GetDialog() => task.Task;
    }

    public List<Placeholder<Dialog>> List { get; set; } = new List<Placeholder<Dialog>>();

    async Task AddDialog()
    {
        var p = new Placeholder<Dialog>();
        List.Add(p);
        var d = await p.GetDialog();
        d.SetText("Hello");
        d.Red.Show();
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...