skip to Main Content

I have this code in my MainWindow.
The user enters Name, Phone and Email in the fields provided, selects Location and then the Name appears in the listbox, lstClients.

enter image description here

I’m trying to write a method to remove a selected name from the listbox.

namespace WpfApp_Employment_Help
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        // client list

        List<Client> ClientList = new List<Client>();
        public MainWindow()
        {
            InitializeComponent();
        }

        // method to select location via radio button
        public string GetSelectedLocation()
        {
            string selected = string.Empty;
           if (RBLocE.IsChecked == true) { selected = "Edinburgh"; }
           else if (RBLocG.IsChecked == true) { selected = "Glasgow"; }
           else if (RBLocO.IsChecked == true) { selected = "Other"; }
           
           return selected;
        }


        // method to create a new client on click
        private void newClient(object sender, RoutedEventArgs e)
        {
            Client c = new Client(boxClientName.Text, boxClientPhone.Text, boxClientEmail.Text, GetSelectedLocation());
            boxClientName.Clear();
            boxClientPhone.Clear();
            boxClientEmail.Clear();
            ClientList.Add(c);
            lstClients.ItemsSource = null;
            lstClients.ItemsSource = ClientList;
        }

        // method to id selected client
        private void AssignID(object sender, RoutedEventArgs e)
        {
            Client c = lstClients.SelectedItem as Client;
            if (c != null)
            {
                c.AssignID();
            }
            lstClients.ItemsSource = null;
            lstClients.ItemsSource = ClientList;
        }

        //    method to remove selected client

        private void RemoveClient(object sender, RoutedEventArgs e)
        {
            lstClients.Items.Remove(lstClients.SelectedItem);
        }

             
        
    }
}

When I run this code, I get Unhandled Exception:
System.InvalidOperationException: ‘Operation is not valid while ItemsSource is in use. Access and modify elements with ItemsControl.ItemsSource instead.’
enter image description here

how can I rewrite my RemoveClient method?
my code for the Client class is this:

   public partial class Client
     {
        public string Name { get; set; }
        public string Phone { get; set; }
        public string Email { get; set; }

        public string Location { get; }

        public bool IDed { get; private set; }

        public Client(string n, string p, string e, string l)
        {
            Name = n;
            Phone = p;
            Email = e;
            Location = l;

        }
    }

I have Visual Studio 2022 which has been recently updated.

I have also tried the following solution but it gives me another unhandled error?
It looks like I need to change List </string/> and string to something else. but what?

        private void RemoveClient(object sender, EventArgs e)
        {
            if (lstClients.Items.Count >= 1)
            {
                if (lstClients.SelectedValue != null)
                {
                    var items = (List<string>)lstClients.ItemsSource;

                    var item = (string)lstClients.SelectedValue;
                    lstClients.ItemsSource = null;
                    lstClients.Items.Clear();
                    items.Remove(item);
                    lstClients.ItemsSource = items;
                }
            }
            else
            {
                System.Windows.Forms.MessageBox.Show("No ITEMS Found");
            }
        }



System.InvalidCastException: 'Unable to cast object of type 'System.Collections.Generic.List`1[WpfApp_Employment_Help.Client]' to type 'System.Collections.Generic.List`1[System.String]'.'

2

Answers


  1. As the error message suggests, you can’t modify the ItemsControl via the collection view returned from the ItemsControl.Items property.

    WPF is generally designed to work on the data sources instead of handling the data related controls (data presentation). This way data and data presentation (GUI) are cleanly separated and code will become a lot simpler to write.
    In case of the ListView (or ItemsControl in general), simply modify the source collection.

    To improve performance, the source collection should be a INotifyCollectionChanged implementation, for example ObservableCollection<T>, especially when you expect to modify the source collection.
    This makes invalidating the ItemsSource e.g. by assigning null, just to set it again redundant and significantly improves the performance.

    public partial class MainWindow : Window
    {
      // client list
      public ObservableCollection<Client> ClientList { get; } = new ObservableCollection<Client>();
    
      // method to create a new client on click
      private void newClient(object sender, RoutedEventArgs e)
      {
        Client c = new Client(boxClientName.Text, boxClientPhone.Text, boxClientEmail.Text, GetSelectedLocation());
        boxClientName.Clear();
        boxClientPhone.Clear();
        boxClientEmail.Clear();
        
        ClientList.Add(c);
        
        // The following lines are no longer needed 
        // as the GUI is now notified about the collection changes (by the INotifyCollectionChanged collection)
        //lstClients.ItemsSource = null;
        //lstClients.ItemsSource = ClientList;
      }
    
      // method to id selected client
      private void AssignID(object sender, RoutedEventArgs e)
      {
        Client c = lstClients.SelectedItem as Client;
        
        // Same as the if-statement below
        c?.AssignID();
        
        //if (c != null)
        //{
        //  c.AssignID();
        //}
        
        // The following lines are no longer needed 
        // as the GUI is now notified about the collection changes (by the INotifyCollectionChanged collection)
        //lstClients.ItemsSource = null;
        //lstClients.ItemsSource = ClientList;
     }
    
     // method to remove selected client
     private void RemoveClient(object sender, RoutedEventArgs e)
     {
       var clientToRemove = lstClients.SelectedItem as Client;
       this.ClientList.Remove(clientToRemove);
     }
    }
    
    Login or Signup to reply.
  2. If you change the type of ClientList from List<Client> to ObservableCollection<Client>, you could simply remove the item directly from the source collection:

    public partial class MainWindow : Window
    {
        ObservableCollection<Client> ClientList = new ObservableCollection<Client>();
        public MainWindow()
        {
            InitializeComponent();
        }
    
        ...
        private void RemoveClient(object sender, RoutedEventArgs e)
        {
            ClientList.Remove(lstClients.SelectedItem as Client);
        }
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search