WPF:如何使用MVVM将命令绑定到ListBoxItem?

我刚开始学习MVVM。我通过遵循这个MVVM教程从头开始制作应用程序(我强烈推荐给所有MVVM初学者)。基本上,我到目前为止创建的是一些文本框,其中用户添加他或她的数据,一个按钮来保存该数据,随后使用所有条目填充ListBox。 这就是我陷入困境的地方:我希望能够双击ListBoxItem并触发我创建并添加到ViewModel的命令。我不知道如何完成XAML方面,即我不知道如何将该命令绑定到ListBox(Item)。 这是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);
    }
    ...
}
最后,这是我想在用户双击EntriesListBox中的项目后执行的OpenEntryCommand:
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");
    }
}
请帮忙,我很感激。     
已邀请:
不幸的是,只有
ButtonBase
派生控件才有可能将
ICommand
对象绑定到它们的
Command
属性(对于
Click
事件)。 但是,您可以使用Blend提供的API将事件(例如
ListBox
中的情况
MouseDoubleClick
)映射到
ICommand
对象。
<ListBox>
    <i:Interaction.Triggers>
        <i:EventTrigger EventName="MouseDoubleClick">
            <i:InvokeCommandAction Command="{Binding YourCommand}"/>
        </i:EventTrigger>
    </i:Interaction.Triggers>
</ListBox>
你必须定义:
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
并引用
System.Windows.Interactivity.dll
。 - 编辑 - 这是WPF4的一部分,但如果您不使用WPF4,则可以使用Microsoft.Windows.Interactivity。这个dll来自Blend SDK,它不需要Blend,从这里: http://www.microsoft.com/downloads/en/details.aspx?FamilyID=f1ae9a30-4928-411d-970b-e682ab179e17&displaylang=en 更新:我找到了一些可以帮到你的东西。检查MVVM Light Toolkit上的这个链接,其中包含有关如何执行此操作的演练,以及指向所需库的链接。 MVVM Light Toolkit是一个非常有趣的框架,用于将MVVM应用于Silverlight,WPF和WP7。 希望这可以帮助 :)     
由于DoubleClick事件,这很棘手。有几种方法可以做到这一点: 处理后面的代码中的双击事件,然后在ViewModel上手动调用命令/方法 使用附加行为将DoubleClick事件路由到您的Command 使用“混合行为”将DoubleClick事件映射到您的命令 2和3可能更纯粹,但坦率地说,1更容易,更简单,而不是世界上最糟糕的事情。对于一次性案例,我可能会使用方法#1。 现在,如果您更改了要求使用每个项目的超链接,那么这将更容易。首先命名XAML中的根元素 - 例如,对于一个Window:
<Window .... Name="This">
现在,在ListBox项的DataTemplate中,使用以下内容:
<ListBox ...>
  <ListBox.ItemTemplate>
    <DataTemplate>
      <Hyperlink 
        Command="{Binding ElementName=This, Path=DataContext.OpenEntryCmd}"
        Text="{Binding Path=Name}" 
        />
ElementName绑定允许您从ViewModel的上下文中解析OpenEntryCmd,而不是特定的数据项。     
我发现最好的方法是为我的内容创建一个简单的用户控件包装器,其中包含命令和参数的依赖项属性。 我这样做的原因是Button没有将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>
内容可以是任何内容,当单击控件时,它将执行命令。 编辑:添加
Background="Transparent"
到UserControl以启用控件的整个区域上的单击事件。     
这有点像黑客攻击,但它运行良好,允许您使用命令并避免代码隐藏。假设你的
ListBoxItems
没有填满整个容器,当你在空的
ScrollView
区域双击(或你的触发器是什么)时,这还有一个额外的好处就是不会触发命令。 基本上,只为你的
ListBox
创建一个
DataTemplate
,它由
TextBlock
组成,并将
TextBlock
的宽度绑定到
ListBox
的宽度,将边距和填充设置为0,并禁用水平滚动(因为
TextBlock
会在可见光之外出血)
ScrollView
的边界触发水平滚动条否则)。我发现的唯一错误是,如果用户精确点击
ListBoxItem
的边框,命令将不会触发,我可以使用它。 这是一个例子:
<ListBox
    x:Name="listBox"
    Width="400"
    Height="150"
    ScrollViewer.HorizontalScrollBarVisibility="Hidden"
    ItemsSource="{Binding ItemsSourceProperty}"
    SelectedItem="{Binding SelectedItemProperty}">
    <ListBox.ItemTemplate>
        <DataTemplate>
            <TextBlock Padding="0" 
                        Margin="0" 
                        Text="{Binding DisplayTextProperty}" 
                        Width="{Binding ElementName=listBox, Path=Width}">
                <TextBlock.InputBindings>
                    <MouseBinding 
                        Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListBox}}, Path=DataContext.SelectProjectCommand}" 
                                    Gesture="LeftDoubleClick" />
                </TextBlock.InputBindings>
            </TextBlock>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>
    

要回复问题请先登录注册