Blazor无限级Dialog解决方案

设计思路

1.通过DialogContainer组件动态显示
2.使用Dictionary存储所有显示的Dialog
3.使用StateHasChanged强制更新DialogContainer呈现树
4.主要代码如下

DialogOption

public class DialogOption {
    public string Title { get; set; }
    public int Width { get; set; } = 500;
    public int Height { get; set; } = 300;
    public RenderFragment Content { get; set; }
}

DialogContainer

public class DialogContainer : BaseComponent {
    private string previous;//上一个Dialog
    private string current; //当前Dialog
    //存储所有Dialog
    private readonly Dictionary<string, DialogOption> dialogs = new();

    public void Show(DialogOption option) {
        previous = current;
        current = option.Title;
        if (!dialogs.ContainsKey(current)) {
            dialogs[option.Title] = option;
            StateHasChanged();
        }
    }

    public void Close() {
        if (string.IsNullOrWhiteSpace(current))
            return;
        if (dialogs.ContainsKey(current)) {
            dialogs.Remove(current);
            current = previous;
            StateHasChanged();
        }
    }

    protected override void OnInitialized() {
        base.OnInitialized();
        if (DialogService != null) {
            DialogService.Register(this);
        }
    }

    protected override void BuildRenderTree(RenderTreeBuilder builder) {
        foreach (var item in dialogs) {
            var option = item.Value;
            builder.Component<Dialog>(attr =>
            {
                attr.Add(nameof(Dialog.Title), option.Title)
                    .Add(nameof(Dialog.Width), option.Width)
                    .Add(nameof(Dialog.Height), option.Height)
                    .Add(nameof(Dialog.Content), option.Content)
                    .Add(nameof(Dialog.OnClose), Callback(e => Close()));
            });
        }
    }
}

Dialog

public class Dialog : BaseComponent {
    [Parameter] public string Title { get; set; }
    [Parameter] public int Width { get; set; } = 500;
    [Parameter] public int Height { get; set; } = 300;
    [Parameter] public RenderFragment Content { get; set; }
    [Parameter] public EventCallback OnClose { get; set; }

    protected override void BuildRenderTree(RenderTreeBuilder builder) {
        builder.Div(attr => attr.Class("mask"));
        builder.Div(attr =>
        {
            attr.Class("dialog").Style(GetStyle());
            BuildHead(builder);
            BuildContent(builder);
        });
    }

    private void BuildHead(RenderTreeBuilder builder) { }

    private void BuildContent(RenderTreeBuilder builder) { }

    private string GetStyle() {
        return new StyleBuilder()
                .Add("width", $"{Width}px")
                .Add("height", $"{Height}px")
                .Add("margin-top", $"-{Height / 2}px")
                .Add("margin-left", $"-{Width / 2}px")
                .Build();
    }
}

DialogService

public class DialogService {
    private DialogContainer Dialog { get; set; }

    public void Show(DialogOption option) {
        Dialog.Show(option);
    }

    internal void Register(DialogContainer dialog) {
        Dialog = dialog;
    }
}
posted @ 2022-04-30 22:31  known  阅读(95)  评论(0编辑  收藏  举报