65

データバインドされたアイテムのリストを表示するWPFListViewコントロールを使用しています。

<ListView ItemsSource={Binding MyItems}>
    <ListView.View>
        <GridView>
            <!-- declare a GridViewColumn for each property -->
        </GridView>
    </ListView.View>
</ListView>

イベントと同様の動作を取得しようとしていListView.SelectionChangedますが、現在選択されているアイテムがクリックされたかどうかも検出したいだけです。同じアイテムをもう一度クリックしても、SelectionChangedイベントは発生しません(明らかに)。

これにアプローチするための最良の(最もクリーンな)方法は何でしょうか?

4

7 に答える 7

91

ListView.ItemContainerStyleプロパティを使用して、ListViewItemsにPreviewMouseLeftButtonDownイベントを処理するEventSetterを指定します。次に、ハンドラーで、クリックされたアイテムが選択されているかどうかを確認します。

XAML:

<ListView ItemsSource={Binding MyItems}>
    <ListView.View>
        <GridView>
            <!-- declare a GridViewColumn for each property -->
        </GridView>
    </ListView.View>
    <ListView.ItemContainerStyle>
        <Style TargetType="ListViewItem">
            <EventSetter Event="PreviewMouseLeftButtonDown" Handler="ListViewItem_PreviewMouseLeftButtonDown" />
        </Style>
    </ListView.ItemContainerStyle>
</ListView>

コードビハインド:

private void ListViewItem_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
    var item = sender as ListViewItem;
    if (item != null && item.IsSelected)
    {
        //Do your stuff
    }
}
于 2012-04-18T22:41:27.860 に答える
28

ListViewのPreviewMouseLeftButtonUpイベントを処理できます。PreviewMouseLeftButtonDownイベントを処理しない理由は、イベントを処理するときまでに、ListViewのSelectedItemがまだnullである可能性があるためです。

XAML:

<ListView ... PreviewMouseLeftButtonUp="listView_Click"> ...

背後にあるコード:

private void listView_Click(object sender, RoutedEventArgs e)
{
    var item = (sender as ListView).SelectedItem;
    if (item != null)
    {
        ...
    }
}
于 2013-12-06T23:25:40.887 に答える
19

これらはすべて素晴らしい提案ですが、私があなたなら、ビューモデルでこれを行います。ビューモデル内で、アイテムテンプレートのクリックイベントにバインドできるリレーコマンドを作成できます。同じアイテムが選択されたかどうかを判断するために、選択したアイテムへの参照をビューモデルに保存できます。バインディングを処理するためにMVVMLightを使用するのが好きです。これにより、プロジェクトを将来変更するのがはるかに簡単になり、Blendでバインディングを設定できるようになります。

すべてが語られて完了すると、XAMLはSergeyが提案したもののようになります。私はあなたの見解でコードビハインドを使用することを避けます。そこにはたくさんの例があるので、この回答でコードを書くことは避けます。

これが1つです: MVVMLightフレームワークでRelayCommandを使用する方法

例が必要な場合はコメントしてください。追加します。

〜乾杯

私は例をするつもりはないと言いましたが、私はそうです。どうぞ。

  1. プロジェクトに、MVVMライトライブラリのみを追加します。

  2. ビューのクラスを作成します。一般的に、ビューごとにビューモデルがあります(ビュー:MainWindow.xaml && viewModel:MainWindowViewModel.cs)

  3. 非常に、非常に、非常に基本的なビューモデルのコードは次のとおりです。

含まれているすべての名前空間(ここに表示されている場合は、既にそれらへの参照を追加していると想定しています。MVVMLightはNugetにあります)

using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.CommandWpf;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

次に、基本的なパブリッククラスを追加します。

/// <summary>
/// Very basic model for example
/// </summary>
public class BasicModel 
{
    public string Id { get; set; }
    public string Text { get; set; }

    /// <summary>
    /// Constructor
    /// </summary>
    /// <param name="text"></param>
    public BasicModel(string text)
    {
        this.Id = Guid.NewGuid().ToString();
        this.Text = text;
    }
}

