2010-04-08 19 views

Respuesta

18

Cada vez que intento afectar directamente la Vista en una aplicación MVVM "pura" (sin código subyacente en la Vista), utilizaré Attached Properties para encapsular cualquier efecto que intente lograr. Crearé una interfaz que define las acciones que deseo realizar usando eventos personalizados. Luego implemento esta interfaz en cada ViewModel que "ejecutará" estos comandos en la Vista. Finalmente, vinculo mi ViewModel a la propiedad adjunta en mi definición de Vista. El siguiente código muestra cómo esto para SelectAll y un TextBox. Este código se puede expandir fácilmente para realizar casi cualquier acción en cualquier componente de la Vista.

mi propiedad y la interfaz adjunta definición:

using System.Windows; 
using System.Windows.Controls; 
using System; 
using System.Collections.Generic; 

namespace SelectAllSample 
{ 
    public static class TextBoxAttach 
    { 
     public static readonly DependencyProperty TextBoxControllerProperty = DependencyProperty.RegisterAttached(
      "TextBoxController", typeof(ITextBoxController), typeof(TextBoxAttach), 
      new FrameworkPropertyMetadata(null, OnTextBoxControllerChanged)); 
     public static void SetTextBoxController(UIElement element, ITextBoxController value) 
     { 
      element.SetValue(TextBoxControllerProperty, value); 
     } 
     public static ITextBoxController GetTextBoxController(UIElement element) 
     { 
      return (ITextBoxController)element.GetValue(TextBoxControllerProperty); 
     } 

     private static readonly Dictionary<ITextBoxController, TextBox> elements = new Dictionary<ITextBoxController, TextBox>(); 
     private static void OnTextBoxControllerChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
     { 
      var element = d as TextBox; 
      if (element == null) 
       throw new ArgumentNullException("d"); 

      var oldController = e.OldValue as ITextBoxController; 
      if (oldController != null) 
      { 
       elements.Remove(oldController); 
       oldController.SelectAll -= SelectAll; 
      } 

      var newController = e.NewValue as ITextBoxController; 
      if (newController != null) 
      { 
       elements.Add(newController, element); 
       newController.SelectAll += SelectAll; 
      } 
     } 
     private static void SelectAll(ITextBoxController sender) 
     { 
      TextBox element; 
      if (!elements.TryGetValue(sender, out element)) 
       throw new ArgumentException("sender"); 
      element.Focus(); 
      element.SelectAll(); 
     } 
    } 

    public interface ITextBoxController 
    { 
     event SelectAllEventHandler SelectAll; 
    } 

    public delegate void SelectAllEventHandler(ITextBoxController sender); 
} 

Mi definición modelo de vista:

public class MyViewModel : ITextBoxController 
{ 
    public MyViewModel() 
    { 
     Value = "My Text"; 
     SelectAllCommand = new RelayCommand(p => 
     { 
      if (SelectAll != null) 
       SelectAll(this); 
     }); 
    } 

    public string Value { get; set; } 
    public RelayCommand SelectAllCommand { get; private set; } 

    public event SelectAllEventHandler SelectAll; 
} 

Mi Ver definición:

<Window x:Class="SelectAllSample.Window1" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:loc="clr-namespace:SelectAllSample" 
    Title="Window1" Height="150" Width="150"> 
    <x:Code><![CDATA[ 
     public Window1() 
     { 
      InitializeComponent(); 
      DataContext = new MyViewModel(); 
     } 
    ]]></x:Code> 
    <StackPanel> 
     <TextBox Text="{Binding Value}" loc:TextBoxAttach.TextBoxController="{Binding}" /> 
     <Button Content="Select All" Command="{Binding SelectAllCommand}" /> 
    </StackPanel> 
</Window> 

Nota: Gracias a Josh Smith por RelayCommand (Vea el código en la Figura 3 en this page). Se usa en MyViewModel en este ejemplo (y casi todo mi código MVVM).

+0

Muchas gracias! – Justin

+0

Me aparece un error: "Delegar 'System.Action' no toma 1 argumentos"? – Justin

+1

¿Dónde está el error? Asegúrese de que el número de parámetros en la definición de su controlador de eventos sea consistente con la forma en que define su controlador (y úselo). Estoy usando un Lambda con RelayCommand para plantear el evento en mi ejemplo. –

Cuestiones relacionadas