簡體   English   中英

WPF:如何使用MVVM將命令綁定到ListBoxItem?

[英]WPF: How to bind a command to the ListBoxItem using MVVM?

我剛剛開始學習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上的MouseDoubleClickMouseDoubleClickICommand對象。

<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/zh-CN/details.aspx? FamilyID=f1ae9a30-4928-411d-970b-e682ab179e17&displaylang =en

更新 :我發現了一些可以幫助您的東西。 請查看MVVM Light Toolkit上的此鏈接,其中包含有關如何執行此操作的演練,以及指向所需庫的鏈接 MVVM Light Toolkit是一個非常有趣的框架,用於將MVVM與Silverlight,WPF和WP7一起應用。

希望這可以幫助 :)

由於DoubleClick事件,這變得棘手。 有幾種方法可以做到這一點:

  1. 在后面的代碼中處理雙擊事件,然后在ViewModel上手動調用命令/方法
  2. 使用附加行為將DoubleClick事件路由到您的Command
  3. 使用混合行為將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>

內容可以是任何內容,當單擊控件時,它將執行命令。

編輯:向UserControl添加Background="Transparent"以在控件的整個區域上啟用單擊事件。

這是一個小技巧,但效果很好,並允許您使用命令並避免出現背后的代碼。 這還具有一個額外的好處,即在您的ListBoxItems不會填充整個容器的情況下,在空白ScrollView區域中雙擊(或您的觸發器是什么)時,不觸發命令。

基本上,只要創建一個DataTemplate為你的ListBox ,它由一個中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>

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM