Skip to content

Latest commit

 

History

History
287 lines (199 loc) · 8.58 KB

File metadata and controls

287 lines (199 loc) · 8.58 KB

Introduction

This DevExpress WPF example displays code in a custom CodeEditor control. The control wraps the Monaco Editor, the editor used in Visual Studio Code. Monaco Editor supports modern code editing features such as syntax highlighting, region folding, a minimap, theming, and custom language support. Since Monaco Editor is a web control, the WPF wrapper uses Microsoft WebView2 to display it.

The CodeEditor implementation uses the following helper classes:

  • ThemeBehavior - integrates Monaco with DevExpress themes.
  • CodeEditorService - a lightweight service for scenarios where direct interaction with the control is not sufficient.

The control is designed as a state-driven wrapper: WPF owns the editor state through dependency properties, and Monaco Editor reflects that state and propagates changes back to WPF in an MVVM-friendly way.

Prerequisites

The CodeEditor project must be compiled against the same DevExpress WPF version that is used in the consuming application.

Quick Start

1. Add the CodeEditor project

Add the CodeEditor project to your solution and reference it from your WPF application:

  • Add existing project → CodeEditor
  • Add project reference from your WPF app
  • Ensure DevExpress WPF and WebView2 dependencies are resolved

2. Declare the XML namespace

<Window
    x:Class="YourApp.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:ce="clr-namespace:CodeEditor;assembly=CodeEditor">

    <Grid>
        <ce:CodeEditor
            Text="{Binding Code, Mode=TwoWay}"
            EditorLanguage="csharp"
            ThemeName="vs-dark" />
    </Grid>

</Window>

3. Create a ViewModel

using DevExpress.Mvvm;

public class MainViewModel : BindableBase
{
    private string _code = @"using System;

class Program
{
    static void Main()
    {
        Console.WriteLine(""Hello, Monaco!"");
    }
}";

    public string Code
    {
        get => _code;
        set => SetProperty(ref _code, value);
    }
}

Set the DataContext of the window to an instance of MainViewModel.

The editor content is automatically synchronized with the bound property.

Note:
CodeEditor does not automatically track DevExpress theme changes.
To synchronize Monaco with the active DevExpress theme, use ThemeBehavior.

Theming

CodeEditor supports built-in Monaco themes, DevExpress theme integration, and custom theme registration.

Built-in Monaco Themes

You can use standard Monaco themes:

editor.ThemeName = "vs";
editor.ThemeName = "vs-dark";
editor.ThemeName = "hc-black";

DevExpress Theme Integration

To synchronize a Monaco Editor with the active DevExpress theme, attach a ThemeBehavior:

xmlns:ce="clr-namespace:CodeEditor;assembly=CodeEditor"
xmlns:cet="clr-namespace:CodeEditor.Theming;assembly=CodeEditor"
xmlns:dxmvvm="http://schemas.devexpress.com/winfx/2008/xaml/mvvm"

...

<ce:CodeEditor
    Text="{Binding Code}"
    EditorLanguage="csharp">

    <dxmvvm:Interaction.Behaviors>
        <cet:ThemeBehavior ApplyDevExpressColors="True" />
    </dxmvvm:Interaction.Behaviors>

</ce:CodeEditor>

ThemeBehavior synchronizes DevExpress themes and Monaco Editor appearance in the following manner:

  • Detects the current DevExpress theme at startup and each time the theme changes
  • Resolves Light / Dark / High Contrast base
  • Registers and applies a corresponding Monaco theme
  • Optionally maps DevExpress palette colors to Monaco color keys via the ApplyDevExpressColors property

Custom Themes

You can register a custom Monaco theme programmatically:

var theme = new MonacoTheme
{
    Name = "my-theme",
    Base = MonacoThemeBase.Dark,
    Colors = new Dictionary<string, Color>
    {
        ["editor.background"] = Color.FromRgb(30, 30, 30),
        ["editor.foreground"] = Color.FromRgb(220, 220, 220)
    }
};

editor.RegisterTheme(theme);
editor.ThemeName = "my-theme";

For a complete list of commonly used Monaco theme color keys, see the official VS Code theme color reference (Monaco uses the same keys): Theme Color.

Rules

In addition to UI colors, Monaco themes support token-level styling via Rules.

Rules define how the editor renders specific token types such as keyword, comment, string, and others.

You can use Rules to override the appearance of existing token types or to define styling for custom tokens introduced by a custom language definition.

var theme = new MonacoTheme
{
    Name = "my-theme",
    Base = MonacoThemeBase.Dark,
    Rules = new[]
    {
        new MonacoThemeRule
        {
            Token = "keyword",
            Foreground = Color.FromRgb(86, 156, 214),
            FontStyle = MonacoFontStyle.Bold
        },
        new MonacoThemeRule
        {
            Token = "comment",
            Foreground = Color.FromRgb(106, 153, 85),
            FontStyle = MonacoFontStyle.Italic
        }
    }
};

Rules is an init-only property and must be provided during theme initialization.

If you use ThemeBehavior, token styling can also be supplied through its Rules property, and it allows rule customization alongside DevExpress theme integration.

Languages

CodeEditor supports both built-in Monaco languages and custom language registration.

Built-in Languages

To use a built-in Monaco language, specify the EditorLanguage property:

editor.EditorLanguage = "csharp";
editor.EditorLanguage = "javascript";
editor.EditorLanguage = "json";

The value must match a language ID supported by Monaco Editor.

Custom Languages

You can register custom languages using LanguageDescriptor:

var language = new LanguageDescriptor
{
    Id = "mylang",

    Monarch = @"{
        tokenizer: {
            root: [
                [/\b(if|else|while)\b/, 'keyword'],
                [/\/\/.*$/, 'comment'],
                [/"".*?""/, 'string'],
                [/\d+/, 'number']
            ]
        }
    }",

    Configuration = @"{
        comments: {
            lineComment: '//'
        },
        brackets: [
            ['{', '}'],
            ['[', ']'],
            ['(', ')']
        ]
    }"
};

editor.RegisterLanguage(language);
editor.EditorLanguage = "mylang";

Monarch Definition

The Monarch property defines syntax highlighting rules.

The property must contain a valid Monaco Monarch tokenizer definition specified as a JavaScript object literal.

All standard Monarch features are supported:

  • Multiple states
  • Nested states
  • Regular expressions
  • Rule objects
  • Includes and state transitions

Refer to the following help topic for additional information: Monarch Documentation

Language Configuration

The optional Configuration property defines editor behavior attributes such as:

  • Line and block comments
  • Brackets
  • Auto-closing pairs
  • Surrounding pairs

The configuration must also be provided as a JavaScript object literal.

For additional information, refer to the following help topic: Language Configuration Guide

See also

API Reference

Monaco Resources