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.
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:
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 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:
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.
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.
The latest Wisej.NET 3.2 is available on NuGet. To use the build, make sure to check the Prereleases option in the NuGet Package Manager.
The Visual Studio 2019 and 2022 extension packages are linked below:
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.
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.
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.
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.
Using this extension requires a Developer Express license.
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
.
improvements across the board.
Consolidated bug fixes and enhancements to all controls.
DataGridView memory footprint for large data sets has been reduced.
Expanded Binding and MVVM ICommand support to ToolBarButtons and MenuItems.
New BindableComponent base class to enable data binding on components.
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.
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.
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:
Required: Validates the presence of any value.
Email: Validates an email entry.
Decimal: Validates a decimal value.
Integer: Validates an integer value.
Currency: Validates a currency value.
Telephone: Validates a phone number using a validation mask.
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.
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 InvalidMessage property of the control being validated, and set the e.Cancel property of the event to true.
👉 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.
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:
Validation messages are typically displayed in an error tooltip by setting the InvalidMessage property of an editor control. A second way to show validation errors, is to use the ErrorProvider extender. However, an application would have to explicitly set the error message in code when processing the Validating event.
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.
Using the ErrorProvider extender.
On any custom implementation of the new IErrorProvider interface: i.e, a MessageBox, a slide-in Panel, any logger, etc.
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.)
IErrorProvider. Exposes the same two public methods implemented by the existing ErrorProvider 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.
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.
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.
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.
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:
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:
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.
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.
The ViewBuilder will search for the component or control name at all levels and assign the reference to the property.
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.
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 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.
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.
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!
The ViewBuilder class exposes two assignable methods: ResolveReference and ResolveEventHandler:
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.
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.
On a separate Label (which now implements the IErrorProvider interface). The Label is automatically show or hidden.
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.
Field | Description | Example |
---|
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.
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} |
An event handler for the event.
An event handler for the event.
One of the fields.
One of the fields.