Le réseau pour les développeurs > Forums - Accueil > Windows Presentation Foundation (WPF) > Click Events for ListView item (aka ListView cell)
Poser une questionPoser une question
 

TraitéeClick Events for ListView item (aka ListView cell)

  • vendredi 25 mai 2007 16:10Jack Cole Médailles de l'utilisateurMédailles de l'utilisateurMédailles de l'utilisateurMédailles de l'utilisateurMédailles de l'utilisateur
     

    Suppose the user clicks a cell in a ListView.  Is there an event that I can handle that will give me the row and column indexes of the cell that was clicked?

     

    It sounds like such a simple thing, but a couple of us have looked at the problem and came up empty handed.

Réponses

  • vendredi 25 mai 2007 19:09Josh SmithMVPMédailles de l'utilisateurMédailles de l'utilisateurMédailles de l'utilisateurMédailles de l'utilisateurMédailles de l'utilisateur
     Traitée

    I came up with this approach, hopefully it will work in your situation.

     

    Code Snippet

    <ListView x:Name="listView" ItemsSource="{Binding}">

     <ListView.View>

      <GridView AllowsColumnReorder="False">

       <GridViewColumn Header="Name">

        <GridViewColumn.CellTemplate>

         <DataTemplate>

          <Border Name="bdrIdx" Grid.Column="0">

           <TextBlock Text="{Binding Name}" />

          </Border>

         </DataTemplate>

        </GridViewColumn.CellTemplate>

       </GridViewColumn>

       <GridViewColumn Header="Age">

        <GridViewColumn.CellTemplate>

         <DataTemplate>

          <Border Name="bdrIdx" Grid.Column="1">

           <TextBlock Text="{Binding Age}" />

          </Border>

         </DataTemplate>

        </GridViewColumn.CellTemplate>

       </GridViewColumn>

      </GridView>

     </ListView.View>

     

     <ListView.ItemContainerStyle>

      <Style TargetType="ListViewItem">

       <!-- Stretch the item content so that hit testing works for the

            entire viewable surface of the ListViewItem. -->

       <Setter Property="HorizontalContentAlignment" Value="Stretch" />

      </Style>

     </ListView.ItemContainerStyle>

    </ListView>

     

     

    void listView_PreviewMouseDown(object sender, MouseButtonEventArgs e)

    {

     Border border;

     ListViewItem lvItem;

      

     if (FindBorderAndListViewItem(

      e.OriginalSource as DependencyObject,

      this.listView,

      out border,

      out lvItem))

     {

      ItemContainerGenerator generator =

        this.listView.ItemContainerGenerator;

      int rowIndex = generator.IndexFromContainer(lvItem);

     

      int columnIndex = Grid.GetColumn(border);

     

      Debug.WriteLine("Row #: " + rowIndex);

      Debug.WriteLine("Col #: " + columnIndex);

     }

    }

     

    static bool FindBorderAndListViewItem(

      DependencyObject elementUnderCursor,

      ListView listVw,

      out Border border,

      out ListViewItem lvItem)

    {

     border = null;

     lvItem = null;

     

     DependencyObject depObj = elementUnderCursor;

     while (depObj != listVw)

     {

      if (border == null && depObj is Border)

      {

       border = depObj as Border;

       // Only reference the named Border.

       if (border.Name != "bdrIdx")

        border = null;

      }

      else if (depObj is ListViewItem)

      {

       lvItem = depObj as ListViewItem;

      }

     

      depObj = VisualTreeHelper.GetParent(depObj);

     }

     

     return border != null && lvItem != null;

    }

     

     HTH!

