dotnet / maui

.NET MAUI is the .NET Multi-platform App UI, a framework for building native device applications spanning mobile, tablet, and desktop.
https://dot.net/maui
MIT License
22.2k stars 1.75k forks source link

CollectionView is not updating SelectedItems bound property #8435

Open atkinsonline opened 2 years ago

atkinsonline commented 2 years ago

Description

With multiselection for a CollectionView, the bound property for SelectedItems is always null in my viewModel. It works fine for single selection where SelectedItem bound property does get set correctly. I see the same problem in my real all and in James Montemagno's Maui full course. It also shows in a very simple attached app. My main problem is that without this property getting updated, I don't know how to clear selected items from my view model. The selected items do get passed to the SelectedItemChanged command handler (as can be seen in the attached sample) but I have not found a way to use that to clear 1 or all selected items. In my real app, I need to delete the selected items and hence remove the selection. I can remove them from the collection but the CollectionView still keeps the selected items and the selected item count CollectionViewTest1.zip .

Steps to Reproduce

Unzip and run the attached CollectionViewTest1 as a Windows app. I see the same problem in Android. You will see a collection view with a list of fruits Select 1 or more fruits and the output console will show (eg)

Count of selected fruits in parameter = 1 bound property SelectedFruits is NULL

or set a breakpoint in FruitViewModel FruitSelectionChanged to see where these messages come from.
The problem is that SelectedFruits is null

I have seen this in windows and Android but have not tried other platforms.

Version with bug

6.0.400 (current)

Last version that worked well

Unknown/Other

Affected platforms

Android, Windows

Affected platform versions

Windows 11 and Android 11

Did you find any workaround?

No workaround was found but I am a beginner! I would at least like a workaround so I can clear the selected items from my view model. Thank you.

Relevant log output

No response

ghost commented 2 years ago

Hi @atkinsonline. We have added the "s/needs-repro" label to this issue, which indicates that we require steps and sample code to reproduce the issue before we can take further action. Please try to create a minimal sample project/solution or code samples which reproduce the issue, ideally as a GitHub repo that we can clone. See more details about creating repros here: https://github.com/dotnet/maui/blob/main/.github/repro.md

This issue will be closed automatically in 7 days if we do not hear back from you by then - please feel free to re-open it if you come back to this issue after that time.

rachelkang commented 2 years ago

Hi, @atkinsonline - thanks for opening this issue and welcome to the world of .NET MAUI! Please reshare your sample in the form of a GitHub repository so that we can investigate further :)

atkinsonline commented 2 years ago

Thank you for the replies. I did supply steps to reproduce and attached a minimum sample to the original request but I'll work out how I can add the GitHub repro

ghost commented 2 years ago

Hi @atkinsonline. We have added the "s/needs-repro" label to this issue, which indicates that we require steps and sample code to reproduce the issue before we can take further action. Please try to create a minimal sample project/solution or code samples which reproduce the issue, ideally as a GitHub repo that we can clone. See more details about creating repros here: https://github.com/dotnet/maui/blob/main/.github/repro.md

This issue will be closed automatically in 7 days if we do not hear back from you by then - please feel free to re-open it if you come back to this issue after that time.

rachelkang commented 2 years ago

Moving forward, we unfortunately are only able to accept samples in the form of a GitHub repo. Thanks for understanding!

atkinsonline commented 2 years ago

Sorry about that. After my last message, I read that attached zips are not allowed. If I've done this correctly, the code is at

https://github.com/atkinsonline/CollectionViewTest1.git

atkinsonline commented 2 years ago

Hi @rachelkang not sure what the correct protocol is here so not sure if I should tag you to say I added the sample app to GitHub showing the problem, as linked above. John

kristinx0211 commented 2 years ago

verified repo on windows and android with above repro project.

victorsigga commented 2 years ago

Any update in this issue ?

victorsigga commented 2 years ago

I'm having the same problem here

Pnixys commented 2 years ago

I'm facing the same problem here.

ghost commented 2 years ago

We've moved this issue to the Backlog milestone. This means that it is not going to be worked on for the coming release. We will reassess the backlog following the current release and consider this item at that time. To learn more about our issue management process and to have better expectation regarding different types of issues you can read our Triage Process.

atkinsonline commented 2 years ago

That's annoying since nobody has been able to suggest a workaround.

