Blazor page elements other than Body

后端 未结 2 1695
傲寒
傲寒 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
    
    <div class="sidebar">
        <AppNavigation />
    </div>
    
    <div class="main">
        <div class="top-row px-4">
            <AppHeader />
        </div>
    
        <div class="content px-4">
            @Body
        </div>
    
        <div class="bottom-row px-4">
            <AppFooter />
        </div>
    </div>
    
    

    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<ILayoutService, LayoutService>();
    

    Example

    @page "/counter"
    
    <h1>Counter</h1>
    
    <p>Current count: @currentCount</p>
    
    <button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
    
    <SetHeader>
        <p>Hello Current count: @currentCount</p>
    </SetHeader>
    
    <SetFooter>
        <p>Goodbye Current count: @currentCount</p>
    </SetFooter>
    
    @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

    0 讨论(0)
  • 2020-12-20 09:16

    MainLayout.razor

    Note: The use of a method to update the render fragment fields I deliberately made private which then calls StateHasChanged(). Other methods could easily be created to clear or set other fields.

    @inherits LayoutComponentBase
    
    <CascadingValue Value="this">
        <div class="page">
            <div class="sidebar">
                <NavMenu />
            </div>
            <div class="main">
                <div class="top-row px-4">
                    @header
                </div>
    
                <div class="content px-4">
                    @Body
                    @footer
                </div>
            </div>
        </div>
    </CascadingValue>
    
    @code {
        private RenderFragment header;
        private RenderFragment footer;
    
        public void SetHeaderAndFooter(RenderFragment header, RenderFragment footer)
        {
            this.header = header;
            this.footer = footer;
            StateHasChanged();
        }
    }
    
    

    LayoutSetter.cs

    
    public class LayoutSetter : ComponentBase
    {
        [CascadingParameter]
        public MainLayout Layout { get; set; }
    
        [Parameter]
        public RenderFragment Header { get; set; }
    
        [Parameter]
        public RenderFragment Footer { get; set; }
    
        protected override void OnInitialized()
        {
            Layout.SetHeaderAndFooter(Header, Footer);
        }
    }
    
    

    On any page...

    @page "/"
    
    <h1>Hello, world!</h1>
    
    <LayoutSetter>
        <Header>
            Hello
        </Header>
        <Footer>
            Goodbye
        </Footer>
    </LayoutSetter>
    
    0 讨论(0)
提交回复
热议问题