WPF: comment lier une commande à ListBoxItem en utilisant MVVM?

je viens de commencer à apprendre le MVVM. J'ai fait l'application à partir de zéro en suivant ce tutoriel MVVM (je le recommande vivement à tous les débutants MVVM là-bas). Fondamentalement, ce que j'ai créé jusqu'à présent est un couple de boîtes de texte où l'utilisateur ajoute ses données, un bouton pour enregistrer ces données qui par la suite popule la boîte de liste avec toutes les entrées effectuées.

C'est là que je suis coincé: je veux pouvoir double-cliquer sur un ListBoxItem et pour déclencher une commande que j'ai créée et ajoutée à mon ViewModel. Je ne sais pas comment terminer le côté XAML, c'est-à-dire Je ne sais pas comment lier cette commande à la liste(élément).

Voici XAML:

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

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

et enfin, voici L'OpenEntryCommand que je veux être exécuté une fois que l'utilisateur double-clique l'élément dans la boîte Entrieslist:

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

S'il vous plaît aider, je vous en serais reconnaissant.

24
demandé sur g t 2011-04-05 02:47:33

3 réponses

malheureusement, seuls les contrôles dérivés ButtonBase ont la possibilité de lier les objets ICommand à leurs propriétés Command (pour l'événement Click ).

cependant, vous pouvez utiliser une API fournie par Blend pour mapper un événement (comme dans votre cas MouseDoubleClick sur le ListBox ) vers un objet ICommand .

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

vous devez définir: xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" et avoir une référence à System.Windows.Interactivity.dll .

-- modifier -- Ceci fait partie de WPF4, mais u peut utiliser Microsoft.Windows.Interactivité si vous n'utilisez pas WPF4. Cette dll est de Blend SDK, qui ne nécessite pas de mélange, d'ici: http://www.microsoft.com/downloads/en/details.aspx?FamilyID=f1ae9a30-4928-411d-970b-e682ab179e17&displaylang=en

Update : j'ai trouvé quelque chose qui devrait vous aider. vérifier ce lien sur MVVM Light Toolkit qui contient un aperçu sur la façon de faire cela, avec un lien aux bibliothèques nécessaires. MVVM Light Toolkit est un cadre très intéressant pour appliquer MVVM avec Silverlight, WPF et WP7.

Espérons que cela aide :)

60
répondu AbdouMoumen 2015-12-16 09:00:57

ceci est rendu délicat à cause de L'événement DoubleClick. Il y a plusieurs façons de le faire:

  1. Gérer l'événement de double-clic En code derrière, puis invoquer manuellement une commande / méthode sur votre ViewModel
  2. utilisez un comportement joint pour router L'événement DoubleClick à votre commande
  3. utilisez un comportement de mélange pour mappez L'événement DoubleClick à votre commande

2 et 3 pourraient être plus pur, mais franchement, 1 est plus facile, moins complexe, et pas la pire chose dans le monde. Pour un cas unique, j'utiliserais probablement l'approche n ° 1.

maintenant, si vous avez changé vos exigences pour utiliser, disons, un lien hypertexte sur chaque élément, ce serait plus facile. Commencez par nommer l'élément root dans votre XAML-par exemple, pour une fenêtre:

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

maintenant, dans le DataTemplate pour vos éléments ListBox, utilisez quelque chose comme ceci:

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

la liaison ElementName vous permet de résoudre L'OpenEntryCmd à partir du contexte de votre modèle de vue, plutôt que de l'élément de données spécifique.

7
répondu Paul Stovell 2017-05-23 12:10:30

je trouve que la meilleure façon de faire ceci est de créer un simple wrapper de contrôle de l'utilisateur pour mon contenu, avec des propriétés de dépendance pour la commande et le paramètre.

la raison pour laquelle j'ai fait cela était dû au bouton ne pas bouillonner l'événement de clic à ma liste qui l'a empêché de sélectionner le 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>

Usage:

<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>

le contenu peut être n'importe quoi, et quand le contrôle est cliqué, il exécutera la commande.

EDIT: , a Ajouté Background="Transparent" à UserControl pour activer les événements click sur l'ensemble de la zone de contrôle.

2
répondu Shahin Dohan 2017-05-15 06:28:28