Tengo una aplicación WPF creada con MVVM. El control tiene un cuadro de texto en el que necesito insertar etiquetas. El control que estoy usando es XamT .

Entonces, cuando el usuario presiona el botón Insertar, necesito consultar el valor SelectionStart del control enfocado, para poder insertar la etiqueta en el índice de texto de la propiedad.

La propiedad de inicio de la selección no es un DP, por lo que no puedo vincular su valor y recibir notificaciones de cambio.

Me pregunto cómo alguien hará esto en MVVM.

Los controles se definen como:

<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>
0
np-hard 27 abr. 2012 a las 20:34

1 respuesta

La mejor respuesta

NOTA: En este caso, a menos que tenga mucho tiempo extra para dedicarlo a esto, lo atribuiría a un control de terceros no completamente compatible con MVVM, rompería un poco las "reglas" y simplemente pondría algo de código detrás en su clase de vista para pasar una referencia a ese editor de texto en su modelo de vista.

Pero si quisiera ir a "MVVM puro sin código detrás", necesitaría crear algún tipo de objeto proxy que supiera cómo comunicarse con XamTextEditor y también recibir eventos del modelo de vista subyacente. Esto es similar al mecanismo utilizado por Blend / Prism para realizar diálogos de interacción del usuario: los objetos de "acción" sirven como un puente entre el modelo de vista (que simplemente genera un evento de solicitud de interacción) y algunos otros elementos de la interfaz de usuario en la página.

Creo que la forma más "robusta" de abordar esto es crear un objeto que sepa "insertar una cadena en un XamTextEditor en la posición de selección actual".

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

Puede implementar esta técnica de varias formas. Lo más fácil es definir una interfaz que tenga un evento, al cual su objeto "puente" personalizado puede suscribirse. (TriggerBase del Blend SDK expone un List<Action> real, que es efectivamente lo mismo pero un poco más de código para implementar):

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 });
    }
  }
}

Su objeto puente necesitaría conectarse a ese evento cuando se cambió 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.
  }
}

En su modelo de vista, simplemente defina una propiedad de tipo ICustomTrigger, establézcala en new CustomTrigger() y llame a su método Raise() cuando necesite insertar una nueva etiqueta en su editor de texto.

1
Michael Edenfield 27 abr. 2012 a las 21:08