WPF: как привязать команду к ListBoxItem с помощью MVVM?

Я только начал изучать MVVM. Я сделал приложение с нуля следуя этой MVVM учебник (я настоятельно рекомендую его всем новичкам MVVM). В принципе, то, что я создал до сих пор, - это несколько текстовых полей, где пользователь добавляет свои данные, кнопку для сохранения этих данных, которая впоследствии заполняет список всеми сделанными записями.

вот где я застрял: я хочу иметь возможность дважды щелкнуть по ListBoxItem и вызвать команду что я создал и добавил к моей ViewModel. Я не знаю, как закончить сторону XAML, т. е. я не знаю, как привязать эту команду к списку(элементу).

вот XAML:

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

вот 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);
    }
    ...
}

и, наконец, вот OpenEntryCommand, который я хочу выполнить, как только пользователь дважды щелкнет элемент в 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");
    }
}

пожалуйста, помогите, я был бы признателен.

3 ответов


к сожалению, только ButtonBase производные элементы управления имеют возможность привязки ICommand объектов Command свойства (для Click событие).

однако вы можете использовать API, предоставляемый Blend для отображения события (как в вашем случае MouseDoubleClick на ListBox) к


это сложно сделать из-за события DoubleClick. Есть несколько способов сделать это:

  1. обработайте событие двойного щелчка в коде позади, а затем вручную вызовите команду / метод на ViewModel
  2. используйте прикрепленное поведение для маршрутизации событие DoubleClick для вашей команды
  3. используйте поведение смеси для сопоставьте событие DoubleClick с вашей командой

2 и 3 могут быть более чистыми, но честно говоря, я легче, менее сложен и не самое худшее в мире. Для одноразового случая я бы, вероятно, использовал подход № 1.

теперь, если вы изменили свои требования, чтобы использовать, скажем, гиперссылку на каждый элемент, это было бы проще. Начните с именования корневого элемента в вашем XAML-например, для окна:

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

теперь, в DataTemplate для элементов списка, используйте что-то вроде этого:

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

привязка ElementName позволяет разрешить OpenEntryCmd из контекста вашей ViewModel, а не конкретного элемента данных.


Я считаю, что лучший способ сделать это-создать простую оболочку пользовательского элемента управления для моего контента со свойствами зависимостей для команды и параметра.

причина, по которой я это сделал, заключалась в том, что кнопка не пузырила событие click в моем ListBox, которое помешало ему выбрать 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>

использование:

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

содержание может быть любым, и когда элемент управления будет нажат, он выполнит команду.

EDIT: добавил Background="Transparent" to UserControl, чтобы включить события щелчка по всей области элемента управления.