0

I have googled so much on this topic that my hands are bleeding before writing this question. What I have gathered so far is that I know I have to use an ObservableCollection.

The ListBox populates on startup, but the problem occurs when I want to delete/remove an item from the ObservableCollection and have it reflected in the ListBox.

The item is removed from the ObservableCollection but the ListBox does not update anything. I have tried different bindings like Mode and UpdateSourceTrigger.

This is my code so far:

<ListBox Name="projectsListBox" ItemsSource="{Binding Projects}"
<ListBox.ItemTemplate>
    <DataTemplate>
        <StackPanel Orientation="Horizontal" Margin="0,0,5,0">
            <Image Source="{Binding Icon}" Width="20"/>
            <TextBlock Text="{Binding ProjectName}" FontSize="14"/>
        </StackPanel>
    </DataTemplate>
</ListBox.ItemTemplate>
</ListBox>

ViewModel. The ViewModel inherits from ViewModelBase which in turn inherits from INotifyPropertyChanged.

public class OpenProjectViewModel : ViewModelBase
{
    private ObservableCollection<ProjectData> _projects;

    public ObservableCollection<ProjectData> Projects
    {
        get { return _projects; }
        set
        {
            if (_projects != value)
            {
                _projects = value;
                OnPropertyChanged(nameof(Projects));
            }
        }
    }
}

Code that removes the item from the ObservebleCollection:

Projects
    .Remove(Projects
    .Where(_ => _.Id == id).Single());

Update: one thing to note is in OpenProjectView I have a OnDelete_Click button, I have instantiated the OpenProjectViewModel which holds the delete logic for the ObservableCollection. The ObservableCollection is instantiated in the constructor. Any thoughts on how to get around this?

private void OnDelete_Click(object sender, RoutedEventArgs e)
{
    OpenProjectViewModel openProjectViewModel = new();//<--The ObservableCollection is instantiated in the constructor
    openProjectViewModel.DeleteProject(listItem);
}

Did I forget to share anything?

Thank you for your assistance!

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
AllramEst
  • 1,319
  • 4
  • 23
  • 47
  • Are you sure that you did not accidently re-set / re-assigned a value to your "Projects" property during runtime? I do not see it on the code you posted, but I made that error in the past myself, then I wondered why the UI was not updating correctly. – Martin Feb 10 '23 at 13:58
  • You could check the return value of `Projects.Remove` to verify that in fact an item has been removed. – Klaus Gütter Feb 10 '23 at 14:09
  • @KlausGütter from the actual code: var successfullyDeleted = Projects .Remove(Projects .Where(_ => _.FullPath == projectData.FullPath && _.ProjectName == projectData.ProjectName).Single()); – AllramEst Feb 10 '23 at 14:13
  • @Martin hmm. good point. checked, and I cant find any reassigns or resets, unfortunately. – AllramEst Feb 10 '23 at 14:26
  • Updated the question with new thoughts. – AllramEst Feb 10 '23 at 14:39
  • 2
    `openProjectViewModel = new();` does of course create a new instance of the view model, which is obviously not the one to which the UI is bound. You may write `var openProjectViewModel = (OpenProjectViewModel)DataContext;` – Clemens Feb 10 '23 at 14:43
  • @Clemens That did it! The ListBox is updating! Is there a way to do this in the xaml view? Right now I only have in the view. – AllramEst Feb 10 '23 at 14:53
  • 1
    The "OpenProjectViewModel" should be created only one time, for example in the constructor of the view. Afterwards the view shall use only this instance. I would implement the delete logic using a button that is bound to an "DeleteCommand" which is of type "ICommand" and resides in the "OpenProjectsViewModel". See also this example: https://stackoverflow.com/a/53781651/4424024 If you want to delete the currently selected item in the list, you should bound the "SelectedItem" property if the ListBox to a new property "SelectedProject" property in the viewmodel. – Martin Feb 10 '23 at 14:57
  • @Clemens make your suggestion an answer and I will mark it as solved. :) – AllramEst Feb 10 '23 at 15:04
  • 1
    I am hesitating to say the following, because I would strictly advise against a UserControl setting its own DataContext. But instead of assigning the DataContext in XAML you could create it in the UserControl's code behind as a field: `private readonly OpenProjectViewModel openProjectViewModel = new OpenProjectViewModel();`. In the control's constructor set `DataContext = openProjectViewModel;` and wherever else you need it, just use the field. – Clemens Feb 10 '23 at 15:18

0 Answers0