locked
Get the selected item in a list view button RRS feed

  • Question

  • User71687 posted

    I am trying to get the selected item in the tap event of a button in a list view item, but I can't seem to figure it out. Anyone know how to accomplish this?

    Monday, April 20, 2015 12:22 AM

All replies

  • User181 posted

    This is one of the situations in which you really need to understand how MVVM works. A ListView's ItemsSource property refers to a list of view models for each item, and the cell should use bindings to the properties in that item view model. A button within the cell should also use a binding to a command. A command is a way of handling an event in a view model by using a binding to inject the handler into the view. The way it works is this: in the view model you define a new property of type ICommand, which might look like this:

        private Command _clickCommand;
    
        public ICommand ClickCommand
        {
            get
            {
                if (_clickCommand == null)
                {
                    _clickCommand = new Command(() => ClickCount++);
                }
    
                return _clickCommand;
            }
        }
    

    Then in your view, instead of using the Clicked event for the button you use the Command property, and you use a binding like this:

                            <Button Text="Click" Command="{Binding ClickCommand}" />
    

    When that button is clicked it will call handler for the command specific to that particular instance of the item view model type, and you can directly modify the state of that item from the handler.

    A complete example is attached, and you can read more here.

    Monday, April 20, 2015 2:28 AM
  • User71687 posted

    @adamkemp I'm looking into doing it with a command as you said. Is there no way to pass a binding context to the button or something along those lines though?

    Monday, April 20, 2015 5:41 PM
  • User181 posted

    The button has a binding context, which it inherits from its parent. Ultimately the binding context comes from the item in ItemsSource for that cell.

    Monday, April 20, 2015 7:43 PM
  • User71687 posted

    So say I have a list of users and I want to access the selected user when the user clicks a button on that list item. How would I access the selected user (item) in the tap event?

    Tuesday, April 21, 2015 6:13 PM
  • User71687 posted

    I keep trying this.BindingContext in the tap event, but it says Object reference not set to an instance of object.

    Tuesday, April 21, 2015 6:15 PM
  • User181 posted

    It seems like you didn't look at the example I attached. Please look at that.

    You don't use an event for this. You use the command, which is itself a binding to the view model. In the context of your user example, the handler for the command would be in the UserViewModel class. If you're trying to put an event handler in your view or page class then you're going down the wrong path.

    Tuesday, April 21, 2015 6:23 PM
  • User71687 posted

    I looked through the example, but it's very different than the code i've been using so I was trying to avoid going that route. Most of my code has events in the code behind like all the Xamarin examples etc. What i'm confused about is that I need to have an Xlabs popup open when the button is clicked and it seems odd to do it with a command in the view model, but i'll give it a shot.

    Thanks for getting back to me so quick btw and sorry for being a little slow at this. I'm new to Xamarin and C# and the whole view model command thing is odd and not documented well in the Xamarin examples.

    Tuesday, April 21, 2015 6:34 PM
  • User181 posted

    Most of my code has events in the code behind like all the Xamarin examples etc

    Yeah, it's a shame most of the examples avoid MVVM (because it's complicated) because in a case like this you really need to use MVVM, and a lot of people get stuck in the exact same situation you're in now.

    Tuesday, April 21, 2015 6:36 PM
  • User83388 posted

    Yes, MVVM is better. But, to answer your question, if you are using the ListView.ItemTapped event, the ItemTappedEventArgs has an Item property that passes along the visual item that was tapped. Cast it to the correct type.

    private void ListViewItemTapped(object sender, ItemTappedEventArgs e)
    {
        var user = e.Item as User;
    }
    

    If you are instead using a Button.Clicked event for a button in a cell in the ListView, you'll have to cast the sender to a Button and get the user from the buttons BindingContext.

    private void ButtonClicked(object sender, EventArgs e)
    {
        var button = sender as Button;
        var user = button.BindingContext as User;
        //Perform actions on user
    }
    
    Tuesday, April 21, 2015 9:12 PM
  • User71687 posted

    @LeeOlsen.3738 That's exactly what I was trying to do. Thanks!!

    @adamkemp I went with Lee's suggestion for now. MVVM is a bit odd for me since I come from a Ruby/Rails background. I'm use to MVC and the whole view/view model thing seems a bit redundant to me when you have a code behind file. Thanks for all your help though. I am going to look through your code more and start trying to convert things to be more MVVM as I get a better grasp on it.

    Tuesday, April 21, 2015 11:20 PM
  • User351573 posted

    @"LeeOlsen.5615" said: Yes, MVVM is better. But, to answer your question, if you are using the ListView.ItemTapped event, the ItemTappedEventArgs has an Item property that passes along the visual item that was tapped. Cast it to the correct type.

    private void ListViewItemTapped(object sender, ItemTappedEventArgs e)
    {
      var user = e.Item as User;
    }
    

    If you are instead using a Button.Clicked event for a button in a cell in the ListView, you'll have to cast the sender to a Button and get the user from the buttons BindingContext.

    private void ButtonClicked(object sender, EventArgs e)
    {
      var button = sender as Button;
      var user = button.BindingContext as User;
      //Perform actions on user
    }
    

    I am using the Button.clicked event and do like above. But getting "System.NullReferenceException: Object reference not set to an instance of an object" on the user actions lines.

    My code: Button inside listview-viewcell

                   <Button
                            BorderRadius="25"
                            HeightRequest="40"
                            WidthRequest="150"
                            TextColor="White"
                             HorizontalOptions="CenterAndExpand"
                             Font="Bold,15"
                             Margin="0,0,0,5"
                             BackgroundColor="#004F7E" 
                            Clicked="MoreDetails"
                             Text="More Details"/> 
    

    Button clicked event:

     public void MoreDetails(Object sender, EventArgs args)
        {
            var button = sender as Button;
            var userProfileTO = button.BindingContext as UserProfileTO;
            Debug.WriteLine("Datas:>>" + userProfileTO.title);
            Debug.WriteLine("Datas1:>>" + userProfileTO);
        }
    

    Any suggestions? :)

    Monday, January 8, 2018 5:39 AM
  • User181 posted

    Most likely this expression is returning null: button.BindingContext as UserProfileTO. That either means the BindingContext is null or it isn’t the expected type. You’ll have to debug it to determine which.

    Friday, January 12, 2018 10:56 PM
  • User343509 posted

    Hello @LeeOlsen.5615,

    Your solution work for me :smiley:

    `Yes, MVVM is better. But, to answer your question, if you are using the ListView.ItemTapped event, the ItemTappedEventArgs has an Item property that passes along the visual item that was tapped. Cast it to the correct type.

    private void ListViewItemTapped(object sender, ItemTappedEventArgs e) { var user = e.Item as User; } If you are instead using a Button.Clicked event for a button in a cell in the ListView, you'll have to cast the sender to a Button and get the user from the buttons BindingContext.

    private void ButtonClicked(object sender, EventArgs e) { var button = sender as Button; var user = button.BindingContext as User; //Perform actions on user } `

    Tuesday, October 16, 2018 9:41 AM