Netrix editor is primarily an HTML editor. Beside the basic editing function it offers several advanced editing and helper functions. You can create simple editors, advanced text processing applications, or interactive displays. The internal format is HTML. It is extensible with private XML elements.
The basic text editing function are such as "Bold", "Italic", font family and color. These functions work in either direct or toggle mode. Binary functions, such as "Bold", are toggle functions. Applying the same command to an already formatted text returns to the other state.
Other basic functions, such as "Copy", "Paste", and "Cut" don't toggle. Simple buttons will work well. However, you have to take care the current functions 'availability'. For each method call Netrix provides the corresponding "Can" method. Hence, for "Copy" is a method "CanCopy".
One of the challenges you face as a developer is to synchronize the toolbars or ribbons with the current state at the cursor position. In this demo application we use a ribbon with either ToggleButton or regular Button element.
One crucial question is how to synchronize the toolbar or ribbon an when it's safe to issue the commands. First of all, Netrix works asynchronous during the load phase. Each loading process, invoked by any of the "Load" methods, is handled asyncrhonously internally. Any operation agaínst the control must wait for the "ReadyStateComplete" event. Once it is fired, the IsReady property is set to true.
Another crucial event is "UpdateUI". Any user operation, such as Key or Mouse, can change the caret's position and hence change the appearance of tool buttons. It's recommended to update all tools at once in this event only.
void _fontControl_ExecuteEvent(object sender, ExecuteEventArgs e) { // Toggle Buttons need to be wrapped if (CanToggle(_fontControl.Bold, HtmlCommand.Bold)) { EditorDocument.HtmlEditor.TextFormatting.ToggleBold(); return; }
The editor just need a call to ToggleBold. This method can be found in the HtmlTextFormatting class, exposed by the TextFormatting property.
The CanToggle method is a private helper method that takes the command invoked by the font control ( _fontControl.Bold) and the corresponding command from HtmlCommand enum. This enum contains an entry for all formatting and several element functions. It is used to ask Netrix whether a specific command is currently available.
bool CanToggle(RibbonLib.Interop.FontProperties prop, HtmlCommand check) { return (prop == RibbonLib.Interop.FontProperties.Set && EditorDocument.HtmlEditor.CommandStatus(check) != HtmlCommandInfo.Checked) || (_fontControl.Bold == RibbonLib.Interop.FontProperties.NotSet && EditorDocument.HtmlEditor.CommandStatus(check) != HtmlCommandInfo.Enabled); }
Netrix provides the CommandStatus method to check for a command's availability. A command can have several states, such as "Checked", "Enabled", or "Both". "Checked" means that the command is currently applied. In case of Bold this means the caret is with a text that is formatted bold (between <b> tags, actually). If it is possible to invoke the command, the method return "Enabled". Ususally, especially for toggle commands, the method returns "Both" (is active and can be invoked again).
In the example code the state of the ribbon's font control is synchronized with the Netrix control's state.
Using this, the ribbon handled the Netrix control's Bold feature. There is just one fuunction left. The toggle control on the ribbon's font control must stay in sync even if the user just moves the caret (not invoking any specific command). Here we use the UpdateUI event. In the example the is routed through the handler class, because the Netrix control resides in a separate window (to make it dockable). The handler looks like this:
_fontControl.Bold = CheckState(HtmlCommand.Bold);
The CheckState method contains the required logic:
RibbonLib.Interop.FontProperties CheckState(HtmlCommand cmd) { if (EditorDocument.HtmlEditor.CommandStatus(cmd) == HtmlCommandInfo.Checked || EditorDocument.HtmlEditor.CommandStatus(cmd) == HtmlCommandInfo.Both) { return RibbonLib.Interop.FontProperties.Set; } else { _fontControl.Bold = RibbonLib.Interop.FontProperties.NotSet; } if (EditorDocument.HtmlEditor.CommandStatus(cmd) != HtmlCommandInfo.Enabled && EditorDocument.HtmlEditor.CommandStatus(cmd) != HtmlCommandInfo.Both) { return RibbonLib.Interop.FontProperties.NotAvailable; } return RibbonLib.Interop.FontProperties.NotSet; }
Again the HtmlCommand enum is used to check the current state. In case the state is "Checked" or "Both" the toggle tool is set. In case it is not enabled the tool is disabled. Otherwise it's avaiable and not set. Some functions do not toggle. In those cases you can simply read the corresponding properties and set your tools accordingly:
_fontControl.Family = EditorDocument.HtmlEditor.TextFormatting.FontName; _fontControl.ForegroundColor = EditorDocument.HtmlEditor.TextFormatting.ForeColor; _fontControl.BackgroundColor = EditorDocument.HtmlEditor.TextFormatting.BackColor;
Internally all HTLM colors are properly translated to System.Drawing.Color objects.
Typical operations regarding paragraphs are alignment, adding ordered or unordered lists, or indent blocks. All these commands are applied as simple method calls. Again, it's recommended to check for the functions availability through the UpdateUI event as shown before. The example shows how to left align a paragraph:
void _buttonAlignLeft_ExecuteEvent(object sender, ExecuteEventArgs e) { EditorDocument.HtmlEditor.TextFormatting.SetAlignment(Alignment.Left); }
All method calls in the formatting classes uses the term "align". There is, however, a conflict between the alignment capabilites of styles (CSS), within block elements, such as table cells, and regular paragraphs. Hence the HtmlCommand enum uses for paragraphs the term "justify". Enabling of disabling the tools checks the CommandStatus method using the JustifyXXX entries of the enum,
Netrix comes with full support for search and replace opertions. Search is internally exposed through the "Find" method. Search and replace both have few options:
The search and replace algorithm takes care of HTML formatting automatically. However, if a word has been found with formatting within the word itself, and the whole word gets replaces, the formatting gets lost. The replace method takes pure text only.
In the example the NextWord event is used to sync a dialog with the current search (or replace) process:
private void HandleSearchAndReplace(bool replace) { SearchReplaceDialog.NextWord += new EventHandler(SearchReplaceDialog_NextWord); SearchReplaceDialog.FormClosed += new System.Windows.Forms.FormClosedEventHandler(SearchReplaceDialog_FormClosed); SearchReplaceDialog.Show(this); } void SearchReplaceDialog_FormClosed(object sender, System.Windows.Forms.FormClosedEventArgs e) { if (SearchReplaceDialog.DialogResult == System.Windows.Forms.DialogResult.OK) { // last search before close SearchReplaceDialog_NextWord(sender, EventArgs.Empty); } SearchReplaceDialog = null; } void SearchReplaceDialog_NextWord(object sender, EventArgs e) { if (SearchReplaceDialog.UseReplace) { EditorDocument.HtmlEditor.ReplaceNext( SearchReplaceDialog.SearchFor, SearchReplaceDialog.ReplaceWith, SearchReplaceDialog.CaseSensitive, SearchReplaceDialog.WholeWord, SearchReplaceDialog.SearchUp); } else { EditorDocument.HtmlEditor.Find( SearchReplaceDialog.SearchFor, SearchReplaceDialog.CaseSensitive, SearchReplaceDialog.WholeWord, SearchReplaceDialog.SearchUp); } }
The several options provided to the editors "Find" as well as "ReplaceNext" methods are pulled from controls the dialog provides.
The search method does not handle anything. In case a word has been found the word is highlighted. Any commands, such as Delete, Copy, or formatting, applies against a highlighted fragment, if any.
The common editing functions work like any other functions. The are bound to hot keys internally. Hot keys can be suppressed and replaced by private once if required.
Undo and Redo is fully implemented. Moreover, you can:
Usually it's not necessary to implement anything using Undo. The call looks simple:
htmlEditor1.Undo();
Note: In the example application this is wrapped into a method that applies the command to either the Netrix editor or the code editor.