Using a custom ScreenType
How to create a custom screen by constructing a custom ScreenType
If you want more control over how a screen looks, or if you want to show off a combination of data for which we have no data model, you can build a truly custom screen by creating and using a custom ScreenType. This is a bit more difficult than using a built-in ScreenType, but also affords you more freedom. You must:
- Create a ProjectFile and configure it
- Make sure the DynamicWeb 10 application loads Views from your custom project
- Add content to the custom screen
Creating the custom project
First you should create an empty ASP.NET Core Web App in Visual Studio:
- Create the ProjectFile and toggle RazorSupportForMVC and GenerateEmbeddedFilesManifest
- Add a reference to the Microsoft.AspNetCore.App framework
- Add a package reference to Microsoft.Extensions.FileProvider.Embedded version 6.0.6
Your project file will look something like this:
<Project Sdk="Microsoft.NET.Sdk.Razor">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<AddRazorSupportForMvc>true</AddRazorSupportForMvc>
<GenerateEmbeddedFilesManifest>true</GenerateEmbeddedFilesManifest>
</PropertyGroup>
<ItemGroup>
<EmbeddedResource Include="wwwroot/**/*" />
</ItemGroup>
<ItemGroup>
<FrameworkReference Include="Microsoft.AspNetCore.App" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.FileProviders.Embedded" Version="6.0.6" />
</ItemGroup>
</Project>
Add a reference to IRenderBundle
Since this custom project will contain custom views and static files, we need to tell DynamicWeb to look for Views inside this dll when the application is loaded. To do this, you create a class which inherits from Dynamicweb.CoreUI.Rendering.IRenderingBundle:
public class RenderingBundle : Dynamicweb.CoreUI.Rendering.IRenderingBundle
The class doesn’t need to have any functionality, it just needs to be there.
Add content to the custom screen
The first thing you want to do is create a component – this is where you define what data is available for the screen, as well as set various properties like a header and whether to show our standard search bar, etc. A component should inherit from Dynamicweb.CoreUi.UIComponentBase, but all other content is up to you.
In this example we’re creating a component called ExpressDeliveryWidget which contains a Header and some other data related to shipping and delivery:
- ShippingLimit: Total hours given to ship a parcel
- ShippingComment: A comment field
- RemainingTime: How much time is left to fulfil this shipping request
public sealed class ExpressDeliveryWidget : UiComponentBase
{
public string Header { get; set; } = "";
public int ShippingLimit { get; set; }
public string ShippingComment { get; set; } = "";
public TimeSpan RemainingTime { get; internal set; }
}
When the component has been defined, it’s time to define how it should look. You do this by creating a matching View. To ensure that a custom view is properly loaded, it must be placed in the same hierarchy we use:
Views\Shared\Components\UiComponentWrapper
The name of a View should be the full name of the Component, so if you have a component called "CustomComponent", and it’s located in the namespace "MyCustomComponent.Components", the full name would be MyCustomComponent.Components.CustomComponent.
In this case our View looks like this:
@using Dynamicweb.CoreUI.Rendering;
@model ExpressDelivery.Components.ExpressDeliveryWidget
<div>
<script src="/ExpressDelivery/js/ExpressDeliveryWidget.js" type="module"></script>
<express-delivery-widget class="h-100" style="border: var(--dw-border);border-radius: 0.5rem;">
<div class="info-card-header">
<div class="flex-fill">
<h6 class="dw-group-header">@Model.Header</h6>
</div>
</div>
<div class="widget-content d-flex justify-content-center">
<div class="list-widget flex-nowrap flex-column w-75">
@if (Model.RemainingTime > TimeSpan.Zero)
{
<div class="flex-row m-3">
@await Component.RenderDynamicwebUiComponent(new Dynamicweb.CoreUI.Displays.Widgets.ProgressWidget((int)Math.Floor(Model.RemainingTime.TotalHours)){ProgressType = Dynamicweb.CoreUI.Displays.Widgets.ProgressWidgetType.Bar, HideSummary = true, OutOf = Model.ShippingLimit})
<span>Hours remaining until shipment: @Model.RemainingTime.ToString("d' days 'hh' hours 'mm' minutes 'ss' seconds'") </span>
</div>
}
<div class="flex-row">
<h3 style="text-align:center">@Model.ShippingComment</h3>
</div>
</div>
</div>
</express-delivery-widget>
</div>
Next steps
When you’re building custom Views you need to fetch and show data to your users, and often you also want your users to do stuff with the data - like edit and save a user, etc. To do so you can use our built-in Queries and Commands – you can see the built-in types via the API explorer.
When we don’t have standard Queries and Commands suited to your needs you can build something custom.