Toutes les réponses

  • vendredi 25 mai 2007 19:09Josh SmithMVPMédailles de l'utilisateurMédailles de l'utilisateurMédailles de l'utilisateurMédailles de l'utilisateurMédailles de l'utilisateur
     Traitée

    I came up with this approach, hopefully it will work in your situation.

     

    Code Snippet

    <ListView x:Name="listView" ItemsSource="{Binding}">

     <ListView.View>

      <GridView AllowsColumnReorder="False">

       <GridViewColumn Header="Name">

        <GridViewColumn.CellTemplate>

         <DataTemplate>

          <Border Name="bdrIdx" Grid.Column="0">

           <TextBlock Text="{Binding Name}" />

          </Border>

         </DataTemplate>

        </GridViewColumn.CellTemplate>

       </GridViewColumn>

       <GridViewColumn Header="Age">

        <GridViewColumn.CellTemplate>

         <DataTemplate>

          <Border Name="bdrIdx" Grid.Column="1">

           <TextBlock Text="{Binding Age}" />

          </Border>

         </DataTemplate>

        </GridViewColumn.CellTemplate>

       </GridViewColumn>

      </GridView>

     </ListView.View>

     

     <ListView.ItemContainerStyle>

      <Style TargetType="ListViewItem">

       <!-- Stretch the item content so that hit testing works for the

            entire viewable surface of the ListViewItem. -->

       <Setter Property="HorizontalContentAlignment" Value="Stretch" />

      </Style>

     </ListView.ItemContainerStyle>

    </ListView>

     

     

    void listView_PreviewMouseDown(object sender, MouseButtonEventArgs e)

    {

     Border border;

     ListViewItem lvItem;

      

     if (FindBorderAndListViewItem(

      e.OriginalSource as DependencyObject,

      this.listView,

      out border,

      out lvItem))

     {

      ItemContainerGenerator generator =

        this.listView.ItemContainerGenerator;

      int rowIndex = generator.IndexFromContainer(lvItem);

     

      int columnIndex = Grid.GetColumn(border);

     

      Debug.WriteLine("Row #: " + rowIndex);

      Debug.WriteLine("Col #: " + columnIndex);

     }

    }

     

    static bool FindBorderAndListViewItem(

      DependencyObject elementUnderCursor,

      ListView listVw,

      out Border border,

      out ListViewItem lvItem)

    {

     border = null;

     lvItem = null;

     

     DependencyObject depObj = elementUnderCursor;

     while (depObj != listVw)

     {

      if (border == null && depObj is Border)

      {

       border = depObj as Border;

       // Only reference the named Border.

       if (border.Name != "bdrIdx")

        border = null;

      }

      else if (depObj is ListViewItem)

      {

       lvItem = depObj as ListViewItem;

      }

     

      depObj = VisualTreeHelper.GetParent(depObj);

     }

     

     return border != null && lvItem != null;

    }

     

     HTH!

  • lundi 28 mai 2007 21:52Jack Cole Médailles de l'utilisateurMédailles de l'utilisateurMédailles de l'utilisateurMédailles de l'utilisateurMédailles de l'utilisateur
     
    Thanks Josh.  This works great an I think I can use the same technique to do some other things I want to do.
  • lundi 28 mai 2007 22:08Josh SmithMVPMédailles de l'utilisateurMédailles de l'utilisateurMédailles de l'utilisateurMédailles de l'utilisateurMédailles de l'utilisateur
     

    Jack,

     

    Just out of curiosity, why do you need to gain access to the row and column indexes for the "cell" in which the user clicked?  What functionality are you creating which requires that information?  Thanks.

  • mardi 29 mai 2007 12:55Jack Cole Médailles de l'utilisateurMédailles de l'utilisateurMédailles de l'utilisateurMédailles de l'utilisateurMédailles de l'utilisateur
     

    Josh,

     

    We want the user to be able to multiply select cells.  But not all combinations are valid.  The rows represent batches.  Some of the columns represent counts of errors in various categories for the batch.  Other columns represent the name of the batch, the date, type of batch, etc.  The user should be able to multiply select error count cells, but not cells with other kinds of information.  Also they shouldn’t be able to multiply select counts from batches of different types.

     

    When the user selects error count cells we show the individual errors that make up the count in another grid.

  • mardi 29 mai 2007 13:11Josh SmithMVPMédailles de l'utilisateurMédailles de l'utilisateurMédailles de l'utilisateurMédailles de l'utilisateurMédailles de l'utilisateur
     

    Jack,

     

    Very interesting.  Thanks for the explanation.  Good luck with the project.

  • lundi 23 juillet 2007 22:47Aybe81 Médailles de l'utilisateurMédailles de l'utilisateurMédailles de l'utilisateurMédailles de l'utilisateurMédailles de l'utilisateur
     

    Hello,

     

    I've tried to convert it to VB but it doesn't work

     

    I couldn't find a substitute for the "out" keyword in C#,

    and returning both values if not null ...

     

    The two tests in the While loop simply never happens.

     

    Basically what i'm trying to do is,

     

    I implemented a Drag & Drop feature however it does Drag everytime,

    even when i'm not clicking a cell and for example, clicking a scrollbar.

     

    Do you have any idea about what could be wrong with it ?

     

     

    Thanks for your help !

     

     

    Private Sub ListViewMain_PreviewMouseDown(ByVal sender As Object, ByVal e As System.Windows.Input.MouseButtonEventArgs) Handles ListViewMain.PreviewMouseDown

    Dim border As Border

    Dim lvitem As ListViewItem

    If (FindBorderAndListViewItem(e.OriginalSource, ListViewMain, border, lvitem)) Then

    Dim generator As ItemContainerGenerator = ListViewMain.ItemContainerGenerator

    Dim rowindex As Integer = generator.IndexFromContainer(lvitem)

    Dim columnindex As Integer = Grid.GetColumn(border)

    Console.WriteLine("Row #: " + rowindex)

    Console.WriteLine("Col #: " + columnindex)

    End If

     

    End Sub

     

    Private Function FindBorderAndListViewItem(ByVal elementUnderCursor As DependencyObject, ByVal listVw As ListView, ByVal border As Border, ByVal lvitem As ListViewItem) As Boolean

    border = Nothing

    lvitem = Nothing

    Dim depobj As DependencyObject = elementUnderCursor

     

    ' Find parent

    While depobj IsNot listVw

     

    If border Is Nothing AndAlso depobj Is border Then

    border = depobj

    If border.Name <> "bdrIdx" Then border = Nothing

    ElseIf depobj Is lvitem Then

    lvitem = depobj

    End If

    ' Find next parent

    depobj = VisualTreeHelper.GetParent(depobj)

    End While

    'Return True

    End Function

     

  • jeudi 27 décembre 2007 08:38ManjunathV Médailles de l'utilisateurMédailles de l'utilisateurMédailles de l'utilisateurMédailles de l'utilisateurMédailles de l'utilisateur
     
    Hi,

    Can we access the each cell from ListView without clicking on the particular Item or cell?

    I want change the cellTemplate for individual cells. Please tell me how to access the individual cell and apply the style for that particular cell without affecting other cells.



    Warm Regards,
    Manjunath V
  • mercredi 2 juillet 2008 14:00Pdeveloper Médailles de l'utilisateurMédailles de l'utilisateurMédailles de l'utilisateurMédailles de l'utilisateurMédailles de l'utilisateur
     
    Hi, I read your conservation. I am having a question, thought anybody of you solve my problem,
    the sceneario is I have a tree contol and a Listview control. In list view control i have three columns.
    out of three one will be empty. what i need to do is to drag the item from tree and drop it in the third blank column in the listview control? is this possible ? i need to devlope in C# 2005. help me :(

    thanks in adv.
    S/W Devep
  • dimanche 8 novembre 2009 01:57Yuezhong Médailles de l'utilisateurMédailles de l'utilisateurMédailles de l'utilisateurMédailles de l'utilisateurMédailles de l'utilisateur
     A du code
    I have the below solution.
    I have a ListView, has 5 columns, Name, OfficeNumber, MobileNumber, HomeNumber,Email.   I want to determine which number(office,mobile,home) that a user has clicked. 
    The ContactEntry is an object holds the above properties.
    GetContactEntryList returns a ObservableCollection of ContactEntry). 

    <ListView Name="contactsListView" Grid.Row="0" Grid.Column="0" HorizontalAlignment="Stretch" HorizontalContentAlignment="Stretch" Width="320"  Height="320" Visibility="Collapsed"  ItemsSource="{Binding ElementName=This, Path=GetContactEntryList}"  VirtualizingStackPanel.IsVirtualizing="True" VirtualizingStackPanel.VirtualizationMode="Recycling" IsSynchronizedWithCurrentItem="True"  MouseDoubleClick="contactsListView_MouseDoubleClick">
                    <ListView.ItemContainerStyle>
                        <Style TargetType="ListViewItem">
                            <Setter Property="Height" Value="20" />
                        </Style>
                    </ListView.ItemContainerStyle>
                    <ListView.View>
                        <GridView  AllowsColumnReorder="False">
                            <GridViewColumn Width="95" DisplayMemberBinding="{Binding FullName}">
                                <GridViewColumnHeader  Tag="FullName" Content="{StaticResource TEXT_NAME}"/>
                            </GridViewColumn>
                            <GridViewColumn Width="85" DisplayMemberBinding="{Binding OfficePhone}">
                                <GridViewColumnHeader  Tag="OfficePhone" Content="{StaticResource TEXT_OFFICE}"/>
                            </GridViewColumn>
                            <GridViewColumn Width="80" DisplayMemberBinding="{Binding MobilePhone}">
                                <GridViewColumnHeader  Tag="MobilePhone" Content="{StaticResource TEXT_MOBILE}"/>
                            </GridViewColumn>
                            <GridViewColumn Width="Auto"  DisplayMemberBinding="{Binding HomePhone}">
                                <GridViewColumnHeader  Tag="HomePhone" Content="{StaticResource TEXT_HOME}"/>
                            </GridViewColumn>
                            <GridViewColumn Width="Auto"  DisplayMemberBinding="{Binding Email}">
                                <GridViewColumnHeader  Tag="Email" Content="{StaticResource TEXT_EMAIL}"/>
                            </GridViewColumn>
                        </GridView>
                    </ListView.View>
                </ListView>
    

     private void contactsListView_MouseDoubleClick(object sender, MouseButtonEventArgs e)
            {
                object obj = this.contactsListView.SelectedItem;
                if (obj is ContactEntry)
                {
                    NumberType type = GetCallNumberType(this.contactsListView, e.GetPosition(this.contactsListView));
                    if (type != NumberType.UNKNOWN)
                    {
                       //we know which number user clicked
                    }
                }
            }

     public NumberType GetCallNumberType(ListView listView, Point point)
            {
                Decorator border = VisualTreeHelper.GetChild(listView, 0) as Decorator;//Border is the first child of a Listview
                ScrollViewer scroll = border.Child as ScrollViewer;
                point.X = point.X + scroll.ContentHorizontalOffset;
                scroll = null;
                border = null;
                double pStart = 0;
                double pEnd = 0;
                GridView gv = listView.View as GridView;
                for (int i = 0; i < gv.Columns.Count; i++)
                {
                    pEnd = pStart + gv.Columns[i].ActualWidth;
                    if (point.X > pStart && point.X < pEnd)
                    {
                        try
                        {
                            GridViewColumnHeader header = gv.Columns[i].Header as GridViewColumnHeader;
                            if (header != null && header.Tag is string)
                            {
                                string tag = header.Tag as string;
                                header = null;
                                gv = null;
                                if (tag.Equals("OfficePhone"))
                                {
                                    return NumberType.OFFICE_PHONE;
                                }
                                else if (tag.Equals("MobilePhone"))
                                {
                                   return NumberType.MOBILE_PHONE;
                                }
                                else if (tag.Equals("HomePhone"))
                                {
                                    return NumberType.HOME_PHONE;
                                }
                                else
                                {
                                    return NumberType.UNKNOWN;
                                }
                            }
                          
                        }
                        catch (Exception)
                        {
                            return NumberType.UNKNOWN;
                        }
                    }
                    pStart = pEnd;
                }
                return NumberType.UNKNOWN;
            }
    


    The important section is 
                Decorator border = VisualTreeHelper.GetChild(listView, 0) as Decorator;//Border is the first child of a Listview
                ScrollViewer scroll = border.Child as ScrollViewer;
                point.X = point.X + scroll.ContentHorizontalOffset;
                scroll = null;
                border = null;
                double pStart = 0;
                double pEnd = 0;
                GridView gv = listView.View as GridView;
                for (int i = 0; i < gv.Columns.Count; i++)
                {
                    pEnd = pStart + gv.Columns[i]. ActualWidth;<br/>                if (point.X > pStart && point.X < pEnd)
                    {
                        //this was clicked
                    }
                }
    
    

    If you don't use the code below, when the column resize too wide, you will not able to detect the correct column.
            Decorator border = VisualTreeHelper.GetChild(listView, 0) as Decorator;//Border is the first child of a Listview
                ScrollViewer scroll = border.Child as ScrollViewer;
                point.X = point.X + scroll.ContentHorizontalOffset;


    Hope this can help anyone out there need a solution.