我正在尝试使用MVVM模式的AvalonEdit工作,但我真的不知道该怎么做。我想将SelectionLength和SelectionStart绑定到我的ViewModel,以便在执行某些业务逻辑时可以访问这两个值。
我开始创建像这样的DependencyProperties:
public class MvvmTextEditor : TextEditor, INotifyPropertyChanged
{
/// <summary>
/// A bindable Text property
/// </summary>
public new string Text
{
get { return base.Text; }
set {
base.Text = value;
RaisePropertyChanged();
}
}
/// <summary>
/// A bindable SelectionStart property
/// </summary>
public new int SelectionStart
{
get { return base.SelectionStart; }
set {base.SelectionStart = value; }
}
/// <summary>
/// A bindable SelectionLength property
/// </summary>
public new int SelectionLength
{
get { return base.SelectionLength; }
set { base.SelectionLength = value; }
}
/// <summary>
/// The bindable selection start property dependency property
/// </summary>
public static readonly DependencyProperty SelectionStartProperty =
DependencyProperty.Register("SelectionStart", typeof(int), typeof(MvvmTextEditor),
new PropertyMetadata((o, args) =>
{
var target = (TextEditor)o;
target.SelectionStart = (int)args.NewValue;
}));
/// <summary>
/// The bindable selection length property dependency property
/// </summary>
public static readonly DependencyProperty SelectionLengthProperty =
DependencyProperty.Register("SelectionLength", typeof(int), typeof(MvvmTextEditor),
new PropertyMetadata((o, args) =>
{
var target = (MvvmTextEditor) o;
target.SelectionLength = (int)args.NewValue;
Debug.WriteLine(target.SelectionLength);
}));
/// <summary>
/// The bindable text property dependency property
/// </summary>
public static readonly DependencyProperty TextProperty =
DependencyProperty.Register("Text", typeof(string), typeof(MvvmTextEditor),
new PropertyMetadata((o, args) =>
{
var target = (MvvmTextEditor)o;
target.Text = (string)args.NewValue;
}));
/// <summary>
/// Raises a property changed event
/// </summary>
/// <param name="property">The name of the property that updates</param>
public void RaisePropertyChanged([CallerMemberName] string caller = "")
{
var handler = PropertyChanged;
if (handler != null)
PropertyChanged(this, new PropertyChangedEventArgs(caller));
}
public event PropertyChangedEventHandler PropertyChanged;
}
TextDependencyProperty工作正常,但SelectionLength和SelectionStart无效。
我为SelectionChanged添加了一个事件处理程序(但我不完全是我在这里用SetValue做的事情:
public MvvmTextEditor()
{
TextArea.SelectionChanged += TextArea_SelectionChanged;
}
void TextArea_SelectionChanged(object sender, EventArgs e)
{
SetValue(SelectionStartProperty, SelectionStart);
SetValue(SelectionLengthProperty, SelectionLength);
}
选择现在正在运行,但向后选择存在问题。在这种情况下,SelectionStart始终为0.如果一切都是正确的,我到目前为止所做的,那么我将创建一个逻辑,如果有人选择向后,则转换索引和长度是正确的。我是否必须在PropertyMetaDataDelegate中实现此逻辑?
答案 0 :(得分:2)
是的,一旦我查看它,原因很明显。在为SelectionStart
和SelectionEnd
支持DP的属性的setter中,我们设置了base.SelectionStart
和base.SelectionLength
这创建了这些值的循环更新并阻止了正确从基类更新这些值。更新的MVVM TextEditor类如下所示。
/// <summary>
/// Class that inherits from the AvalonEdit TextEditor control to
/// enable MVVM interaction.
/// </summary>
public class MvvmTextEditor : TextEditor, INotifyPropertyChanged
{
/// <summary>
/// Default constructor to set up event handlers.
/// </summary>
public MvvmTextEditor()
{
TextArea.SelectionChanged += TextArea_SelectionChanged;
}
/// <summary>
/// Event handler to update properties based upon the selection changed event.
/// </summary>
void TextArea_SelectionChanged(object sender, EventArgs e)
{
this.SelectionStart = SelectionStart;
this.SelectionLength = SelectionLength;
}
#region Text.
/// <summary>
/// Dependancy property for the editor text property binding.
/// </summary>
public static readonly DependencyProperty TextProperty =
DependencyProperty.Register("Text", typeof(string), typeof(MvvmTextEditor),
new PropertyMetadata((obj, args) =>
{
MvvmTextEditor target = (MvvmTextEditor)obj;
target.Text = (string)args.NewValue;
}));
/// <summary>
/// Provide access to the Text.
/// </summary>
public new string Text
{
get { return base.Text; }
set { base.Text = value; }
}
/// <summary>
/// Return the current text length.
/// </summary>
public int Length
{
get { return base.Text.Length; }
}
/// <summary>
/// Override of OnTextChanged event.
/// </summary>
protected override void OnTextChanged(EventArgs e)
{
RaisePropertyChanged("Length");
base.OnTextChanged(e);
}
#endregion // Text.
#region Caret Offset.
/// <summary>
/// DependencyProperty for the TextEditorCaretOffset binding.
/// </summary>
public static DependencyProperty CaretOffsetProperty =
DependencyProperty.Register("CaretOffset", typeof(int), typeof(MvvmTextEditor),
new PropertyMetadata((obj, args) =>
{
MvvmTextEditor target = (MvvmTextEditor)obj;
target.CaretOffset = (int)args.NewValue;
}));
/// <summary>
/// Provide access to the CaretOffset.
/// </summary>
public new int CaretOffset
{
get { return base.CaretOffset; }
set { base.CaretOffset = value; }
}
#endregion // Caret Offset.
#region Selection.
/// <summary>
/// DependencyProperty for the TextEditor SelectionLength property.
/// </summary>
public static readonly DependencyProperty SelectionLengthProperty =
DependencyProperty.Register("SelectionLength", typeof(int), typeof(MvvmTextEditor),
new PropertyMetadata((obj, args) =>
{
MvvmTextEditor target = (MvvmTextEditor)obj;
target.SelectionLength = (int)args.NewValue;
}));
/// <summary>
/// Access to the SelectionLength property.
/// </summary>
public new int SelectionLength
{
get { return base.SelectionLength; }
set { SetValue(SelectionLengthProperty, value); }
}
/// <summary>
/// DependencyProperty for the TextEditor SelectionStart property.
/// </summary>
public static readonly DependencyProperty SelectionStartProperty =
DependencyProperty.Register("SelectionStart", typeof(int), typeof(MvvmTextEditor),
new PropertyMetadata((obj, args) =>
{
MvvmTextEditor target = (MvvmTextEditor)obj;
target.SelectionStart = (int)args.NewValue;
}));
/// <summary>
/// Access to the SelectionStart property.
/// </summary>
public new int SelectionStart
{
get { return base.SelectionStart; }
set { SetValue(SelectionStartProperty, value); }
}
#endregion // Selection.
/// <summary>
/// Implement the INotifyPropertyChanged event handler.
/// </summary>
public event PropertyChangedEventHandler PropertyChanged;
public void RaisePropertyChanged([CallerMemberName] string caller = null)
{
var handler = PropertyChanged;
if (handler != null)
PropertyChanged(this, new PropertyChangedEventArgs(caller));
}
}
我希望这有助于其他人。