18

WPF アプリケーションで Avalon MVVM と互換性を持たせようとしています。グーグルで調べたところ、AvalonEdit は MVVM フレンドリーではなく、TextEditor から派生したクラスを作成し、必要な依存関係プロパティを追加して、AvalonEdit の状態をエクスポートする必要があることがわかりました。ここでのGrunwald氏の答えで私はかなり迷っているのではないかと心配しています:

MVVM を使用してエディターの状態をエクスポートする必要がある場合は、TextEditor から派生したクラスを作成して、必要な依存関係プロパティを追加し、それらを AvalonEdit の実際のプロパティと同期させることをお勧めします。

これを達成する方法について、誰かが例を持っているか、良い提案をしていますか?

4

3 に答える 3

27

Herr Grunwald は、TextEditorプロパティを依存関係プロパティでラップして、それらにバインドできるようにすることについて話しています。基本的な考え方は次のとおりです (たとえば、CaretOffsetプロパティを使用)。

修正された 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));
        }
    }
}

が DependencyProperty にラップされたので、View ModelCaretOffsetなどのプロパティにバインドできます。説明のために、コントロールの値を同じ View Model プロパティOffsetにバインドし、Slider を移動すると、Avalon エディターのカーソル位置が更新されることを確認します。SliderOffset

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>

コード ビハインドのテスト

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

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

テスト ビュー モデル

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));
        }
    }
}
于 2012-09-13T05:11:03.043 に答える
7

エディターから Document プロパティを使用して、ViewModel のプロパティにバインドできます。

ビューのコードは次のとおりです。

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

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

ソース :ブログ nawrem.reverse

于 2012-09-12T20:08:53.707 に答える
0

これがあなたのニーズに合っているかどうかはわかりませんが、ViewModelのTextEditorのすべての「重要な」コンポーネントにアクセスしながら、View に表示しながら可能性を探る方法を見つけました。

View でTextEditorをインスタンス化し、必要な多くのプロパティをバインドする代わりに、コンテンツ コントロールを作成し、そのコンテンツをViewModelで作成したTextEditorインスタンスにバインドしました。

意見:

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

ビューモデル:

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

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

現時点では、アプリケーションが textEditor を使用して構成/実行するために必要なものを正確に決定していますが、これらのテストから、MVVM アプローチを維持しながら、そこから任意のプロパティを変更できるようです。

于 2017-01-05T10:20:39.217 に答える