Blazor page elements other than Body

后端 未结 2 1697
傲寒
傲寒 2020-12-20 08:52

I have a Blazor server-side app, trying to understand the structure. Inside the MainLayout.razor page, I see the tag @Body, and this is where each page\'s content is rendere

2条回答
  •  北海茫月
    2020-12-20 09:06

    Here is a more Dynamic solution:

    MainLayout.razor

    @inherits LayoutComponentBase
    
    
    
    
    @Body

    AppHeader.razor

    @implements IDisposable
    
    @LayoutService.Header
    @code {
        [Inject]
        public ILayoutService LayoutService { get; set; }
    
        protected override void OnInitialized()
        {
            LayoutService.PropertyChanged += LayoutService_PropertyChanged;
            base.OnInitialized();
        }
    
        private void LayoutService_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
        {
            if (e.PropertyName == nameof(ILayoutService.Header))
            {
                StateHasChanged();
            }
        }
    
        public void Dispose()
        {
            if (LayoutService != null)
            {
                LayoutService.PropertyChanged -= LayoutService_PropertyChanged;
            }
        }
    
    }
    

    ILayoutService.cs

    public interface ILayoutService
    {    
        RenderFragment Header { get; }    
        SetHeader HeaderSetter { get; set; }
        event PropertyChangedEventHandler PropertyChanged;    
        void UpdateHeader();
    }
    

    LayoutService.cs

    public class LayoutService : ILayoutService, INotifyPropertyChanged
    {
    
        public RenderFragment Header => HeaderSetter?.ChildContent;
    
        public SetHeader HeaderSetter
        {
            get => headerSetter;
            set
            {
                if (headerSetter == value) return;
                headerSetter = value;
                UpdateHeader();
            }
        }
    
        public void UpdateHeader() => NotifyPropertyChanged(nameof(Header));
    
        public event PropertyChangedEventHandler PropertyChanged;
    
        private void NotifyPropertyChanged([CallerMemberName] string propertyName = "")
            => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    
        private SetHeader headerSetter;
    }
    
    

    The Setter

    SetHeader.cs

    public class SetHeader : ComponentBase, IDisposable
    {
        [Inject]
        private ILayoutService Layout { get; set; }
    
        [Parameter]
        public RenderFragment ChildContent { get; set; }
    
        protected override void OnInitialized()
        {
            if (Layout != null)
            {
                Layout.HeaderSetter = this;
            }
            base.OnInitialized();
        }
    
        protected override bool ShouldRender()
        {
            var shouldRender = base.ShouldRender();
            if (shouldRender)
            {
                Layout.UpdateHeader();
            }
            return shouldRender;
        }
    
        public void Dispose()
        {
            if (Layout != null)
            {
                Layout.HeaderSetter = null;
            }
        }
    
    }
    

    Provide the service:

    In my case Program.cs

     builder.Services.AddScoped();
    

    Example

    @page "/counter"
    
    

    Counter

    Current count: @currentCount

    Hello Current count: @currentCount

    Goodbye Current count: @currentCount

    @code { private int currentCount = 0; private void IncrementCount() => currentCount++; }

    This also clears the values on navigation as I am using IDisposable . The Setter does not have to be set (Null is ok). If more than one setter is used the latest takes precedence. I have not tested dynamically removing multiple setters on one page.

    Here is a repo using WebAssembly 3.2.1

提交回复
热议问题