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. Есть несколько способов сделать это:
- обработайте событие двойного щелчка в коде позади, а затем вручную вызовите команду / метод на ViewModel
- используйте прикрепленное поведение для маршрутизации событие DoubleClick для вашей команды
- используйте поведение смеси для сопоставьте событие 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, чтобы включить события щелчка по всей области элемента управления.