wpf 使 AvalonEdit MVVM 兼容

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/12344367/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-13 05:17:17  来源:igfitidea点击:

Making AvalonEdit MVVM compatible

c#.netwpfmvvmavalonedit

提问by l46kok

I'm trying to make Avalon MVVM compatible in my WPF application. From googling, I found out that AvalonEdit is not MVVM friendlyand I need to export the state of AvalonEdit by making a class derived from TextEditor then adding the necessary dependency properties. I'm afraid that I'm quite lost in Herr Grunwald's answer here:

我正在尝试使 Avalon MVVM 在我的 WPF 应用程序中兼容。通过谷歌搜索,我发现AvalonEdit 不是 MVVM 友好的,我需要通过创建一个从 TextEditor 派生的类然后添加必要的依赖属性来导出 AvalonEdit 的状态。我怕我在格伦沃尔德先生的回答完全迷失在这里

If you really need to export the state of the editor using MVVM, then I suggest you create a class deriving from TextEditor which adds the necessary dependency properties and synchronizes them with the actual properties in AvalonEdit.

如果你真的需要使用 MVVM 导出编辑器的状态,那么我建议你创建一个派生自 TextEditor 的类,它添加必要的依赖属性并将它们与 AvalonEdit 中的实际属性同步。

Does anyone have an example or have good suggestions on how to achieve this?

有没有人有一个例子或有关于如何实现这一目标的好建议?

回答by McGarnagle

Herr Grunwald is talking about wrapping the TextEditorproperties with dependency properties, so that you can bind to them. The basic idea is like this (using the CaretOffsetproperty for example):

Grunwald 先生正在谈论TextEditor依赖属性包装属性,以便您可以绑定到它们。基本思想是这样的(例如使用CaretOffset属性):

Modified TextEditor class

修改后的 TextEditor 类

public class MvvmTextEditor : TextEditor, INotifyPropertyChanged
{
    public static DependencyProperty CaretOffsetProperty = 
        DependencyProperty.Register("CaretOffset", typeof(int), typeof(MvvmTextEditor),
        // binding changed callback: set value of underlying property
        new PropertyMetadata((obj, args) =>
        {
            MvvmTextEditor target = (MvvmTextEditor)obj;
            target.CaretOffset = (int)args.NewValue;
        })
    );

    public new string Text
    {
        get { return base.Text; }
        set { base.Text = value; }
    }

    public new int CaretOffset
    {
        get { return base.CaretOffset; }
        set { base.CaretOffset = value; }
    }

    public int Length { get { return base.Text.Length; } }

    protected override void OnTextChanged(EventArgs e)
    {
        RaisePropertyChanged("Length");
        base.OnTextChanged(e);
    }

    public event PropertyChangedEventHandler PropertyChanged;
    public void RaisePropertyChanged(string info)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(info));
        }
    }
}

Now that the CaretOffsethas been wrapped in a DependencyProperty, you can bind it to a property, say Offsetin your View Model. For illustration, bind a Slidercontrol's value to the same View Model property Offset, and see that when you move the Slider, the Avalon editor's cursor position gets updated:

现在CaretOffset已经被包裹在一个 DependencyProperty 中,你可以将它绑定到一个属性,比如Offset在你的视图模型中。例如,将Slider控件的值绑定到相同的 View Model 属性Offset,并看到当您移动 Slider 时,Avalon 编辑器的光标位置会更新:

Test XAML

测试 XAML

<Window x:Class="AvalonDemo.TestWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:avalonEdit="http://icsharpcode.net/sharpdevelop/avalonedit"
    xmlns:avalonExt="clr-namespace:WpfTest.AvalonExt"
    DataContext="{Binding RelativeSource={RelativeSource Self},Path=ViewModel}">
  <StackPanel>
    <avalonExt:MvvmTextEditor Text="Hello World" CaretOffset="{Binding Offset}" x:Name="editor" />
    <Slider Minimum="0" Maximum="{Binding ElementName=editor,Path=Length,Mode=OneWay}" 
        Value="{Binding Offset}" />
    <TextBlock Text="{Binding Path=Offset,StringFormat='Caret Position is {0}'}" />
    <TextBlock Text="{Binding Path=Length,ElementName=editor,StringFormat='Length is {0}'}" />
  </StackPanel>
