BpfLayout 0.4.0

There is a newer version of this package available.
See the version list below for details.
dotnet add package BpfLayout --version 0.4.0
                    
NuGet\Install-Package BpfLayout -Version 0.4.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="BpfLayout" Version="0.4.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="BpfLayout" Version="0.4.0" />
                    
Directory.Packages.props
<PackageReference Include="BpfLayout" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add BpfLayout --version 0.4.0
                    
#r "nuget: BpfLayout, 0.4.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package BpfLayout@0.4.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=BpfLayout&version=0.4.0
                    
Install as a Cake Addin
#tool nuget:?package=BpfLayout&version=0.4.0
                    
Install as a Cake Tool

BpfLayout

A Blazor component library attempting to replicate WPF layout panels like Grid, StackPanel, and ScrollViewer in Blazor.

Why?

As a programmer moving familiar with how layout works in WPF, moving to Blazor with its HTML/CSS-based layout was incredibly frustrating. Elements were constantly resizing themselves when I didn't expect them to, things would scroll as I expected, etc. I wanted something that could give me the control I had with WPF in Blazor.

Goals

  • Replicate as closely as possible the layout elements in WPF so that their use in Blazor would be intuitive.
  • Work out-of-the-box with arbitrary child elements, especially in other component libraries like MudBlazor.
  • Make it obvious why a layout is behaving the way that it is. Minimize the need to go hunting around in browser debugging tools.

Challenges

There are a couple of key challenges, beyond simply mapping WPF layout behavior to HTML/CSS, when trying to replicate WPF functionality in HTML/CSS:

  1. Blazor components are very weakly opinionated. They can contain effectively arbitrary HTML/CSS, and do not provide anything like the base functionality that FrameworkElement provides in WPF. As a result, getting a bunch of disparate components to play by similar layout rules is challenging.
  2. Blazor has no notion of attached properties like WPF does. You cannot natively attach, for example, Grid properties to an arbitrary component or piece of HTML/CSS in Blazor.

Solutions

To solve the above problems, BpfLayout adopts the following convention:

Each layout panel has two parts: the panel itself, that provides the properties that the equivalent panel in WPF provides, and a wrapper "element" component used to host an arbitrary Blazor component or HTML/CSS. This wrapper component provides the parameters that FrameworkElement provides in WPF and attempts to impart them (using some internal CSS) to the hosted Blazor component or HTML/CSS.

Examples

For example, here is how a Grid works in BpfLayout:

<Grid RootWidthCss="800px" RootHeightCss="600px">
  <GridRowDefinitions>
    <GridRowDefinition Height="100" />
    <GridRowDefinition Height="Auto" />
    <GridRowDefinition Height="*" />
  </GridRowDefinitions>
  <GridColumnDefinitions>
    <GridColumnDefinition Width ="200" />
    <GridColumnDefinition Width ="*" />
    <GridColumnDefinition Width ="2*" />
    <GridColumnDefinition Width ="Auto" />
  </GridColumnDefinitions>
</Grid>
<ChildContent>
  <GridElement Row="0" Column="0" HorizontalAlignment="HorizontalAlignment.Stretch" VerticalAlignment="VerticalAlignment.Stretch">
    <div class="some-class">
      Hello, World!
    </div>
  </GridElement>
  <GridElement Row="0" Column="1" Width="300">
    <StackPanel Orientation="Orientation.Horizontal">
      <StackPanelElement Width="150">
        <div class="some-class3">
          More Hello, World!
        </div>
      </StackPanelElement>
      <StackPanelElement Height="10" VerticalAlignment="VerticalAlignment.Bottom">
        <div class="some-class4">
          More Hello, World!
        </div>
      </StackPanelElement>
    </StackPanel>
  </GridElement>
  <GridElement Row="1" Column="2" Width="100" Height="50" HorizontalAlignment="HorizontalAlignment.Center">
    <div class="some-class2">
      Hello, World! Again!
    </div>
  </GridElement>
</ChildContent>

Here we a Grid with three rows and four columns, demonstrating the various sizing options for rows and columns. How does this differ from a WPF Grid?

  • Note the presence of the RootWidthCss and RootHeightCss properties on the Grid component. This lets the user specify a CSS-based width and height for a panel component that is not nested inside other BpfLayout panels, then turns layout over to the BPF layout system. If RootWidthCss or RootHeightCss are specified on a panel nested inside another panel, the panel's element width and height properties will override it. RootWidthCss and RootHeightCss default to 100% so that in most contexts, the user will not even need to specify root sizes, the panel will simply consume all available space and turn subsequent layout over to the BpfLayout system.
  • The Grid itself does not have the standard FrameworkElement properties for dimension or alignment. All FrameworkElement properties are present on the *Element classes, like StackPanelElement or GridElement. Because the Grid here is a root, the RootWidthCss and RootHeightCss properties effectively provide the initial size for this layout hierarchy. If we were to nest a Grid inside a Grid or a StackPanel, the FrameworkElement properties for the nested Grid would come from the GridElement or StackPanelElement that hosts it. This keeps layout consistent between internal and external components in the BpfLayout system.
  • The row and column definitions aren't direct properties of the Grid. In WPF, we would see Grid.RowDefinitions, using XAML syntax to specify a direct value for the Grid property RowDefinitions. We don't have that option in Blazor, so instead, the RenderFragment parameters GridRowDefinitions and GridColumnDefinitions are used to supply this information.
  • Child elements of the Grid are not placed directly under the Grid itself. Instead, they are placed under the ChildContent RenderFragment property. Again, this is simply how Blazor works.
  • Elements are not placed directly under ChildContent. Instead, all child elements are wrapped in an element component. For a Grid, this is GridElement. These element components supply the equivalent FrameworkElement properties from WPF and attempt to transform their child elements to honor these properties. Subsequent BpfLayout components can be nested inside these element components. In this example, the div tags take all their sizing and alignment information from the element component in which they are nested.
  • The Row and Column properites aren't attached properties as in WPF, but are rather properties of the GridElement class.
Product Compatible and additional computed target framework versions.
.NET net6.0 is compatible.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.2 2,536 6/20/2025
1.0.1 395 4/27/2025
1.0.0 247 3/28/2025
0.6.0 626 3/11/2025
0.5.0 288 3/11/2025
0.4.0 1,335 8/13/2024
0.3.0 3,900 1/5/2023
0.2.0 412 12/15/2022
0.1.0 422 12/13/2022