次に、ビューモデルを作成します。

public class MainWindowViewModel : ViewModelBase
{
    public MainWindowViewModel()
    {
        ModelsCollection = new ObservableCollection<BasicModel>(new List<BasicModel>() {
            new BasicModel("Model one")
            , new BasicModel("Model two")
            , new BasicModel("Model three")
        });
    }

    private BasicModel _selectedBasicModel;

    /// <summary>
    /// Stores the selected mode.
    /// </summary>
    /// <remarks>This is just an example, may be different.</remarks>
    public BasicModel SelectedBasicModel 
    {
        get { return _selectedBasicModel; }
        set { Set(() => SelectedBasicModel, ref _selectedBasicModel, value); }
    }

    private ObservableCollection<BasicModel> _modelsCollection;

    /// <summary>
    /// List to bind to
    /// </summary>
    public ObservableCollection<BasicModel> ModelsCollection
    {
        get { return _modelsCollection; }
        set { Set(() => ModelsCollection, ref _modelsCollection, value); }
    }        
}

ビューモデルに、relayコマンドを追加します。これを非同期にして、パラメーターを渡してもらうことに注意してください。

    private RelayCommand<string> _selectItemRelayCommand;
    /// <summary>
    /// Relay command associated with the selection of an item in the observablecollection
    /// </summary>
    public RelayCommand<string> SelectItemRelayCommand
    {
        get
        {
            if (_selectItemRelayCommand == null)
            {
                _selectItemRelayCommand = new RelayCommand<string>(async (id) =>
                {
                    await selectItem(id);
                });
            }

            return _selectItemRelayCommand;
        }
        set { _selectItemRelayCommand = value; }
    }

    /// <summary>
    /// I went with async in case you sub is a long task, and you don't want to lock you UI
    /// </summary>
    /// <returns></returns>
    private async Task<int> selectItem(string id)
    {
        this.SelectedBasicModel = ModelsCollection.FirstOrDefault(x => x.Id == id);
        Console.WriteLine(String.Concat("You just clicked:", SelectedBasicModel.Text));
        //Do async work

        return await Task.FromResult(1);
    }

ビューの背後にあるコードで、ビューモデルのプロパティを作成し、ビューのデータコンテキストをビューモデルに設定します(これを行う方法は他にもありますが、これを簡単な例にしようとしています)。

public partial class MainWindow : Window
{
    public MainWindowViewModel MyViewModel { get; set; }
    public MainWindow()
    {
        InitializeComponent();

        MyViewModel = new MainWindowViewModel();
        this.DataContext = MyViewModel;
    }
}

XAMLでは、コードの先頭にいくつかの名前空間を追加する必要があります

<Window x:Class="Basic_Binding.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
    xmlns:Custom="clr-namespace:GalaSoft.MvvmLight;assembly=GalaSoft.MvvmLight"
    Title="MainWindow" Height="350" Width="525">

「i」と「Custom」を追加しました。

ListViewは次のとおりです。

<ListView 
        Grid.Row="0" 
        Grid.Column="0" 
        HorizontalContentAlignment="Stretch"
        ItemsSource="{Binding ModelsCollection}"
        ItemTemplate="{DynamicResource BasicModelDataTemplate}">
    </ListView>

ListViewのItemTemplateは次のとおりです。

<DataTemplate x:Key="BasicModelDataTemplate">
        <Grid>
            <TextBlock Text="{Binding Text}">
                <i:Interaction.Triggers>
                    <i:EventTrigger EventName="MouseLeftButtonUp">
                        <i:InvokeCommandAction 
                            Command="{Binding DataContext.SelectItemRelayCommand, 
                                RelativeSource={RelativeSource FindAncestor, 
                                        AncestorType={x:Type ItemsControl}}}"
                            CommandParameter="{Binding Id}">                                
                        </i:InvokeCommandAction>
                    </i:EventTrigger>
                </i:Interaction.Triggers>
            </TextBlock>
        </Grid>
    </DataTemplate>

