tutorial que programacion principiantes para conceptos codeproject basico c# wpf mvvm binding commandbinding

c# - que - WPF: ¿Cómo vincular un comando al ListBoxItem usando MVVM?



tutorial mvvm wpf c# (3)

Acabo de comenzar a aprender MVVM. Realicé la aplicación desde cero siguiendo este tutorial de MVVM (lo recomiendo encarecidamente a todos los principiantes de MVVM). Básicamente, lo que he creado hasta ahora es un par de cuadros de texto donde el usuario agrega sus datos, un botón para guardar esos datos que posteriormente llena el ListBox con todas las entradas realizadas.

Aquí es donde me quedé atascado: quiero poder hacer doble clic en un ListBoxItem y activar un comando que he creado y agregado a mi ViewModel. No sé cómo terminar el lado XAML, es decir, no sé cómo vincular ese comando al ListBox (Elemento).

Aquí está XAML:

... <ListBox Name="EntriesListBox" Width="228" Height="208" Margin="138,12,0,0" HorizontalAlignment="Left" VerticalAlignment="Top" ItemsSource="{Binding Entries}" /> ...

Aquí está ViewModel:

public class MainWindowViewModel : DependencyObject { ... public IEntriesProvider Entries { get { return entries; } } private IEntriesProvider entries; public OpenEntryCommand OpenEntryCmd { get; set; } public MainWindowViewModel(IEntriesProvider source) { this.entries = source; ... this.OpenEntryCmd = new OpenEntryCommand(this); } ... }

Y finalmente, aquí está el OpenEntryCommand que quiero que se ejecute una vez que el usuario hace doble clic en el elemento en el EntriesListBox:

public class OpenEntryCommand : ICommand { private MainWindowViewModel viewModel; public OpenEntryCommand(MainWindowViewModel viewModel) { this.viewModel = viewModel; } public event EventHandler CanExecuteChanged { add { CommandManager.RequerySuggested += value; } remove { CommandManager.RequerySuggested -= value; } } public bool CanExecute(object parameter) { return parameter is Entry; } public void Execute(object parameter) { string messageFormat = "Subject: {0}/nStart: {1}/nEnd: {2}"; Entry entry = parameter as Entry; string message = string.Format(messageFormat, entry.Subject, entry.StartDate.ToShortDateString(), entry.EndDate.ToShortDateString()); MessageBox.Show(message, "Appointment"); } }

Por favor ayuda, te agradecería.


Desafortunadamente, solo los controles derivados de ButtonBase tienen la posibilidad de vincular objetos ICommand a sus propiedades de Command (para el evento Click ).

Sin embargo, puede usar una API proporcionada por Blend para mapear un evento (como en su caso MouseDoubleClick en el ListBox ) a un objeto ICommand .

<ListBox> <i:Interaction.Triggers> <i:EventTrigger EventName="MouseDoubleClick"> <i:InvokeCommandAction Command="{Binding YourCommand}"/> </i:EventTrigger> </i:Interaction.Triggers> </ListBox>

Deberá definir: xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" y tener una referencia a System.Windows.Interactivity.dll .

- EDITAR - Esto es parte de WPF4, pero puede usar Microsoft.Windows.Interactivity si no está usando WPF4. Este dll es de Blend SDK, que no requiere mezcla, desde aquí: http://www.microsoft.com/downloads/en/details.aspx?FamilyID=f1ae9a30-4928-411d-970b-e682ab179e17&displaylang=en

Actualización : Encontré algo que debería ayudarte. revise este enlace en MVVM Light Toolkit que contiene un tutorial sobre cómo hacer esto, junto con un link a las bibliotecas necesarias. MVVM Light Toolkit es un marco muy interesante para aplicar MVVM con Silverlight, WPF y WP7.

Espero que esto ayude :)


Encuentro que la mejor manera de hacerlo es crear un contenedor de control de usuario simple para mi contenido, con propiedades de dependencia para el comando y el parámetro.

La razón por la que hice esto fue debido a que el botón no burbujeaba el evento de clic en mi ListBox, lo que impedía que seleccionara ListBoxItem.

CommandControl.xaml.cs:

public partial class CommandControl : UserControl { public CommandControl() { MouseLeftButtonDown += OnMouseLeftButtonDown; InitializeComponent(); } private void OnMouseLeftButtonDown(object sender, MouseButtonEventArgs mouseButtonEventArgs) { if (Command != null) { if (Command.CanExecute(CommandParameter)) { Command.Execute(CommandParameter); } } } public static readonly DependencyProperty CommandProperty = DependencyProperty.Register("Command", typeof(ICommand), typeof(CommandControl), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.None)); public ICommand Command { get { return (ICommand)GetValue(CommandProperty); } set { SetValue(CommandProperty, value); } } public static readonly DependencyProperty CommandParameterProperty = DependencyProperty.Register("CommandParameter", typeof(object), typeof(CommandControl), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.None)); public object CommandParameter { get { return (object)GetValue(CommandParameterProperty); } set { SetValue(CommandParameterProperty, value); } } }

CommandControl.xaml:

<UserControl x:Class="WpfApp.UserControls.CommandControl" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="300" Background="Transparent"> </UserControl>

Uso:

<ListBoxItem> <uc:CommandControl Command="{Binding LoadPageCommand}" CommandParameter="{Binding HomePageViewModel}"> <TextBlock Text="Home" Margin="0,0,0,5" VerticalAlignment="Center" Foreground="White" FontSize="24" /> </uc:CommandControl> </ListBoxItem>

El contenido puede ser lo que sea, y cuando se hace clic en el control, ejecutará el comando.

EDITAR: se agregó Background="Transparent" a UserControl para habilitar eventos de clic en toda el área del control.


Esto es complicado debido al evento de DoubleClick. Hay algunas maneras de hacer esto:

  1. Controle el evento de doble clic en el código subyacente y luego invoque manualmente un comando / método en su ViewModel
  2. Use un comportamiento adjunto para enrutar el evento de DoubleClick a su Comando
  3. Use un Comportamiento de combinación para asignar el evento de DoubleClick a su comando

2 y 3 podrían ser más puros, pero francamente, 1 es más fácil, menos complejo y no es lo peor del mundo. Para un caso aislado, probablemente usaría el enfoque n. ° 1.

Ahora, si cambió sus requisitos para usar, por ejemplo, un hipervínculo en cada elemento, sería más fácil. Comience nombrando el elemento raíz en su XAML, por ejemplo, para una ventana:

<Window .... Name="This">

Ahora, en DataTemplate para sus elementos de ListBox, use algo como esto:

<ListBox ...> <ListBox.ItemTemplate> <DataTemplate> <Hyperlink Command="{Binding ElementName=This, Path=DataContext.OpenEntryCmd}" Text="{Binding Path=Name}" />

El enlace ElementName le permite resolver el OpenEntryCmd a partir del contexto de su ViewModel, en lugar del elemento de datos específico.