Skip to content

Commit 770981e

Browse files
Merge pull request #1 from sergepilipchuk/sp-add-doc-26.1.1+
Add documentation for CodeEditor control
2 parents e5a7e3d + 5b827b0 commit 770981e

5 files changed

Lines changed: 410 additions & 0 deletions

File tree

CS/CodeEditor/Docs/CodeEditor.md

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
# CodeEditor
2+
3+
A WPF code editor control with syntax highlighting and modern code display and navigation capabilities. The control embeds the Monaco Editor, the editor used in Visual Studio Code, through WebView2.
4+
5+
## Properties
6+
7+
| Name | Type | Description |
8+
| ---- | ---- | ----------- |
9+
| `Text` | `string` | Gets or sets the editor text. This is a dependency property that supports two-way binding. |
10+
| `EditorLanguage` | `string` | Gets or sets the programming language for syntax highlighting. This is a dependency property. Default: `"csharp"` |
11+
| `ReadOnly` | `bool` | Gets or sets whether the editor is read-only. This is a dependency property. Default: `false` |
12+
| `IsModified` | `bool` | Gets whether the content has been modified since the last save. This is a read-only dependency property. |
13+
| `ShowLineNumbers` | `bool` | Gets or sets whether line numbers are displayed. This is a dependency property. Default: `true` |
14+
| `LineNumbersMinChars` | `int` | Gets or sets the minimum number of characters reserved for the line-number gutter. This is a dependency property. Default: `5` |
15+
| `ShowMinimap` | `bool` | Gets or sets whether the minimap is displayed. This is a dependency property. Default: `false` |
16+
| `ShowGlyphMargin` | `bool` | Gets or sets whether the glyph margin is displayed. This is a dependency property. Default: `false` |
17+
| `EnableFolding` | `bool` | Gets or sets whether code folding is enabled. This is a dependency property. Default: `true` |
18+
| `TabSize` | `int` | Gets or sets the tab size in spaces (1-64). This is a dependency property. Default: `4` |
19+
| `InsertSpaces` | `bool` | Gets or sets whether spaces are inserted instead of tabs. This is a dependency property. Default: `true` |
20+
| `DetectIndentation` | `bool` | Gets or sets whether indentation is detected from file content. This is a dependency property. Default: `true` |
21+
| `AutoIndent` | `EditorAutoIndent` | Gets or sets the auto-indentation mode. This is a dependency property. Default: `EditorAutoIndent.Full` |
22+
| `WordWrap` | `EditorWordWrap` | Gets or sets word the wrap mode. This is a dependency property. Default: `EditorWordWrap.Off` |
23+
| `EnableScrollBeyondLastLine` | `bool` | Gets or sets whether scrolling beyond the last line is allowed. This is a dependency property. Default: `true` |
24+
| `ScrollBeyondLastColumn` | `int` | Gets or sets the number of columns the editor can scroll beyond the last character. This is a dependency property. Default: `5` |
25+
| `EnableSmoothScrolling` | `bool` | Gets or sets whether smooth scrolling is enabled. This is a dependency property. Default: `false` |
26+
| `EnableStickyScroll` | `bool` | Gets or sets whether sticky scroll is enabled. This is a dependency property. Default: `true` |
27+
| `EnableContextMenu` | `bool` | Gets or sets whether the context menu is enabled. This is a dependency property. Default: `true` |
28+
| `EnableDragAndDrop` | `bool` | Gets or sets whether drag and drop is enabled. This is a dependency property. Default: `true` |
29+
| `EnableMouseWheelZoom` | `bool` | Gets or sets whether zooming with <kbd>Ctrl</kbd>+<kbd>MouseWheel</kbd> is enabled. This is a dependency property. Default: `false` |
30+
| `EnableQuickSuggestions` | `bool` | Gets or sets whether quick suggestions are enabled. This is a dependency property. Default: `true` |
31+
| `EnableWordBasedSuggestions` | `bool` | Gets or sets whether word-based suggestions are enabled. This is a dependency property. Default: `true` |
32+
| `EnableSuggestOnTriggerCharacters` | `bool` | Gets or sets whether suggestions appear automatically when a user types trigger characters. This is a dependency property. Default: `true` |
33+
| `EnableParameterHints` | `bool` | Gets or sets whether parameter hints are displayed. This is a dependency property. Default: `true` |
34+
| `ThemeName` | `string` | Gets or sets the Monaco Editor theme name. This is a dependency property. Default: `"vs"` |
35+
| `MarkAsSavedCommand` | `ICommand` | Gets the command that resets the `IsModified` flag. |
36+
37+
## Methods
38+
39+
| Name | Description |
40+
| ---- | ----------- |
41+
| `GetAvailableLanguagesAsync(CancellationToken)` | Asynchronously retrieves a list of available programming language IDs. |
42+
| `RegisterLanguage(LanguageDescriptor)` | Registers a custom programming language with a Monarch tokenizer. |
43+
| `RegisterTheme(MonacoTheme)` | Registers a custom Monaco Editor theme. |
44+
| `MarkAsSaved()` | Resets the `IsModified` property to `false`. |
45+
| `Dispose()` | Releases WebView2 resources. |
46+
47+
## Events
48+
49+
| Name | Description |
50+
| ---- | ----------- |
51+
| `EditorInitialized` | Occurs when the Monaco Editor is fully initialized and ready for commands. |
52+
53+
## Enums
54+
55+
### EditorAutoIndent
56+
57+
| Member | Description |
58+
| ------ | ----------- |
59+
| `None` | No automatic indentation |
60+
| `Keep` | Keep current indentation |
61+
| `Brackets` | Indent based on brackets |
62+
| `Advanced` | Advanced indentation |
63+
| `Full` | Full automatic indentation (recommended) |
64+
65+
### EditorWordWrap
66+
67+
| Member | Description |
68+
| ------ | ----------- |
69+
| `Off` | No word wrapping |
70+
| `On` | Word wrapping enabled |
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# CodeEditorService
2+
3+
MVVM service that provides access to CodeEditor control functionality from ViewModels.
4+
5+
## Interface
6+
7+
```csharp
8+
public interface ICodeEditorService {
9+
void MarkAsSaved();
10+
Task<IReadOnlyCollection<string>> GetLanguagesAsync(CancellationToken cancellationToken = default);
11+
void RegisterLanguage(LanguageDescriptor language);
12+
}
13+
```
14+
15+
## Methods
16+
17+
| Name | Description |
18+
| ---- | ----------- |
19+
| `MarkAsSaved()` | Resets the `IsModified` flag of the associated `CodeEditor` to `false`. |
20+
| `GetLanguagesAsync(CancellationToken)` | Asynchronously retrieves a collection of available programming language IDs from the associated `CodeEditor`. |
21+
| `RegisterLanguage(LanguageDescriptor)` | Registers a custom programming language with a Monarch tokenizer in the associated `CodeEditor`. |

