Rendre la compatibilité MVVM D'AvalonEdit compatible

j'essaie de rendre le MVVM D'Avalon compatible avec mon application WPF. De googling, j'ai découvert que AvalonEdit N'est pas MVVM amical et je dois exporter l'état D'AvalonEdit en faisant une classe dérivée de TextEditor puis en ajoutant les propriétés de dépendance nécessaires. Je crains d'être perdu dans la réponse de M. Grunwald ici :

Si vous avez vraiment besoin d'exporter l'état de l'éditeur à l'aide MVVM, alors je vous suggère de créer une classe dérivant de TextEditor qui ajoute les propriétés de dépendance nécessaires et les synchronise avec les propriétés réelles dans AvalonEdit.

Quelqu'un a-t-il un exemple ou de bonnes suggestions pour y parvenir?

15
demandé sur McGarnagle 2012-09-10 05:21:00

3 réponses

M. Grunwald parle d'envelopper les propriétés TextEditor avec propriétés de dépendance , de sorte que vous puissiez vous y lier. L'idée de base est comme ceci (en utilisant la CaretOffset propriété par exemple):

Modifié TextEditor classe

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

maintenant que le CaretOffset a été enveloppé dans une propriété de dépendance, vous pouvez le lier à une propriété, dites Offset dans votre Modèle De Vue. Pour l'illustration, liez la valeur d'un contrôle Slider à la propriété Offset , et voyez que lorsque vous déplacez le curseur, la position du curseur de L'éditeur Avalon est mise à jour:

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

code D'essai-derrière

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

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

Le Test De La Vue Modèle

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));
        }
    }
}
24
répondu McGarnagle 2012-09-20 05:55:47

vous pouvez utiliser la propriété Document de l'éditeur et la lier à une propriété de votre ViewModel.

voici le code pour la vue :

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

et le code pour le modèle de vue :

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.inversé

5
répondu Frederic 2012-09-12 20:08:53

pas sûr si cela correspond à vos besoins, mais j'ai trouvé un moyen d'accéder à tous les composants" importants "du TextEditor sur un ViewModel tout en le faisant afficher sur une vue, en explorant encore les possibilités cependant.

ce que j'ai fait était au lieu d'instancier le TextEditor sur la vue et puis liant les nombreuses propriétés que je vais avoir besoin, j'ai créé un contrôle de contenu et lié son contenu à une instance TextEditor que je crée dans le ViewModel .

:

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

code D'essai dans le viseur (fonctionne!)

// 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";

en ce moment je suis encore décider exactement ce que j'ai besoin de mon application pour configurer/faire avec le textEditor mais à partir de ces tests, il semble que je puisse changer n'importe quelle propriété de celui-ci tout en gardant une approche MVVM.

0
répondu Luis Ferreira 2017-07-25 08:04:20