C# 使用MVVM从ObservableCollection中删除selectedItem

C# 使用MVVM从ObservableCollection中删除selectedItem,c#,wpf,mvvm,binding,listboxitem,C#,Wpf,Mvvm,Binding,Listboxitem,我想在坚持MVVM的同时从ObservableCollection中删除一个项目。我理解这个任务,我认为我非常理解这个逻辑,并且已经实现了它,但是这个项在视图中从未被删除 我用断点跟踪了应用程序,并且正确读取了selectedProject的值。我还添加了变量来检查remove语句前后的集合大小,它们的值相同,因此它不会删除该项。我的问题是为什么?我错过了什么?我没有遵守什么规则?对.NET来说,这是一个相当新的概念 **我正在使用一个WCF服务,从我的CodeFirst DB返回一个项目的Ob

我想在坚持MVVM的同时从ObservableCollection中删除一个项目。我理解这个任务,我认为我非常理解这个逻辑,并且已经实现了它,但是这个项在视图中从未被删除

我用断点跟踪了应用程序,并且正确读取了selectedProject的值。我还添加了变量来检查remove语句前后的集合大小,它们的值相同,因此它不会删除该项。我的问题是为什么?我错过了什么?我没有遵守什么规则?对.NET来说,这是一个相当新的概念

**我正在使用一个WCF服务,从我的CodeFirst DB返回一个项目的ObservableCollection,当用户打开Projects视图时就会调用它

查看

<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"/>

我认为删除项目后需要调用OnPropertyChanged(“ProjectList”),以发出更新视图的通知

可观测采集必须与模型层交互。 也许你需要这个:

SelectedItem属性需要双向绑定

看法


ViewModel、Model和ICommand实现

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();
    }
}
公共类视图模型:INotifyPropertyChanged
{
公共视图模型()
{
var q=new[]{new Project(){Name=“A”},new Project(){Name=“B”},new Project(){Name=“C”};
ProjectList=新的可观测集合(q);
}
私有可观察收集项目列表;
公共可观测集合项目列表
{
得到
{
返回项目列表;
}
设置
{
_projectList=值;
OnPropertyChanged(“项目列表”);
}
}
项目-所选项目;
公共项目选定项目
{
获取{return\u selectedProject;}
设置
{
_selectedProject=值;
OnPropertyChanged(“SelectedProject”);
}
}
公共ICommand DeleteCommand=>newsimpleCommand(DeleteProject);
私有项目()
{
如果(SelectedProject!=null)
{
ProjectList.Remove(SelectedProject);
}
}
公共事件属性更改事件处理程序属性更改;
私有void OnPropertyChanged(字符串propertyName)
{
PropertyChanged?.Invoke(这是新的PropertyChangedEventArgs(propertyName));
}
}
公共类项目
{
公共字符串名称{get;set;}
}
公共类SimpleCommand:ICommand
{
行动执行;
公共SimpleCommand(操作执行)
{
这个。_execute=execute;
}
公共事件处理程序CanExecuteChanged;
public bool CanExecute(对象参数)=>true;
public void Execute(对象参数)
{
_执行();
}
}

不幸的是,没有解决问题。我添加了
模式=TwoWay
,这并没有解决问题。我也不明白为什么它应该有,因为SelectedItem只允许我检索要删除的项目。用户在UI(视图)中更改选择。通过双向绑定,ViewModels属性SelectedItem将得到更新。我将编辑我的答案并发布一个有效的解决方案。这很有意义,托马斯,谢谢。我不明白的是,当我使用断点跟踪时,我可以看到正确的selectedItem已传递到ViewModel中,但是调用remove不会改变视图中的列表。更新了我的答案。如果你还有问题,请告诉我。托马斯,谢谢你在这方面的帮助。它工作得很好。最明显的区别是我没有在ViewModel构造函数中初始化ProjectList。不管怎样,非常感谢你花时间来做这件事。让对张贴问题的恐惧变得值得。:)
public void DeleteProject()
        {

            if (SelectedProject != null)
            {
                ProjectList.Remove(SelectedProject);
            }
        } 
    <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" />
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();
    }
}