CS/CodeEditor/Docs/Overview.md

Lines changed: 287 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,287 @@
1+
## Introduction
2+
3+
This DevExpress WPF example displays code in a custom `CodeEditor` control. The control wraps the [Monaco Editor](https://microsoft.github.io/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](https://learn.microsoft.com/en-us/microsoft-edge/webview2/) to display it.
4+
5+
6+
7+
8+
9+
The `CodeEditor` implementation uses the following helper classes:
10+
11+
- `ThemeBehavior` - integrates Monaco with DevExpress themes.
12+
- `CodeEditorService` - a lightweight service for scenarios where direct interaction with the control is not sufficient.
13+
14+
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.
15+
16+
17+
## Prerequisites
18+
19+
- DevExpress WPF v26.1 (or newer compatible version)
20+
- Monaco Editor v0.55.1 (the control is built and validated against this specific release)
21+
- .NET version compatible with DevExpress WPF version you use: [WPF Controls → Prerequisites → .NET / .NET Core](https://docs.devexpress.com/WPF/8091/prerequisites#netnet-core)
22+
- Windows with [Microsoft Edge WebView2 Runtime](https://learn.microsoft.com/en-us/microsoft-edge/webview2/concepts/distribution)
23+
24+
> The `CodeEditor` project must be compiled against the same DevExpress WPF version that is used in the consuming application.
25+
26+
## Quick Start
27+
28+
### 1. Add the `CodeEditor` project
29+
30+
Add the `CodeEditor` project to your solution and reference it from your WPF application:
31+
32+
- Add existing project → `CodeEditor`
33+
- Add project reference from your WPF app
34+
- Ensure DevExpress WPF and WebView2 dependencies are resolved
35+
36+
### 2. Declare the XML namespace
37+
38+
```xml
39+
<Window
40+
x:Class="YourApp.MainWindow"
41+
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
42+
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
43+
xmlns:ce="clr-namespace:CodeEditor;assembly=CodeEditor">
44+
45+
<Grid>
46+
<ce:CodeEditor
47+
Text="{Binding Code, Mode=TwoWay}"
48+
EditorLanguage="csharp"
49+
ThemeName="vs-dark" />
50+
</Grid>
51+
52+
</Window>
53+
```
54+
55+
### 3. Create a ViewModel
56+
57+
```csharp
58+
using DevExpress.Mvvm;
59+
60+
public class MainViewModel : BindableBase
61+
{
62+
private string _code = @"using System;
63+
64+
class Program
65+
{
66+
static void Main()
67+
{
68+
Console.WriteLine(""Hello, Monaco!"");
69+
}
70+
}";
71+
72+
public string Code
73+
{
74+
get => _code;
75+
set => SetProperty(ref _code, value);
76+
}
77+
}
78+
```
79+
80+
Set the `DataContext` of the window to an instance of `MainViewModel`.
81+
82+
The editor content is automatically synchronized with the bound property.
83+
84+
> **Note:**
85+
> `CodeEditor` does not automatically track DevExpress theme changes.
86+
> To synchronize Monaco with the active DevExpress theme, use `ThemeBehavior`.
87+
88+
## Theming
89+
90+
`CodeEditor` supports built-in Monaco themes, DevExpress theme integration, and custom theme registration.
91+
92+
### Built-in Monaco Themes
93+
94+
You can use standard Monaco themes:
95+
96+
```csharp
97+
editor.ThemeName = "vs";
98+
editor.ThemeName = "vs-dark";
99+
editor.ThemeName = "hc-black";
100+
```
101+
102+
103+
104+
### DevExpress Theme Integration
105+
106+
107+
108+
To synchronize a Monaco Editor with the active DevExpress theme, attach a `ThemeBehavior`:
109+
110+
```xml
111+
xmlns:ce="clr-namespace:CodeEditor;assembly=CodeEditor"
112+
xmlns:cet="clr-namespace:CodeEditor.Theming;assembly=CodeEditor"
113+
xmlns:dxmvvm="http://schemas.devexpress.com/winfx/2008/xaml/mvvm"
114+
115+
...
116+
117+
<ce:CodeEditor
118+
Text="{Binding Code}"
119+
EditorLanguage="csharp">
120+
121+
<dxmvvm:Interaction.Behaviors>
122+
<cet:ThemeBehavior ApplyDevExpressColors="True" />
123+
</dxmvvm:Interaction.Behaviors>
124+
125+
</ce:CodeEditor>
126+
```
127+
128+
`ThemeBehavior` synchronizes DevExpress themes and Monaco Editor appearance in the following manner:
129+
130+
- Detects the current DevExpress theme at startup and each time the theme changes
131+
- Resolves Light / Dark / High Contrast base
132+
- Registers and applies a corresponding Monaco theme
133+
- Optionally maps DevExpress palette colors to Monaco color keys via the `ApplyDevExpressColors` property
134+
135+
136+
137+
### Custom Themes
138+
139+
You can register a custom Monaco theme programmatically:
140+
141+
```csharp
142+
var theme = new MonacoTheme
143+
{
144+
Name = "my-theme",
145+
Base = MonacoThemeBase.Dark,
146+
Colors = new Dictionary<string, Color>
147+
{
148+
["editor.background"] = Color.FromRgb(30, 30, 30),
149+
["editor.foreground"] = Color.FromRgb(220, 220, 220)
150+
}
151+
};
152+
153+
editor.RegisterTheme(theme);
154+
editor.ThemeName = "my-theme";
155+
```
156+
157+
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](https://code.visualstudio.com/api/references/theme-color).
158+
159+
### Rules
160+
161+
In addition to UI colors, Monaco themes support token-level styling via `Rules`.
162+
163+
Rules define how the editor renders specific token types such as `keyword`, `comment`, `string`, and others.
164+
165+
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.
166+
167+
```csharp
168+
var theme = new MonacoTheme
169+
{
170+
Name = "my-theme",
171+
Base = MonacoThemeBase.Dark,
172+
Rules = new[]
173+
{
174+
new MonacoThemeRule
175+
{
176+
Token = "keyword",
177+
Foreground = Color.FromRgb(86, 156, 214),
178+
FontStyle = MonacoFontStyle.Bold
179+
},
180+
new MonacoThemeRule
181+
{
182+
Token = "comment",
183+
Foreground = Color.FromRgb(106, 153, 85),
184+
FontStyle = MonacoFontStyle.Italic
185+
}
186+
}
187+
};
188+
```
189+
190+
`Rules` is an init-only property and must be provided during theme initialization.
191+
192+
If you use `ThemeBehavior`, token styling can also be supplied through its `Rules` property, and it allows rule customization alongside DevExpress theme integration.
193+
194+
## Languages
195+
196+
`CodeEditor` supports both built-in Monaco languages and custom language registration.
197+
198+
### Built-in Languages
199+
200+
To use a built-in Monaco language, specify the `EditorLanguage` property:
201+
202+
```csharp
203+
editor.EditorLanguage = "csharp";
204+
editor.EditorLanguage = "javascript";
205+
editor.EditorLanguage = "json";
206+
```
207+
208+
The value must match a language ID supported by Monaco Editor.
209+
210+
### Custom Languages
211+
212+
You can register custom languages using `LanguageDescriptor`:
213+
214+
```csharp
215+
var language = new LanguageDescriptor
216+
{
217+
Id = "mylang",
218+
219+
Monarch = @"{
220+
tokenizer: {
221+
root: [
222+
[/\b(if|else|while)\b/, 'keyword'],
223+
[/\/\/.*$/, 'comment'],
224+
[/"".*?""/, 'string'],
225+
[/\d+/, 'number']
226+
]
227+
}
228+
}",
229+
230+
Configuration = @"{
231+
comments: {
232+
lineComment: '//'
233+
},
234+
brackets: [
235+
['{', '}'],
236+
['[', ']'],
237+
['(', ')']
238+
]
239+
}"
240+
};
241+
242+
editor.RegisterLanguage(language);
243+
editor.EditorLanguage = "mylang";
244+
```
245+
246+
### Monarch Definition
247+
248+
The `Monarch` property defines syntax highlighting rules.
249+
250+
The property must contain a valid Monaco Monarch tokenizer definition specified as a JavaScript object literal.
251+
252+
All standard Monarch features are supported:
253+
254+
- Multiple states
255+
- Nested states
256+
- Regular expressions
257+
- Rule objects
258+
- Includes and state transitions
259+
260+
Refer to the following help topic for additional information: [Monarch Documentation](https://microsoft.github.io/monaco-editor/monarch.html)
261+
262+
### Language Configuration
263+
264+
The optional `Configuration` property defines editor behavior attributes such as:
265+
266+
- Line and block comments
267+
- Brackets
268+
- Auto-closing pairs
269+
- Surrounding pairs
270+
271+
The configuration must also be provided as a JavaScript object literal.
272+
273+
For additional information, refer to the following help topic: [Language Configuration Guide](https://code.visualstudio.com/api/language-extensions/language-configuration-guide)
274+
275+
## See also
276+
277+
### API Reference
278+
279+
- [CodeEditor API Reference](CodeEditor.md)
280+
- [CodeEditorService API Reference](CodeEditorService.md)
281+
- [ThemeBehavior API Reference](ThemeBehavior.md)
282+
283+
### Monaco Resources
284+
285+
- [Monaco Editor](https://microsoft.github.io/monaco-editor/)
286+
- [Monarch Documentation](https://microsoft.github.io/monaco-editor/monarch.html)
287+
- [Monaco Playground – Custom Languages Example](https://microsoft.github.io/monaco-editor/playground.html?source=v0.55.1#example-extending-language-services-custom-languages)

0 commit comments

Comments
 (0)