</Window>

Test Code-behind

测试代码隐藏

namespace AvalonDemo
{
    public partial class TestWindow : Window
    {
        public AvalonTestModel ViewModel { get; set; }

        public TestWindow()
        {
            ViewModel = new AvalonTestModel();
            InitializeComponent();
        }
    }
}

Test View Model

测试视图模型

public class AvalonTestModel : INotifyPropertyChanged
{
    private int _offset;

    public int Offset 
    { 
        get { return _offset; } 
        set 
        { 
            _offset = value; 
            RaisePropertyChanged("Offset"); 
        } 
    }

    public event PropertyChangedEventHandler PropertyChanged;
    public void RaisePropertyChanged(string info)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(info));
        }
    }
}

回答by Frederic

You can use the Document property from the editor and bind it to a property of your ViewModel.

您可以使用编辑器中的 Document 属性并将其绑定到您的 ViewModel 的属性。

Here is the code for the view :

这是视图的代码:

<Window x:Class="AvalonEditIntegration.UI.View"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:AvalonEdit="clr-namespace:ICSharpCode.AvalonEdit;assembly=ICSharpCode.AvalonEdit"
        Title="Window1"
        WindowStartupLocation="CenterScreen"
        Width="500"
        Height="500">
    <DockPanel>
        <Button Content="Show code"
                Command="{Binding ShowCode}"
                Height="50"
                DockPanel.Dock="Bottom" />
        <AvalonEdit:TextEditor ShowLineNumbers="True"
                               Document="{Binding Path=Document}"
                               FontFamily="Consolas"
                               FontSize="10pt" />
    </DockPanel>
</Window>

And the code for the ViewModel :

以及 ViewModel 的代码:

namespace AvalonEditIntegration.UI
{
    using System.Windows;
    using System.Windows.Input;
    using ICSharpCode.AvalonEdit.Document;

    public class ViewModel
    {
        public ViewModel()
        {
            ShowCode = new DelegatingCommand(Show);
            Document = new TextDocument();
        }

        public ICommand ShowCode { get; private set; }
        public TextDocument Document { get; set; }

        private void Show()
        {
            MessageBox.Show(Document.Text);
        }
    }
}

source : blog nawrem.reverse

来源:博客nawrem.reverse

回答by Luis Ferreira

Not sure if this fits your needs, but I found a way to access all the "important" components of the TextEditoron a ViewModelwhile having it displayed on a View, still exploring the possibilities though.

不确定这是否符合您的需求,但我找到了一种方法来访问ViewModelTextEditor 的所有“重要”组件,同时将其显示在视图上,但仍在探索可能性。

What I did was instead of instantiating the TextEditoron the View and then binding the many properties that I will need, I created a Content Control and bound its content to a TextEditorinstance that I create in the ViewModel.

我所做的不是在 View 上实例化TextEditor然后绑定我需要的许多属性,而是创建了一个 Content Control 并将其内容绑定到我在ViewModel 中创建的TextEditor实例。

View:

看法:

<ContentControl Content="{Binding AvalonEditor}" />

ViewModel:

视图模型:

using ICSharpCode.AvalonEdit;
using ICSharpCode.AvalonEdit.Document;
using ICSharpCode.AvalonEdit.Highlighting;
// ...
private TextEditor m_AvalonEditor = new TextEditor();
public TextEditor AvalonEditor => m_AvalonEditor;

Test code in the ViewModel (works!)

ViewModel 中的测试代码(有效!)

// tests with the main component
m_AvalonEditor.SyntaxHighlighting = HighlightingManager.Instance.GetDefinition("XML");
m_AvalonEditor.ShowLineNumbers = true;
m_AvalonEditor.Load(@"C:\testfile.xml");

// test with Options
m_AvalonEditor.Options.HighlightCurrentLine = true;

// test with Text Area
m_AvalonEditor.TextArea.Opacity = 0.5;

// test with Document
m_AvalonEditor.Document.Text += "bla";

At the moment I am still deciding exactly what I need my application to configure/do with the textEditor but from these tests it seems I can change any property from it while keeping a MVVM approach.

目前,我仍在决定我需要我的应用程序使用 textEditor 配置/执行的确切内容,但从这些测试来看,我似乎可以在保留 MVVM 方法的同时更改它的任何属性。