我已经在我的项目是基于WPF和MVVM使用AvalonEdit。 看完这篇文章我创建了以下类:
public class MvvmTextEditor : TextEditor, INotifyPropertyChanged
{
public static DependencyProperty DocumentTextProperty =
DependencyProperty.Register("DocumentText",
typeof(string), typeof(MvvmTextEditor),
new PropertyMetadata((obj, args) =>
{
MvvmTextEditor target = (MvvmTextEditor)obj;
target.DocumentText = (string)args.NewValue;
})
);
public string DocumentText
{
get { return base.Text; }
set { base.Text = value; }
}
protected override void OnTextChanged(EventArgs e)
{
RaisePropertyChanged("DocumentText");
base.OnTextChanged(e);
}
public event PropertyChangedEventHandler PropertyChanged;
public void RaisePropertyChanged(string info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
}
并用下面的XAML使用此控件:
<avalonedit:MvvmTextEditor x:Name="xmlMessage">
<avalonedit:MvvmTextEditor.DocumentText>
<Binding Path ="MessageXml" Mode="TwoWay"
UpdateSourceTrigger="PropertyChanged">
<Binding.ValidationRules>
<local:XMLMessageValidationRule />
</Binding.ValidationRules>
</Binding>
</avalonedit:MvvmTextEditor.DocumentText>
</avalonedit:MvvmTextEditor>
但结合作品OneWay
并且不更新我的字符串属性,也没有运行验证规则。
如何解决绑定按预期运行TwoWay
?
WPF绑定不使用你的DocumentText
财产; 相反,他们直接访问依赖属性的基本价值。
您OnTextChanged
方法实际上并没有改变基本的依赖项属性的值。 您需要的值从复制base.Text
插入每一个变化的依赖项属性:
protected override void OnTextChanged(EventArgs e)
{
SetCurrentValue(DocumentTextProperty, base.Text);
base.OnTextChanged(e);
}
如果你遵照执行正确的模式这个问题会更容易看到DependencyProperty
的: DocumentText
属性应该使用GetValue
/ SetValue
方法,而不是访问一个不同的后备存储。
使用的GetValue和的SetValue即使你不能得到TextProperty更新绑定当文本的变化,所以丹尼尔回答无论如何必须遵守。
我确实改变了一下,以使其更直观不必使用文本作为正常dependecy模式最终用户:
public new string Text
{
get { return (string)GetValue(TextProperty); }
set { SetValue(TextProperty, value); }
}
internal string baseText { get { return base.Text; } set { base.Text = value; } }
public static DependencyProperty TextProperty =
DependencyProperty.Register("Text", typeof(string), typeof(MvvmTextEditor),
// binding changed callback: set value of underlying property
new PropertyMetadata((obj, args) =>
{
MvvmTextEditor target = (MvvmTextEditor)obj;
if(target.baseText != (string)args.NewValue) //avoid undo stack overflow
target.baseText = (string)args.NewValue;
})
);
protected override void OnTextChanged(EventArgs e)
{
SetCurrentValue(TextProperty, baseText);
RaisePropertyChanged("Text");
base.OnTextChanged(e);
}
我不得不检查,如果相同的文本已经在那里了,以避免撤消堆栈引擎例外。 另外在性能方面是一个很好的协议。
我想基于上面稍作修改答案的代码,如结合是不是为我工作两者兼得。 下面的内容应该允许绑定两种方式。
public static readonly DependencyProperty MyContentProperty = DependencyProperty.Register(
"MyContent", typeof(string), typeof(MyTextEditor), new PropertyMetadata("", OnMyContentChanged));
private static void OnMyContentChanged(object sender, DependencyPropertyChangedEventArgs e)
{
var control = (MyTextEditor)sender;
if (string.Compare(control.MyContent, e.NewValue.ToString()) != 0)
{
//avoid undo stack overflow
control.MyContent = e.NewValue.ToString();
}
}
public string MyContent
{
get { return Text; }
set { Text = value; }
}
protected override void OnTextChanged(EventArgs e)
{
SetCurrentValue(MyContentProperty, Text);
base.OnTextChanged(e);
}