How do i add an item from one collection view while also removing an item from another collection view

MysticsDen 70 Reputation points
2023-03-01T08:45:26.48+00:00

I want to take the code from my store page and add them to my emotes page I attempted to make an event but I don't believe I am invoking it correctly. Also, I don't know what commands I should be useing to add and remove from the collection view!

This code is where the event is coming from to get the data to add to another collection view

    public partial class Store : TabbedPage
    {
        public event EventHandler<StoreEventArgs> AddEmoteEvent;
        public class StoreEventArgs : EventArgs
        {
            private readonly string customString;
            public StoreEventArgs(string customString)
            {
                this.customString = customString;
            }
            public string CustomString
            {
                get { return this.customString; }
            }
        }
        ObservableCollection<StorePage_Emotes_> storeEmotes;
        public Store()
        {

            InitializeComponent();
            storeEmotes = new ObservableCollection<StorePage_Emotes_>
                            {
                 new StorePage_Emotes_ {Name ="No Icon", Image="Achievement_Frame.png", Category= StorePage_Emotes_.Group.Emote, Cost="3.99"},
                 new StorePage_Emotes_ {Name ="No Icon", Image="Achievement_Frame.png", Category= StorePage_Emotes_.Group.Emote, Cost="3.99"},
                 new StorePage_Emotes_ {Name ="No Icon", Image="Achievement_Frame.png", Category= StorePage_Emotes_.Group.Emote, Cost="3.99"},
                 new StorePage_Emotes_ {Name ="No Icon", Image="Achievement_Frame.png", Category= StorePage_Emotes_.Group.Emote, Cost="3.99"},
                 new StorePage_Emotes_ {Name ="No Icon", Image="Achievement_Frame.png", Category= StorePage_Emotes_.Group.Emote, Cost="3.99"}

        };
            StoreEmotesView.ItemsSource= storeEmotes;
        }

         private async void StoreEmotesView_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            var StoreEmoteSelected = e.CurrentSelection[0] as StorePage_Emotes_;
            string Name = StoreEmoteSelected.Name;
            string Image = StoreEmoteSelected.Image;
            string Cost = StoreEmoteSelected.Cost;
            Navigation.ShowPopup(new StorePopup(Name, Image, Cost));
            AddEmoteEvent?.Invoke(this, new StoreEventArgs(Image));
        }
        
    }
// This is the code that i want it to go to

        public EmotesPage()
        {
            InitializeComponent();
            emotes = new ObservableCollection<EmotesModel>
            {
                new EmotesModel {Image="Achievement_Frame.png"},
                new EmotesModel {Image="Police_Icon.png", },
                new EmotesModel {Image="Danger_Icon.png"},
                new EmotesModel {Image="Danger_Icon.png", },
                new EmotesModel {Image="Danger_Icon.png"},

        };
            EmotesView.ItemsSource = emotes;
        }
Developer technologies .NET Xamarin
Developer technologies XAML
Developer technologies C#
{count} votes

