Forum Xamarin.Forms

How to bind collection view selected items into a new listview using MVVM?

matheuspacificimatheuspacifici Member ✭✭
edited June 2020 in Xamarin.Forms

I have the following observableCollection:
Main View Model:

MainViewModel : INotifyProperyChanged
 public MainViewModel()
{
Accessories = new ObservableCollection<string>();
            Accessories.Add("Cast");
              Accessories.Add("Neck Ring");
             Accessories.Add("Shoulder Wedges");
            Accessories.Add("Grip Rings");
            Accessories.Add("Head Rest");
            Accessories.Add("Knee Roll");
            Accessories.Add("Elbow Sling");
             Accessories.Add("Thermoplastic Mask");
            Accessories.Add("Vacuum Lock Bags");
            Accessories.Add("Breast Board");
}

 public ObservableCollection<string> selectedAccessories = new ObservableCollection<string>();
        public ObservableCollection<string> SelectedAccessories
        {
            get => selectedAccessories;
            set
            {
                if (selectedAccessories == value)
                    return;
                else
                {
                    selectedAccessories = value;
                    OnPropertyChanged(nameof(SelectedAccessories));

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

Then on the XAML Side:

    <CollectionView ItemsSource="{Binding Accessories}" SelectionMode="Multiple" SelectedItems="{Binding SelectedAccessories}" />

    <Label x:Name="label1" Text="{Binding SelectedAccessories}"  />

    <ListView x:Name="list1" ItemsSource="{Binding SelectedAccessories}"  />

I would like to display in either a label or listview (both work). Now, Selected Accessories is an observable collection that would need to be the ItemsSource for the new list.

I also tried a different PropertyChanged method and it still doesn't work:

public event PropertyChangedEventHandler PropertyChanged;
        publicvoid OnPropertyChanged2(ObservableCollection<string> selectedAccessories)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(selectedAccessories.ToString()));
        }

The same structure work for other data types but I can't make it work for ObservableCollections. Do I need to create a method to retrieve the strings of the selected items? How can I access the selectedItems?

Answers

  • jezhjezh Member, Xamarin Team Xamurai

    I couldn't see the whole code of yours, but after I tested page VerticalListMultiplePreSelectionPage.xaml of the sample code and added a listview to display the selected Items (SelectedMonkeys) , it works properly.

    The bind model is MonkeysViewModel.cs and the main code is:

       public class MonkeysViewModel : INotifyPropertyChanged
        {
            readonly IList<Monkey> source;
            Monkey selectedMonkey;
            int selectionCount = 1;
    
            public ObservableCollection<Monkey> Monkeys { get; private set; }
            public IList<Monkey> EmptyMonkeys { get; private set; }
    
            public Monkey SelectedMonkey
            {
                get
                {
                    return selectedMonkey;
                }
                set
                {
                    if (selectedMonkey != value)
                    {
                        selectedMonkey = value;
                    }
                }
            }
    
            ObservableCollection<object> selectedMonkeys;
            public ObservableCollection<object> SelectedMonkeys
            {
                get
                {
                    return selectedMonkeys;
                }
                set
                {
                    if (selectedMonkeys != value)
                    {
                        selectedMonkeys = value;
                    }
                }
            }
    
            public string SelectedMonkeyMessage { get; private set; }
    
            public MonkeysViewModel()
            {
                source = new List<Monkey>();
                CreateMonkeyCollection();
    
                selectedMonkey = Monkeys.Skip(3).FirstOrDefault();
                MonkeySelectionChanged();
    
                SelectedMonkeys = new ObservableCollection<object>()
                {
                    Monkeys[1], Monkeys[3], Monkeys[4]
                };
            }
    
            void CreateMonkeyCollection()
            {
                source.Add(new Monkey
                {
                    Name = "Baboon",
                    Location = "Africa & Asia",
                    Details = "Baboons are African and Arabian Old World monkeys belonging to the genus Papio, part of the subfamily Cercopithecinae.",
                    ImageUrl = "http://upload.wikimedia.org/wikipedia/commons/thumb/f/fc/Papio_anubis_%28Serengeti%2C_2009%29.jpg/200px-Papio_anubis_%28Serengeti%2C_2009%29.jpg"
                });
    
                source.Add(new Monkey
                {
                    Name = "Capuchin Monkey",
                    Location = "Central & South America",
                    Details = "The capuchin monkeys are New World monkeys of the subfamily Cebinae. Prior to 2011, the subfamily contained only a single genus, Cebus.",
                    ImageUrl = "http://upload.wikimedia.org/wikipedia/commons/thumb/4/40/Capuchin_Costa_Rica.jpg/200px-Capuchin_Costa_Rica.jpg"
                });       
    
                Monkeys = new ObservableCollection<Monkey>(source);
            }
    
            void FilterItems(string filter)
            {
                var filteredItems = source.Where(monkey => monkey.Name.ToLower().Contains(filter.ToLower())).ToList();
                foreach (var monkey in source)
                {
                    if (!filteredItems.Contains(monkey))
                    {
                        Monkeys.Remove(monkey);
                    }
                    else
                    {
                        if (!Monkeys.Contains(monkey))
                        {
                            Monkeys.Add(monkey);
                        }
                    }
                }
            }
    
            void MonkeySelectionChanged()
            {
                SelectedMonkeyMessage = $"Selection {selectionCount}: {SelectedMonkey.Name}";
                OnPropertyChanged("SelectedMonkeyMessage");
                selectionCount++;
            }
    
            void RemoveMonkey(Monkey monkey)
            {
                if (Monkeys.Contains(monkey))
                {
                    Monkeys.Remove(monkey);
                }
            }
    
            void FavoriteMonkey(Monkey monkey)
            {
                monkey.IsFavorite = !monkey.IsFavorite;
            }
    
            #region INotifyPropertyChanged
            public event PropertyChangedEventHandler PropertyChanged;
    
            void OnPropertyChanged([CallerMemberName] string propertyName = null)
            {
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
            }
            #endregion
        }
    

    The tested xaml is:

    <StackLayout Margin="20">
            <Button  Text="get selected nums" Clicked="Button_Clicked" />
            <CollectionView x:Name="collectionView"
                            ItemsSource="{Binding Monkeys}"
                            SelectionMode="Multiple"
                            SelectedItems="{Binding SelectedMonkeys}">
                <CollectionView.ItemTemplate>
                    <DataTemplate>
                        <Grid Padding="10">
                            <Grid.RowDefinitions>
                                <RowDefinition Height="Auto" />
                                <RowDefinition Height="Auto" />
                            </Grid.RowDefinitions>
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="Auto" />
                                <ColumnDefinition Width="Auto" />
                            </Grid.ColumnDefinitions>
                            <Image Grid.RowSpan="2" 
                                   Source="{Binding ImageUrl}" 
                                   Aspect="AspectFill"
                                   HeightRequest="60" 
                                   WidthRequest="60" />
                            <Label Grid.Column="1" 
                                   Text="{Binding Name}" 
                                   FontAttributes="Bold" />
                            <Label Grid.Row="1"
                                   Grid.Column="1" 
                                   Text="{Binding Location}"
                                   FontAttributes="Italic" 
                                   VerticalOptions="End" />
                        </Grid>
                    </DataTemplate>
                </CollectionView.ItemTemplate>
            </CollectionView>
    
    
            <ListView  x:Name="lstView" RowHeight="60" ItemsSource="{Binding SelectedMonkeys}" >
                <ListView.ItemTemplate>
                    <DataTemplate>
                        <ViewCell>
                            <StackLayout Orientation="Horizontal" HorizontalOptions="Fill" BackgroundColor="Olive">
                                <StackLayout Orientation="Vertical">
                                    <Label Text = "{Binding Name}" FontSize="24" AbsoluteLayout.LayoutBounds="0.25, 0.25, 400, 40"/>
                                    <Label Text = "{Binding Location}" AbsoluteLayout.LayoutBounds="50, 35, 200, 25"/>
                                </StackLayout>
                                <Image Source="{Binding ImageUrl}" HorizontalOptions="End" AbsoluteLayout.LayoutBounds="250.25, 0.25, 50, 50 "/>
                            </StackLayout>
                        </ViewCell>
                    </DataTemplate>
                </ListView.ItemTemplate>
            </ListView>
        </StackLayout>
    

    The result is:

  • jezhjezh Member, Xamarin Team Xamurai

    Hi @matheuspacifici,have you resolved your question?

Sign In or Register to comment.