From 69498f68f98005202e9102e3c768046413095fac Mon Sep 17 00:00:00 2001 From: Steve Sanderson Date: Fri, 16 Feb 2018 14:54:30 +0000 Subject: [PATCH] Add LayoutDisplay component and use it in StandaloneApp --- samples/StandaloneApp/App.cshtml | 2 + samples/StandaloneApp/Home.cshtml | 1 - samples/StandaloneApp/Pages/Home.cshtml | 2 + samples/StandaloneApp/Program.cs | 2 +- .../StandaloneApp/Shared/MainLayout.cshtml | 11 +++ .../targets/All.targets | 3 + .../Layouts/LayoutDisplay.cs | 67 +++++++++++++++++++ 7 files changed, 86 insertions(+), 2 deletions(-) create mode 100644 samples/StandaloneApp/App.cshtml delete mode 100644 samples/StandaloneApp/Home.cshtml create mode 100644 samples/StandaloneApp/Pages/Home.cshtml create mode 100644 samples/StandaloneApp/Shared/MainLayout.cshtml create mode 100644 src/Microsoft.AspNetCore.Blazor/Layouts/LayoutDisplay.cs diff --git a/samples/StandaloneApp/App.cshtml b/samples/StandaloneApp/App.cshtml new file mode 100644 index 0000000000..2336a07b22 --- /dev/null +++ b/samples/StandaloneApp/App.cshtml @@ -0,0 +1,2 @@ +@using Microsoft.AspNetCore.Blazor.Layouts + diff --git a/samples/StandaloneApp/Home.cshtml b/samples/StandaloneApp/Home.cshtml deleted file mode 100644 index 0ad1ea275e..0000000000 --- a/samples/StandaloneApp/Home.cshtml +++ /dev/null @@ -1 +0,0 @@ -

Hello, world!

diff --git a/samples/StandaloneApp/Pages/Home.cshtml b/samples/StandaloneApp/Pages/Home.cshtml new file mode 100644 index 0000000000..08af6d96be --- /dev/null +++ b/samples/StandaloneApp/Pages/Home.cshtml @@ -0,0 +1,2 @@ +@(Layout()) +

Hello, world!

diff --git a/samples/StandaloneApp/Program.cs b/samples/StandaloneApp/Program.cs index e4863042a8..1244342d11 100644 --- a/samples/StandaloneApp/Program.cs +++ b/samples/StandaloneApp/Program.cs @@ -9,7 +9,7 @@ namespace StandaloneApp { public static void Main(string[] args) { - new BrowserRenderer().AddComponent("app"); + new BrowserRenderer().AddComponent("app"); } } } diff --git a/samples/StandaloneApp/Shared/MainLayout.cshtml b/samples/StandaloneApp/Shared/MainLayout.cshtml new file mode 100644 index 0000000000..6a830c938a --- /dev/null +++ b/samples/StandaloneApp/Shared/MainLayout.cshtml @@ -0,0 +1,11 @@ +@using Microsoft.AspNetCore.Blazor.RenderTree +@(Implements()) + +
+ Layout + @Body +
+ +@functions { + public RenderFragment Body { get; set; } +} diff --git a/src/Microsoft.AspNetCore.Blazor.Build/targets/All.targets b/src/Microsoft.AspNetCore.Blazor.Build/targets/All.targets index 76a766f55b..71a1e527cc 100644 --- a/src/Microsoft.AspNetCore.Blazor.Build/targets/All.targets +++ b/src/Microsoft.AspNetCore.Blazor.Build/targets/All.targets @@ -1,6 +1,9 @@ dotnet "$(MSBuildThisFileDirectory)../tools/Microsoft.AspNetCore.Blazor.Build.dll" + + + true diff --git a/src/Microsoft.AspNetCore.Blazor/Layouts/LayoutDisplay.cs b/src/Microsoft.AspNetCore.Blazor/Layouts/LayoutDisplay.cs new file mode 100644 index 0000000000..80a30c5576 --- /dev/null +++ b/src/Microsoft.AspNetCore.Blazor/Layouts/LayoutDisplay.cs @@ -0,0 +1,67 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Reflection; +using Microsoft.AspNetCore.Blazor.Components; +using Microsoft.AspNetCore.Blazor.RenderTree; + +namespace Microsoft.AspNetCore.Blazor.Layouts +{ + /// + /// Displays the specified page component, rendering it inside its layout + /// and any further nested layouts. + /// + public class LayoutDisplay : IComponent + { + private RenderHandle _renderHandle; + + /// + /// Gets or sets the type of the page component to display. + /// The type must implement . + /// + public Type Page { get; set; } + + /// + public void Init(RenderHandle renderHandle) + { + _renderHandle = renderHandle; + } + + /// + public void SetParameters(ParameterCollection parameters) + { + parameters.AssignToProperties(this); + Render(); + } + + private void Render() + { + // In the middle, we render the requested page + var fragment = RenderComponentWithBody(Page, bodyParam: null); + + // Repeatedly wrap it in each layer of nested layout until we get + // to a layout that has no parent + Type layoutType = Page; + while ((layoutType = GetLayoutType(layoutType)) != null) + { + fragment = RenderComponentWithBody(layoutType, fragment); + } + + _renderHandle.Render(fragment); + } + + private RenderFragment RenderComponentWithBody(Type componentType, RenderFragment bodyParam) => builder => + { + builder.OpenComponent(0, componentType); + if (bodyParam != null) + { + builder.AddAttribute(1, nameof(ILayoutComponent.Body), bodyParam); + } + builder.CloseComponent(); + }; + + private Type GetLayoutType(Type type) + => type.GetCustomAttribute()?.LayoutType; + } +}