WPF之AvalonEdit實現MVVM雙向繫結

傅小灰發表於2021-12-31

AvalonEdit簡介

AvalonEdit是基於WPF開發的程式碼顯示控制元件,預設支援多種不同語言的關鍵詞高亮,並且可以自定義高亮配置。所以通過AvalonEdit可以快速開發出自己想要的程式碼編輯器。

通過Nuget安裝AvalonEdit,並在頁面新增控制元件

 <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>

引數含義

  • xmlns:avalonEdit:名稱空間,也可以直接寫在呼叫該控制元件的窗體內

  • SyntaxHighlighting:設定高亮

  • ShowLineNumbers:是否顯示行號

  • LineNumbersForeground:設定編輯器行號顏色

  • ShowSpaces:是否顯示空格

  • WordWrapIndentation:換行縮排距離

  • InheritWordWrapIndentation:是否繼承上一行的換行縮排

自定義高亮配置

比如AvalonEdit預設支援的sql語法高亮不夠強大或者不符合要求,可以自定義配置註冊進行。

首先,在專案中引入一個.xshd檔案,具體規則可以參考官網介紹。這裡提供一個sql.xshd檔案,描述了對SQL語法的高亮支援。

在程式啟動的時候讀取該配置檔案,並註冊到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:這裡是將sql.xshd的生成操作設定為了嵌入的資源,也可以將其輸出到目錄再讀取內容。

如果需要在專案執行過程中,切換高亮語法支援,可以這麼做

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

看下高亮效果:

MVVM繫結AvalonEdit文字內容

當我嘗試直接將ViewModel中的字串直接繫結到Text上時,編輯器就報錯了,因為Text屬性並不是可以直接繫結的依賴屬性。

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

最後鼓搗一通後的解決方案是使用Microsoft.Xaml.Behaviors包(其實是微軟以前System.Windows.Interactivity的開源版)。

xaml程式碼

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

後端程式碼

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;
            }
        }
    }
}

最後看一下實際效果吧

專案Demohttps://github.com/fxhui/DatabaseManagement

相關文章