TrevorSquillario commented 1 year ago

Same here. Binding SelectedItems to an ObservableCollection in the ViewModel and it's not being updated. Pre-selection is not working on multi-select either.

TrevorSquillario commented 1 year ago

I got this working using the DevExpress components for Maui and the Maui Community Toolkit using the ObservableObject on my model. Not the best workaround but a workaround until this is fixed.

using CommunityToolkit.Mvvm.ComponentModel;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;

namespace DXMauiApp1
{
    public class Contact : ObservableObject
    {
        string name;
        public string Name
        {
            get => this.name;
            set
            {
                this.name = value;
                if (Photo == null)
                {
                    string resourceName = value.Replace(" ", "").ToLower() + ".jpg";
                    Photo = ImageSource.FromFile(resourceName);
                }
            }
        }

        public Contact(string name, string phone)
        {
            Name = name;
            Phone = phone;
        }
        public ImageSource Photo { get; set; }
        public string Phone { get; set; }
    }

    public class ViewModel : INotifyPropertyChanged
    {
        ObservableCollection<Contact> selectedContacts;
        public ObservableCollection<Contact> SelectedContacts
        {
            get { return selectedContacts; }
            set
            {
                if (selectedContacts != value)
                {
                    selectedContacts = value;
                }
            }
        }
        public ObservableCollection<Contact> Data { get; set; }

        public ViewModel()
        {
            Data = new ObservableCollection<Contact> {
                new Contact("Sirens", "(206) 555-9857"),
                new Contact("Get Tight", "(206) 555-9482"),
                new Contact("Rosie", "(206) 555-3412"),
                new Contact("Joyful Sound", "(206) 555-8122"),
                new Contact("Sweet Spot", "(71) 555-4848"),
                new Contact("Colorado Bluebird Sky", "(71) 555-7773"),
                new Contact("Moonflower", "(71) 555-5598"),
                new Contact("Jellyfish", "(206) 555-1189"),
                new Contact("Texas", "(206) 555-1189"),
                new Contact("Little Hands", "(206) 555-1189"),
                new Contact("Black Clouds", "(206) 555-1189"),
                new Contact("Johnny Cash", "(206) 555-1189"),
                new Contact("Lester Had a Coconut", "(206) 555-1189"),
                new Contact("Mouna Bowa", "(206) 555-1189"),
                new Contact("Birdland", "(206) 555-1189"),
                new Contact("Hey Pocky Way", "(206) 555-11893"),
                new Contact("Smile", "(206) 555-11893"),
                new Contact("Outside and Inside", "(206) 555-11893"),
                new Contact("Miss Brown's Teahouse", "(206) 555-11893"),
                new Contact("Shakin' the Tree", "(206) 555-11893"),
                new Contact("Hi Ho No Show", "(206) 555-11893"),
                new Contact("Best Feeling", "(206) 555-11893"),
                new Contact("Restless Wind", "(206) 555-11893"),
                new Contact("This Must Be the Place", "(206) 555-11893"),
                new Contact("Shine", "(206) 555-11893")
            };
            SelectedContacts = new ObservableCollection<Contact>()
            {
                Data[0], Data[1]
            };
        }

