AvalonEdit of WPF implements MVVM bidirectional binding

Posted by BrianPeiris on Wed, 05 Jan 2022 12:42:42 +0100

Introduction to AvalonEdit

AvalonEdit is a code display control developed based on WPF. By default, it supports keyword highlighting in many different languages, and you can customize the highlighting configuration. Therefore, you can quickly develop the code editor you want through AvalonEdit.

Install via Nuget AvalonEdit And add controls to the page

 <avalonEdit:TextEditor
                        xmlns:avalonEdit="http://icsharpcode.net/sharpdevelop/avalonedit"
                        Name="TextEditor"
                        SyntaxHighlighting="C#"
                        FontFamily="Consolas"
                        FontSize="14"
                        WordWrap ="True"
                        LineNumbersForeground="#FF2B91AF"
                        ShowLineNumbers="True">
     <avalonEdit:TextEditor.Options>
         <avalonEdit:TextEditorOptions ShowSpaces="True" WordWrapIndentation="4" InheritWordWrapIndentation="true">
             <avalonEdit:TextEditorOptions.ColumnRulerPosition>
                 <system:Int32>10</system:Int32>
             </avalonEdit:TextEditorOptions.ColumnRulerPosition>
         </avalonEdit:TextEditorOptions>
     </avalonEdit:TextEditor.Options>
</avalonEdit:TextEditor>

Parameter meaning

  • xmlns:avalonEdit: namespace. It can also be written directly in the form calling the control

  • SyntaxHighlighting: set highlighting

  • ShowLineNumbers: show line numbers

  • LineNumbersForeground: sets the editor line number color

  • ShowSpaces: Show spaces

  • WordWrap indentation: newline indentation distance

  • Inherit WordWrap indentation: whether to inherit the newline indentation of the previous line

Custom highlight configuration

For example, the sql syntax supported by AvalonEdit by default is not strong enough or does not meet the requirements. You can customize the configuration and register.

First, introduce a in the project xshd file, specific rules can refer to Official website Introduction. Here is an SQL xshd file , describes highlighting support for SQL syntax.

Read the configuration file when the program starts and register it in AvalonEdit.

using (var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(Assembly.GetExecutingAssembly().GetName().Name + ".sql.xshd"))
{
    using (var reader = new System.Xml.XmlTextReader(stream))
    {
        var sqlDefinition = HighlightingLoader.Load(reader, HighlightingManager.Instance);
        HighlightingManager.Instance.RegisterHighlighting("SQL", new string[] { ".sql" }, sqlDefinition);
	}
}

ps: here is the SQL The generation operation of xshd is set as an embedded resource. You can also output it to the directory and then read the content.

If you need to switch highlight syntax support during project operation, you can do so

textEditor.SyntaxHighlighting = HighlightingManager.Instance.GetDefinition("SQL");

See the highlight effect:

MVVM binding AvalonEdit text content

When I try to bind the string in the ViewModel directly to Text, the editor will report an error because the Text property is not a dependent property that can be bound directly.

Object of type 'System.Windows.Data.Binding' cannot be converted to type 'System.String'.

The final solution is to use Microsoft Xaml. Behaviors package (in fact, it is the open source version of system. Windows. Interaction before Microsoft).

xaml code

<avalonEdit:TextEditor Name="TextEditor">
    <i:Interaction.Behaviors>
        <local:AvalonEditBehaviour InputText="{Binding InputString}"/>
    </i:Interaction.Behaviors>
</avalonEdit:TextEditor>

Back end code

public sealed class AvalonEditBehaviour : Behavior<TextEditor>
{
    public static readonly DependencyProperty InputTextProperty =
        DependencyProperty.Register("InputText", typeof(string), typeof(AvalonEditBehaviour),
        new FrameworkPropertyMetadata(default(string), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, null));

    public string InputText
    {
        get { return (string)GetValue(InputTextProperty); }
        set { SetValue(InputTextProperty, value); }
    }

    protected override void OnAttached()
    {
        base.OnAttached();
        if (AssociatedObject != null)
        {
            AssociatedObject.TextChanged += AssociatedObjectOnTextChanged;
        }
    }

    protected override void OnDetaching()
    {
        base.OnDetaching();
        if (AssociatedObject != null)
        {
            AssociatedObject.TextChanged -= AssociatedObjectOnTextChanged;
        }
    }

    private void AssociatedObjectOnTextChanged(object sender, EventArgs eventArgs)
    {
        var textEditor = sender as TextEditor;
        if (textEditor != null)
        {
            if (textEditor.Document != null)
            {
                InputText = textEditor.Document.Text;
            }
        }
    }
}

Finally, let's take a look at the actual effect

Project Demo: https://github.com/fxhui/DatabaseManagement

Topics: WPF