WPF之AvalonEdit實現MVVM雙向綁定

AvalonEdit簡介

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

通過Nuget安裝AvalonEdit,並在頁面添加控件

 <avalonEdit:TextEditor
                        xmlns:avalonEdit="//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;
            }
        }
    }
}

最後看一下實際效果吧

項目Demo//github.com/fxhui/DatabaseManagement

Tags: