注意:在这种情况下,除非我有很多额外的时间花在这上面,否则我会将其归结为对 MVVM 不完全友好的第三方控件,稍微打破“规则”,然后放一些代码在您的 View 类后面将对该文本编辑器的引用传递给您的视图模型。
但是,如果您想使用“纯无代码隐藏 MVVM”,则需要创建某种代理对象,该对象知道如何与 XamTextEditor 通信并接收来自底层视图模型的事件。这类似于 Blend/Prism 用于执行用户交互对话框的机制:“动作”对象充当视图模型(它只是引发交互请求事件)和页面上的一些其他 UI 元素之间的桥梁。
我认为解决这个问题的最“稳健”的方法是创建一个知道如何“在当前选择位置将字符串插入 XamTextEditor”的对象。
<local:XamEditorInserter
SourceObject="{Binding InsertTagRequest}"
TargetEditor="{Binding ElementName=TBody}" />
您可以通过几种方式实现此技术。最简单的方法是定义一个具有事件的接口,您的自定义“桥”对象可以订阅该事件。(TriggerBase
来自 Blend SDK 公开了一个实际的List<Action>
,这实际上是同一件事,但要实现更多代码):
public class CustomTriggerEventArgs : EventArgs
{
public string StringData
{
get;
set;
}
}
public interface ICustomTrigger
{
event EventHandler<CustomTriggerEventArgs> CustomTriggerRaised;
}
public class CustomTrigger : ICustomTrigger
{
event EventHandler<CustomTriggerEventArgs> CustomTriggerRaised;
public void Raise(string s)
{
if (this.CustomTriggerRaised != null)
{
this.CustomTriggerRaised(this, new CustomTriggerEventArgs { StringData = s });
}
}
}
然后,您的桥对象将需要在SourceObject
更改时连接到该事件:
public DependencyObject SourceObject
{
get
{
return this.GetValue(SourceObjectProperty) as DependencyObject;
}
set
{
if (value is ICustomTrigger)
{
((ICustomTrigger)value).CustomTriggerRaised += this.TriggerRaised;
}
this.SetValue(SourceObjectProperty, value);
}
}
public void TriggerRaised(object sender, CustomTriggerEventArgs e)
{
if (this.TargetEditor != null)
{
var sel = this.TargetObject.SelectionStart;
var tag = e.StringData;
// do whatever.
}
}
在您的视图模型中,您只需定义 type 的属性ICustomTrigger
,将其设置为 a ,并在需要将新标签插入文本编辑器时new CustomTrigger()
调用其方法。Raise()