アプリケーションを実行し、出力ウィンドウを確認します。コンバーターを使用して、選択したアイテムのスタイリングを処理できます。

これは非常に複雑に見えるかもしれませんが、ビューをViewModelから分離する必要がある場合(たとえば、複数のプラットフォーム用のViewModelを開発する場合)、将来の作業がはるかに簡単になります。さらに、Blend10xでの作業が簡単になります。ViewModelを開発したら、それを非常に芸術的に見せることができるデザイナーに渡すことができます:)。MVVM Lightは、BlendにViewModelを認識させるためのいくつかの機能を追加します。ほとんどの場合、ViewModelでビューに影響を与えるために必要なことはほぼすべて実行できます。

誰かがこれを読んだら、これがお役に立てば幸いです。ご不明な点がございましたら、お気軽にお問い合わせください。この例ではMVVMLightを使用しましたが、MVVMLightがなくてもこれを行うことができます。

于 2015-04-27T00:44:52.767 に答える
6

次のようにリストビューアイテムのクリックを処理できます。

<ListView.ItemTemplate>
  <DataTemplate>
     <Button BorderBrush="Transparent" Background="Transparent" Focusable="False">
        <i:Interaction.Triggers>
                <i:EventTrigger EventName="Click">
                    <i:InvokeCommandAction Command="{Binding DataContext.MyCommand, ElementName=ListViewName}" CommandParameter="{Binding}"/>
                </i:EventTrigger>
        </i:Interaction.Triggers>
      <Button.Template>
      <ControlTemplate>
         <Grid VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
    ...
于 2015-04-03T09:14:12.523 に答える
2

これは私のために働いた。

行をシングルクリックすると、コードビハインドがトリガーされます。

XAML:

<ListView x:Name="MyListView" MouseLeftButtonUp="MyListView_MouseLeftButtonUp">
    <GridView>
        <!-- Declare GridViewColumns. -->
    </GridView>
</ListView.View>

コードビハインド:

private void MyListView_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
    System.Windows.Controls.ListView list = (System.Windows.Controls.ListView)sender;
    MyClass selectedObject = (MyClass)list.SelectedItem;
    // Do stuff with the selectedObject.
}
于 2019-08-01T16:12:53.997 に答える
0

また、クリックされたアイテムの選択を解除して、MouseDoubleClickイベントを使用することをお勧めします

private void listBox_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{
    try {
        //Do your stuff here
        listBox.SelectedItem = null;
        listBox.SelectedIndex = -1;
    } catch (Exception ex) {
        System.Diagnostics.Debug.WriteLine(ex.Message);
    }
}
于 2018-12-29T14:12:56.407 に答える
0

受け入れられた答えを私が望むように機能させることができませんでした(Farrukhのコメントを参照)。

マウスボタンを押した状態でアイテムを選択し、マウスボタンを離したときにそれに反応できるため、少しネイティブな感じのソリューションを思いつきました。

XAML:

<ListView Name="MyListView" ItemsSource={Binding MyItems}>
<ListView.ItemContainerStyle>
    <Style TargetType="ListViewItem">
        <EventSetter Event="PreviewMouseLeftButtonDown" Handler="ListViewItem_PreviewMouseLeftButtonDown" />
        <EventSetter Event="PreviewMouseLeftButtonUp" Handler="ListViewItem_PreviewMouseLeftButtonUp" />
    </Style>
</ListView.ItemContainerStyle>

背後にあるコード:

private void ListViewItem_PreviewMouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
    MyListView.SelectedItems.Clear();

    ListViewItem item = sender as ListViewItem;
    if (item != null)
    {
        item.IsSelected = true;
        MyListView.SelectedItem = item;
    }
}

private void ListViewItem_PreviewMouseLeftButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
    ListViewItem item = sender as ListViewItem;
    if (item != null && item.IsSelected)
    {
        // do stuff
    }
}
于 2019-04-06T18:34:26.233 に答える