使用MVVM在VM中获取控件的非依赖属性值

时间:2012-04-27 16:34:40

标签: wpf mvvm

我有一个使用MVVM构建的WPF应用程序。该控件有一个文本框,我需要在其中插入标签。我使用的控件是 XamT

因此,当用户按下插入按钮时,我需要查询聚焦控件的SelectionStart值,这样我就可以在属性文本索引处插入标记。

选择开始属性不是DP,因此我无法对其值进行数据绑定并接收更改通知。

我想知道MVVM中有人会这样做吗?

控件定义为:

<x:XamTextEditor Grid.Column="1" Grid.Row="3" 
                 Grid.ColumnSpan="2"  Margin="0 5 0 5" 
                 Template="{StaticResource ResourceKey=MyTextEditorTemplate}" 
                 Name="TBody" 
                 Text="{Binding Body}" 
                 TextWrapping="Wrap" 
                 IsAlwaysInEditMode="{Binding InEditMode,Mode=OneWay}"
                 AcceptsReturn="True" AcceptsTab="True">
    <igEditors:ValueConstraint Nullable="False" MinLength="1"/>
</x:XamTextEditor>

1 个答案:

答案 0 :(得分:1)

注意:在这种情况下,除非我有更多的额外时间花在这上面,否则我会把它归结为一个不完全MVVM友好的第三方控件,打破“规则”一点,然后只是在View类中添加一些代码,将对该文本编辑器的引用传递给您的视图模型。

但是如果你想要“纯粹的无代码隐藏的MVVM”,你需要创建某种代理对象,它知道如何与XamTextEditor进行通信,并从底层视图模型接收事件。这类似于Blend / Prism用于执行用户交互对话框的机制:“action”对象充当视图模型(简单地引发交互请求事件)与页面上的一些其他UI元素之间的桥梁。 p>

我认为最有效的方法是创建一个知道如何“在当前选择位置将字符串插入XamTextEditor”的对象。

<local:XamEditorInserter 
    SourceObject="{Binding InsertTagRequest}" 
    TargetEditor="{Binding ElementName=TBody}" />

您可以通过几种方式实现此技术。最简单的方法是定义一个具有事件的接口,您的自定义“桥”对象可以订阅该事件。 (Blend SDK中的TriggerBase公开了一个实际的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.
  }
}

在您的viewmodel中,您只需定义ICustomTrigger类型的属性,将其设置为new CustomTrigger(),并在需要在文本中插入新标记时调用其Raise()方法编辑器。