Burgers_In_Terminus
Burgers_In_Terminus

Reputation: 23

Removing selectedItem from ObservableCollection using MVVM

I want to remove an item from an ObservableCollection while adhering to MVVM. I understand the task, I think I understand the logic pretty well and have implemented it, but the item is never removed in the view.

I have traced the application with breakpoints and the value of selectedProject is being read correctly. I also added variables to check the Collection size before and after the remove statement, which were the same value so it therefore does not remove the item. My question is why? What have I missed? What rules have I not adhered to? Pretty new to .NET.

**I am using a WCF Service, to return an ObservableCollection of Projects from my CodeFirst DB and this is called as soon as a user opens the Projects view.

View

<ListBox ItemsSource="{Binding ProjectList, UpdateSourceTrigger=PropertyChanged}" SelectedItem="{Binding SelectedProject}" SelectedIndex="{Binding ProjectIndex}" BorderThickness="0" Margin="60,195,218.8,212.4">
        <ListBox.ItemTemplate>
            <DataTemplate>
                <TextBlock Text="{Binding ProjectName}"/>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>
    <Button Command="{Binding DeleteCommand}" Content="Up" HorizontalAlignment="Left" Margin="563,195,0,0" VerticalAlignment="Top" Height="35" Width="75"/>

ViewModel

private ObservableCollection<Project> _projectList;
public ObservableCollection<Project> ProjectList
    {
        get 
        {
            var q = client.ReturnProjects().ToList();
            _projectList = new ObservableCollection<Project>(q.ToList());
            return _projectList;
        }
        set
        {
            _projectList = value;
            OnPropertyChanged("ProjectList");
        }

public int SelectedProject
    {
        get { return _selectedProject; }
        set
        {
            _selectedProject = value;
            OnPropertyChanged("SelectedProject");
        }
    }

The method executed by the command is as follows, the command is being hit and the method called.

public void DeleteProject()
        {

            if (SelectedProject != null)
            {
                ProjectList.Remove(SelectedProject);
            }
        } 

Upvotes: 2

Views: 3729

Answers (3)

Thomas Mutzl
Thomas Mutzl

Reputation: 755

You need a two-way-binding for the SelectedItem property.

View

    <ListBox ItemsSource="{Binding ProjectList}"
             SelectedItem="{Binding SelectedProject, Mode=TwoWay}">
        <ListBox.ItemTemplate>
            <DataTemplate>
                <TextBlock Text="{Binding Name}" />
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>
    <Button Command="{Binding DeleteCommand}"
            Content="Delete"
            HorizontalAlignment="Right"
            VerticalAlignment="Bottom" />

ViewModel, Model and ICommand Implementation

public class ViewModel : INotifyPropertyChanged
{
    public ViewModel()
    {
        var q = new[] { new Project() { Name = "A" }, new Project() { Name = "B" }, new Project() { Name = "C" } };
        ProjectList = new ObservableCollection<Project>(q);
    }

    private ObservableCollection<Project> _projectList;

    public ObservableCollection<Project> ProjectList
    {
        get
        {
            return _projectList;
        }
        set
        {
            _projectList = value;
            OnPropertyChanged("ProjectList");
        }
    }

    Project _selectedProject;
    public Project SelectedProject
    {
        get { return _selectedProject; }
        set
        {
            _selectedProject = value;
            OnPropertyChanged("SelectedProject");
        }
    }

    public ICommand DeleteCommand => new SimpleCommand(DeleteProject);

    private void DeleteProject()
    {

        if (SelectedProject != null)
        {
            ProjectList.Remove(SelectedProject);
        }
    }
    public event PropertyChangedEventHandler PropertyChanged;
    private void OnPropertyChanged(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

public class Project
{
    public string Name { get; set; }
}

public class SimpleCommand : ICommand
{
    Action _execute;
    public SimpleCommand(Action execute)
    {
        this._execute = execute;
    }

    public event EventHandler CanExecuteChanged;

    public bool CanExecute(object parameter) => true;

    public void Execute(object parameter)
    {
        _execute();
    }
}

Upvotes: 1

Brummell
Brummell

Reputation: 223

The ObservableCollection has to interact with the model layer. Maybe you need this: https://blogs.msdn.microsoft.com/bethmassi/2009/05/08/using-the-wpf-observablecollection-with-ef-entities/

Upvotes: 0

Gowri Pranith Kumar
Gowri Pranith Kumar

Reputation: 1685

I think OnPropertyChanged("ProjectList") needs to be called after deleting the item to raise the notification for updating the view .

Upvotes: 0

Related Questions