        public event PropertyChangedEventHandler PropertyChanged;
        private void OnPropertyChanged([CallerMemberName] string propertyName = "")
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

https://docs.devexpress.com/MAUI/403377/collection-view/item-selection https://learn.microsoft.com/en-us/dotnet/communitytoolkit/maui https://stackoverflow.com/questions/73425175/net-maui-one-of-the-observablecollection-property-changes-does-not-fire-datatri

jerry08 commented 1 year ago

I found a workaround. SelectedItems uses IList<object> so if I bind the SelectedItems to List<Fruit> as an example, it should work (I guess).. but it doesn't! However, if I do List<object>, it will work. You can then cast the selected items to List<Fruit>. Here's an example:

Not working:

//CollectionView not updating SelectedItems bound property
public ObservableCollection<Fruit> SelectedFruits { get; set; }
...
[RelayCommand]
void FruitSelectionChanged(Fruit items)
{
    List<Fruit> selectedFruits = items.ToList();
}

Workaround:

public ObservableCollection<object> SelectedFruits { get; set; }
...
[RelayCommand]
void FruitSelectionChanged(object items)
{
    List<Fruit> selectedFruits = items.Cast<Fruit>().ToList();
}
Strypper commented 1 year ago

Are you kidding me ? this a very basic scenario, while your team is focus on working the collectionview. This is still not resolved ?

TrevorSquillario commented 1 year ago

I switched to Flutter, MAUI isn't ready for production apps. I'm much happier with my experience.

SokoFromNZ commented 1 year ago

Unbelievable... another important feature not working in CollectionView?! I really regret my choice using MAUI :(

PieEatingNinjas commented 1 year ago

I was facing this issue as well, but I found the following workaround: Binding SelectedItems only seems to work if the IEnumerable of the binding source has object as generic type parameter. So binding to public ObservableCollection<object> SelectedItems{ get; set; } or public List<object> SelectedItems{ get; set; } works.

For example, you can have the following, which works:

ViewModel

public List<UserReviewViewModel> Reviews
{
    get => _reviews;
    private set => SetProperty(ref _reviews, value);
}

public ObservableCollection<object> SelectedReviews { get; } = new();

View

<CollectionView
            ItemsSource="{Binding Reviews}"
            SelectedItems="{Binding SelectedReviews}"
            SelectionMode="Multiple">

Which means, if you want to go and do something with SelectedReviews, you will need to cast them. Not ideal, but it does the trick.

jinxinjuan commented 1 year ago

Verified this issue with Visual Studio Enterprise 17.7.0 Preview 3.0(net8). Can repro on Android platform with sample Project. CollectionViewTest1.zip

benjamin-Keller commented 1 year ago

It's been over a year now, any update on this?

Strypper commented 1 year ago

It's been over a year now, any update on this?

I will give you an update They "choose" to ignore it

Pnixys commented 1 year ago

Yeah I'm pretty disappointed

Vroomer commented 10 months ago

This is expected behavior. As per documentation you are supposed to bind to IList<object> https://learn.microsoft.com/en-us/dotnet/maui/user-interface/controls/collectionview/selection?view=net-maui-8.0

The SelectedItems property data binds to the SelectedMonkeys property of the connected view model, which is of type ObservableCollection. The SelectedMonkeys property is defined in the MonkeysViewModel class, and is set to the second, fourth, and fifth items in the Monkeys collection:

Strypper commented 10 months ago

This is expected behavior. As per documentation you are supposed to bind to IList<object> https://learn.microsoft.com/en-us/dotnet/maui/user-interface/controls/collectionview/selection?view=net-maui-8.0

The SelectedItems property data binds to the SelectedMonkeys property of the connected view model, which is of type ObservableCollection. The SelectedMonkeys property is defined in the MonkeysViewModel class, and is set to the second, fourth, and fifth items in the Monkeys collection:

Ok Boommer You disgusted us (the community), I bet Microsoft put a "dick" inside the framework and you will suck it like a lollipop and scream "Delicious shit"

I don't forget, that's what your mom to me when she low down

symbiogenesis commented 10 months ago

ObservableCollection implements IList<> so it feels like you should be able to use any collection that implements IList.

I just tested and using ObservableCollection<object> works, but you cannot use any other type in the generic type parameter.

It feels like a bug to me. Especially since the single-selection SelectedItem supports using the actual type you need.

Vroomer commented 10 months ago

@terrajobst You might be interested in Strypper's comment here as you have already reprimanded him in this discussion https://github.com/dotnet/maui/discussions/19029#discussioncomment-7685278

Vroomer commented 10 months ago

@symbiogenesis It is not a bug. It's been like this even in Xamarin.Forms and it is stated in documentation as well. However I agree that Binding to generic IList<T> would be much better option.

Strypper commented 10 months ago

@terrajobst You might be interested in Strypper's comment here as you have already reprimanded him in this discussion #19029 (reply in thread)

That's right kid run to your daddy

terrajobst commented 10 months ago

@Strypper I have called you out earlier for CoC violations. Your comments here suggest you're unwilling to adjust your behavior. You're now blocked.

alexanderdibenedetto commented 2 months ago

The casting workaround worked for me! Thanks to those who mentioned it above. This feels like a fix in line with .NET MAUI's "production ready" .NET 8 sentiment. Any chance we'll see it prioritized? I realize this may be considered "working by design" from the docs, but it feels more like "working via workaround."