Accepted answer
  1. Yonglun Liu (Shanghai Wicresoft Co,.Ltd.) 50,126 Reputation points Microsoft External Staff
    2023-03-16T07:36:49.7833333+00:00

    Hello,

    Through in-depth investigation and official documentation, it is more recommended that this function be easily achieved by binding the same ViewModel to two pages by using the MVVM design method of singleton mode, and the call logic is clear.

    Please refer to the following documentation and code samples:

    ViewModel:

    public class BaseViewModel : INotifyPropertyChanged
    {
        // create a sington instance.
        private static BaseViewModel instance = null;
        public static BaseViewModel Instance
        {
            get
            {
                if (instance == null)
                {
                    instance = new BaseViewModel();
                }
                return instance;
            }
        }
        public event PropertyChangedEventHandler PropertyChanged;
        bool SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyName = null)
        {
            if (Object.Equals(storage, value))
                return false;
    
           storage = value;
            OnPropertyChanged(propertyName);
            return true;
        }
    
       protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
        private ObservableCollection<StorePage_Emotes_> storeEmotes;
        private ObservableCollection<EmotesModel> emotes;
        private StorePage_Emotes_ selectedItem;
        public StorePage_Emotes_ SelectedItem
        {
            get { return selectedItem; }
            set
            {
                selectedItem = value;
                OnPropertyChanged(nameof(SelectedItem));
            }
        }
        public ObservableCollection<EmotesModel> Emotes
        {
            get { return emotes; }
            set
            {
                emotes = value;
                OnPropertyChanged(nameof(Emotes));
            }
        }
        public ObservableCollection<StorePage_Emotes_> StoreEmotes
        {
            get { return storeEmotes; }
            set
            {
                storeEmotes = value;
                OnPropertyChanged(nameof(StoreEmotes));
            }
        }
    
       public ICommand MigrationCommand { get; }
        private async void Migration()
        {
            // add an item from one collection view while also removing an item from another collection
    	// popup your page in this method.
            StoreEmotes.Remove(selectedItem);
            Emotes.Add(new EmotesModel { Image = selectedItem.Image });
       }
        public BaseViewModel()
        {
            StoreEmotes = new ObservableCollection<StorePage_Emotes_>{
                     new StorePage_Emotes_ {Name ="No Icon1", Image="dotnet_bot.png"},
                     new StorePage_Emotes_ {Name ="No Icon2", Image="dotnet_bot.png"},
                     new StorePage_Emotes_ {Name ="No Icon3", Image="dotnet_bot.png"},
                     new StorePage_Emotes_ {Name ="No Icon4", Image="dotnet_bot.png"},
                     new StorePage_Emotes_ {Name ="No Icon5", Image="dotnet_bot.png"}};
            Emotes = new ObservableCollection<EmotesModel>();
            Emotes.Add(new EmotesModel { Image = "dotnet_bot.png" });
            MigrationCommand = new Command(Migration);
        }
    }
    

    Then, you could bind the viewmodel instance in the code behind of pages.

    BindingContext = BaseViewModel.Instance;
    

    Data binding in your two collectionviews:

    StoreEmotes CollectionView:

    <VerticalStackLayout>
        <CollectionView ItemsSource="{Binding StoreEmotes}"
                            SelectedItem="{Binding SelectedItem}"
                            SelectionMode="Single"
                            SelectionChangedCommand="{Binding MigrationCommand}">
            <CollectionView.ItemTemplate>
                <DataTemplate>
                    <StackLayout>
                        <Label Text="{Binding Name}"/>
                        <Image Source="{Binding Image}"/>
                    </StackLayout>
                </DataTemplate>
            </CollectionView.ItemTemplate>
        </CollectionView>
    </VerticalStackLayout>
    

    Emotes CollectionView:

    <VerticalStackLayout>
        <CollectionView ItemsSource="{Binding Emotes}">
            <CollectionView.ItemTemplate>
                <DataTemplate>
                    <StackLayout>
                        <Image Source="{Binding Image}"/>
                    </StackLayout>
                </DataTemplate>
            </CollectionView.ItemTemplate>
        </CollectionView>
    </VerticalStackLayout>
    

    Best Regards,

    Alec Liu.


    If the answer is the right solution, please click "Accept Answer" and kindly upvote it. If you have extra questions about this answer, please click "Comment".

    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.

    0 comments No comments

1 additional answer

Sort by: Most helpful
  1. Alan Farias 755 Reputation points
    2023-03-01T09:55:46.44+00:00

    To add an item to one CollectionView and remove it from another CollectionView, you need to handle the event raised in the first CollectionView and use the arguments to add the item to the second CollectionView and remove it from the first one.

    In your case, you have already defined an event AddEmoteEvent in the Store class that will be raised when the user selects an item in the StoreEmotesView CollectionView. You also have a class StoreEventArgs to encapsulate the data that needs to be passed to the event handlers.

    To handle the AddEmoteEvent event in the EmotesPage class, you need to subscribe to the event in the constructor of the EmotesPage class. You can then define a handler method to handle the event and add the new item to the emotes collection and remove it from the storeEmotes collection.

    Here's some sample code that shows how you can accomplish this:

    public partial class EmotesPage : ContentPage
    {
        ObservableCollection<EmotesModel> emotes;
        ObservableCollection<StorePage_Emotes_> storeEmotes;
        
        public EmotesPage()
        {
            InitializeComponent();
            
            emotes = new ObservableCollection<EmotesModel>
            {
                // ...
            };
            EmotesView.ItemsSource = emotes;
            
            // Get a reference to the Store page
            var storePage = ((App)Application.Current).MainPage.Children.OfType<Store>().First();
            
            // Subscribe to the AddEmoteEvent event
            storePage.AddEmoteEvent += OnAddEmoteEvent;
            
            // Get a reference to the storeEmotes collection in the Store page
            storeEmotes = storePage.storeEmotes;
        }
        
        private void OnAddEmoteEvent(object sender, Store.StoreEventArgs e)
        {
            // Add the new item to the emotes collection
            emotes.Add(new EmotesModel { Image = e.CustomString });
            
            // Remove the item from the storeEmotes collection
            var itemToRemove = storeEmotes.FirstOrDefault(x => x.Image == e.CustomString);
            if (itemToRemove != null)
            {
                storeEmotes.Remove(itemToRemove);
            }
        }
    }
    

    In the constructor of the EmotesPage class, we get a reference to the Store page and subscribe to the AddEmoteEvent event. We also get a reference to the storeEmotes collection in the Store page.

    In the OnAddEmoteEvent event handler method, we create a new EmotesModel object with the Image property set to the value passed in the CustomString property of the StoreEventArgs argument. We then add the new object to the emotes collection.

    Next, we use LINQ to find the item in the storeEmotes collection that has the same Image property value as the one passed in the CustomString property of the StoreEventArgs argument. We remove that item from the storeEmotes collection if it exists.


    Please, if this answer is helpful, click "Accept Answer" and kindly upvote it. If you have extra questions about this answer, please let me know.


Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.