对于那些想了解使用AvalonEdit实现MVVM的人,这里是其中一种方法,首先我们有这个类:
public class CodeEditor : TextEditor, INotifyPropertyChanged
{
private static bool canScroll = true;
public CodeEditor()
{
FontSize = 12;
FontFamily = new FontFamily("Consolas");
Options = new TextEditorOptions
{
IndentationSize = 3,
ConvertTabsToSpaces = true
};
}
#region Text.
public static readonly DependencyProperty TextProperty =
DependencyProperty.Register("Text", typeof(string), typeof(CodeEditor),
new PropertyMetadata((obj, args) =>
{
CodeEditor target = (CodeEditor)obj;
target.Text = (string)args.NewValue;
}));
public new string Text
{
get { return base.Text; }
set { base.Text = value; }
}
public int Length
{
get { return base.Text.Length; }
}
protected override void OnTextChanged(EventArgs e)
{
RaisePropertyChanged("Length");
base.OnTextChanged(e);
}
void TextArea_SelectionChanged(object sender, EventArgs e)
{
this.SelectionStart = SelectionStart;
this.SelectionLength = SelectionLength;
}
void TextArea_CaretPositionChanged(object sender, EventArgs e)
{
try
{
canScroll = false;
this.TextLocation = TextLocation;
}
finally
{
canScroll = true;
}
}
#endregion // Text.
#region Caret Offset.
public static DependencyProperty CaretOffsetProperty =
DependencyProperty.Register("CaretOffset", typeof(int), typeof(CodeEditor),
new PropertyMetadata((obj, args) =>
{
CodeEditor target = (CodeEditor)obj;
if (target.CaretOffset != (int)args.NewValue)
target.CaretOffset = (int)args.NewValue;
}));
public new int CaretOffset
{
get { return base.CaretOffset; }
set { SetValue(CaretOffsetProperty, value); }
}
#endregion // Caret Offset.
#region Selection.
public static readonly DependencyProperty TextLocationProperty =
DependencyProperty.Register("TextLocation", typeof(TextLocation), typeof(CodeEditor),
new PropertyMetadata((obj, args) =>
{
CodeEditor target = (CodeEditor)obj;
TextLocation loc = (TextLocation)args.NewValue;
if (canScroll)
target.ScrollTo(loc.Line, loc.Column);
}));
public TextLocation TextLocation
{
get { return base.Document.GetLocation(SelectionStart); }
set { SetValue(TextLocationProperty, value); }
}
public static readonly DependencyProperty SelectionLengthProperty =
DependencyProperty.Register("SelectionLength", typeof(int), typeof(CodeEditor),
new PropertyMetadata((obj, args) =>
{
CodeEditor target = (CodeEditor)obj;
if (target.SelectionLength != (int)args.NewValue)
{
target.SelectionLength = (int)args.NewValue;
target.Select(target.SelectionStart, (int)args.NewValue);
}
}));
public new int SelectionLength
{
get { return base.SelectionLength; }
set { SetValue(SelectionLengthProperty, value); }
}
public static readonly DependencyProperty SelectionStartProperty =
DependencyProperty.Register("SelectionStart", typeof(int), typeof(CodeEditor),
new PropertyMetadata((obj, args) =>
{
CodeEditor target = (CodeEditor)obj;
if (target.SelectionStart != (int)args.NewValue)
{
target.SelectionStart = (int)args.NewValue;
target.Select((int)args.NewValue, target.SelectionLength);
}
}));
public new int SelectionStart
{
get { return base.SelectionStart; }
set { SetValue(SelectionStartProperty, value); }
}
#endregion // Selection.
#region Properties.
public string FilePath
{
get { return (string)GetValue(FilePathProperty); }
set { SetValue(FilePathProperty, value); }
}
public static readonly DependencyProperty FilePathProperty =
DependencyProperty.Register("FilePath", typeof(string), typeof(CodeEditor),
new PropertyMetadata(String.Empty, OnFilePathChanged));
#endregion // Properties.
#region Raise Property Changed.
public event PropertyChangedEventHandler PropertyChanged;
public void RaisePropertyChanged([CallerMemberName] string caller = null)
{
var handler = PropertyChanged;
if (handler != null)
PropertyChanged(this, new PropertyChangedEventArgs(caller));
}
#endregion // Raise Property Changed.
}
然后在您想要使用AvalonEdit的视图中,您可以执行以下操作:
...
<Grid>
<Local:CodeEditor
x:Name="CodeEditor"
FilePath="{Binding FilePath,
Mode=TwoWay,
NotifyOnSourceUpdated=True,
NotifyOnTargetUpdated=True}"
WordWrap="{Binding WordWrap,
Mode=TwoWay,
NotifyOnSourceUpdated=True,
NotifyOnTargetUpdated=True}"
ShowLineNumbers="{Binding ShowLineNumbers,
Mode=TwoWay,
NotifyOnSourceUpdated=True,
NotifyOnTargetUpdated=True}"
SelectionLength="{Binding SelectionLength,
Mode=TwoWay,
NotifyOnSourceUpdated=True,
NotifyOnTargetUpdated=True}"
SelectionStart="{Binding SelectionStart,
Mode=TwoWay,
NotifyOnSourceUpdated=True,
NotifyOnTargetUpdated=True}"
TextLocation="{Binding TextLocation,
Mode=TwoWay,
NotifyOnSourceUpdated=True,
NotifyOnTargetUpdated=True}"/>
</Grid>
这可以放置在UserControl、Window或其他地方,然后在此视图的ViewModel中,我们有以下代码(我正在使用Caliburn Micro作为MVVM框架):
public string FilePath
{
get { return filePath; }
set
{
if (filePath == value)
return;
filePath = value;
NotifyOfPropertyChange(() => FilePath);
}
}
public bool WordWrap
{
get { return wordWrap; }
set
{
if (wordWrap == value)
return;
wordWrap = value;
NotifyOfPropertyChange(() => WordWrap);
}
}
public bool ShowLineNumbers
{
get { return showLineNumbers; }
set
{
if (showLineNumbers == value)
return;
showLineNumbers = value;
NotifyOfPropertyChange(() => ShowLineNumbers);
}
}
private int selectionStart = 0;
public int SelectionStart
{
get { return selectionStart; }
set
{
selectionStart = value;
NotifyOfPropertyChange(() => SelectionStart);
}
}
private int selectionLength = 0;
public int SelectionLength
{
get { return selectionLength; }
set
{
selectionLength = value;
UpdateStatusBar();
NotifyOfPropertyChange(() => SelectionLength);
}
}
private TextLocation textLocation = new TextLocation(0, 0);
public TextLocation TextLocation
{
get { return textLocation; }
set
{
textLocation = value;
UpdateStatusBar();
NotifyOfPropertyChange(() => TextLocation);
}
}
就是这样!完成。
希望这可以帮到你。
编辑。对于所有寻找使用MVVM处理AvalonEdit示例的人,你可以从http://1drv.ms/1E5nhCJ下载一个非常基本的编辑器应用程序。
注释。这个应用程序实际上通过继承AvalonEdit标准控件并根据需要添加附加依赖属性来创建一个MVVM友好的编辑器控件——*这与我在上面给出的答案不同*。然而,在解决方案中,我还展示了如何使用附加属性来完成此操作(如我在上面的答案中所述),并且在Behaviors
命名空间下有代码。但实际上实现的是以上的第一种方法。
还请注意,解决方案中有一些未使用的代码。这个*样例*是一个较大应用程序的简化版本,我留下了一些代码,因为它可能对下载此示例编辑器的用户有用。除了上述之外,我在示例代码中访问Text通过绑定到document,有些人可能会认为这不是纯粹的MVVM,我说“好吧,但它有效”。有时候,与这种模式斗争并不是正确的方法。
希望这对你们中的一些人有用。
Text
属性。我肯定已经正确地监视了控件。感谢您的帮助... - MoonKnight