2009-06-26 10 views
9

Actualmente estoy convirtiendo un pequeño proyecto de WPF a MVVM. Tengo un List<CustomObject> en el ViewModel de la ventana principal a la que se une my ItemsControl y utiliza un DataTemplate para construir la UI de cada elemento. Mi código anterior usaba un controlador de eventos dentro de DataTemplate para manejar un evento de clic. Quiero utilizar algún tipo de enlace de comando para eliminar mis controladores de eventos de código subyacente, pero el DataContext de los elementos en mi ItemsControl es el objeto modelo, por lo que actualmente no puedo enlazar a ICommand desde ViewModel.WPF MVVM - Enlace de comandos dentro de ItemsControl

Entonces, supongo que hay un par de formas de atacar esto y no estoy seguro de cuál sería la forma más "MVVM" de hacerlo. ¿Vincularé ItemsControl.ItemsSource a una colección de una nueva clase ViewModel que represente cada elemento? ¿O utilizo UserControls en lugar de DataTemplate y luego puedo vincular cada UserControl a su propia instancia de un ViewModel que lo representa? ¿O hay algún tipo de expresión vinculante que pueda usar para referirme al DataContext de la ventana para tener acceso a enlazar al ViewModel (mientras escribo esto, suena mal así que estoy asumiendo un gran "NO" a esto idea)?

Además, lo que quiero vincular a mi comando es el evento LeftMouseButtonUp de un control de cuadrícula. No hay un "Comando" para una Grilla, así que estaba tratando de usar InputBindings. Podría usar un comando estático (como uno de los comandos de aplicación integrados), pero no podría usar una expresión vinculante para enlazar a una instancia de ICommand que es una propiedad de ViewModel porque MouseBinding.Command no es DependencyProperty.

Estoy bastante confundido sobre el tema del manejo de eventos en MVVM, por lo que se aprecia toda la información.

Respuesta

4

Josh Smith escribió un excelente artículo en MSDN here donde habla sobre el enlace de comandos.

En su caso se reduce a lo siguiente:

  • Usted no va a eliminar todas las de código subyacente, pero es probable que un aspecto diferente
  • Sus CustomObjects probablemente tendrán que tener clases calza VM , o ser máquinas virtuales para aprovechar la arquitectura RelayCommand que él describe.

HTH.

19

¿Ato el ItemsControl.ItemsSource a una colección de una nueva clase de ViewModel que representa cada elemento?

Si crea un CustomObjectViewModel para alojar el comando o coloca el comando dentro del mismo ViewModel que tiene la lista realmente depende de la función de la acción que se está produciendo. ¿Es algo que pertenece al CustomObject o es algo que pertenece a su ViewModel actual?

O hay algún tipo de expresión de enlace que puede utilizar para hacer referencia de nuevo a la DataContext de la ventana para tener acceso a enlazar con el modelo de vista (mientras escribo esto, suena mal, así que estoy asumiendo una gran "NO" a esta idea)?

Esto no es tan malo como parece. Realmente no necesita el DataContext de la ventana, solo el DataContext antes de cambiar a los elementos individuales.Así que si su comando estaba en el mismo modelo de vista que aloja la Lista de CustomObjects, que podría obligar a la misma desde dentro de una de DataTemplate del CustomObject utilizando cualquiera de estos métodos:

{Binding ElementName=uiCustomObjectsItemsControl, Path=DataContext.MyCommand} 
{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ItemsControl}}, Path=DataContext.MyCommand} 

Además, lo que quiero para unirse mi comando a es el evento LeftMouseButtonUp de un control de cuadrícula . No hay un "Comando" para una Cuadrícula, así que estaba tratando de usar Entradas de Entrada.

Para esto, usaría algo como Attached Command Behaviors que le permitirá conectar un ICommand a cualquier evento.

1

Puede intentar mantener su comando en su modelo.

public class MyModel 
{ 
    public MyModel() 
    { 
     MyCommand = new DelegateCommand(MyCommandExecute); 
    } 

    public ICommand MyCommandCommand { get; set; } 

    private void MyCommandExecute() 
    { 
    } 
} 

Y luego, debe tener un ObservableList para la lista de sus productos en su modelo de vista que,

public class MyViewModel 
{ 
    public MyViewModel() 
    { 
     MyStarterCommand = new DelegateCommand(MyCommandExecute); 

     if (!IsDesignTime)//(bool)DependencyPropertyDescriptor.FromProperty(DesignerProperties.IsInDesignModeProperty, typeof(DependencyObject)).Metadata.DefaultValue; 
      MyCommand.Execute(null); 
    } 

    private ObservableCollection<MyModel> list; 
    private ICommand MyStarterCommand { get; set; } 

    public ObservableCollection<MyModel> List 
    { 
     get { return list; } 
     set 
     { 
      list = value; 
      RaisePropertyChanged(() => List); 
     } 
    } 

    private void MyStarterCommandExecute() 
    { 
     List = new ObservableCollection<MyModel>(); 

     //Fill the list here 
     List.Add(new MyModel()); 
    } 
} 

Luego, en XAML que hay que decir;

<ItemsControl ItemsSource="{Binding List}"> 
    <ItemsControl.ItemTemplate> 
     <DataTemplate> 
      <Button Content="MyButton" Command="{Binding MyCommand}" /> 
     </DataTemplate> 
    </ItemsControl.ItemTemplate> 
</ItemsControl> 
Cuestiones relacionadas