使用 ObservableCollection 实现 Onpropertychanged(C#、WPF)

Implement Onpropertychanged with ObservableCollection (C#, WPF)

我有 ComboBox "ProjectList":

MainWindow.xaml

<ComboBox ItemsSource="{Binding Path=ProjectList}" IsSynchronizedWithCurrentItem="True" />

元素正在添加到下面的方法中并且工作正常:

MainViewModel.cs

[AddINotifyPropertyChangedInterface]
public class MainViewModel{

 public ObservableCollection<string> ProjectList { get; internal set; } 
  = new ObservableCollection<string>(); 

  public async Task GetProjects(){
  ...
   foreach (AItem item in....)
   {
     ProjectList.Add(item.name)
   }
 }    
}

注意 - 我已经安装了 "PropertyChanged.Fody"。

现在我添加了第二个 ComboBox "TaskList" 到 xaml:

<ComboBox ItemsSource="{Binding Path=TaskList}" IsSynchronizedWithCurrentItem="True" />

此处的列表应根据所选项目创建 "ProjectList"。方法基本相同,只有一个参数:

public ObservableCollection<string> TaskList { get; internal set; } 
 = new ObservableCollection<string>();

public async Task GetTask(string projectId = ""){
      ...
       foreach (AItem item in....)
       {
         TaskList.Add(item.name2)
       }
 }   

现在我想将它添加到我的 MVVM 中。

问题是:何时以及如何运行 GetTask()? ObservableCollection TaskList 的 "internal set" 应该实现 "onpropertychanged"?

您需要一个在 ProjectList 组合框的所选项目更改时触发的事件。

如果您使用后面的代码,您只需将 SelectionChanged 属性 设置为指向一个函数即可。但是,您似乎正在使用 MVVM,因此您需要向组合框添加交互触发器、触发器调用的命令和命令调用的方法。

将此命名空间添加到 window:

xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"

更改您的组合框以包含触发器并公开 SelectedItem

           <ComboBox ItemsSource="{Binding Path=ProjectList}" 
                     IsSynchronizedWithCurrentItem="True"
                     SelectedItem="{Binding SelectedProject}" >
                <i:Interaction.Triggers>
                    <i:EventTrigger EventName="SelectionChanged">
                        <i:InvokeCommandAction Command="{Binding ReloadTasksCommand}" />
                    </i:EventTrigger>
                </i:Interaction.Triggers>
            </ComboBox>

然后,在您的 ViewModel 中,添加 ReloadTasksCommand 命令。您需要定义命令及其调用的方法。

private ICommand reloadTasks;
public ICommand ReloadTasksCommand => this.reloadTasks?? (this.reloadTasks= new RelayCommand(this.ReloadTasks));

public string SelectedProject{ get; set; }

private void ReloadTasks()
{
    GetTasks(this.SelectedProject);
}

我还为 SelectedProject 添加了一个 属性,绑定到项目组合框的 SelectedItem。

RelayCommand 在 GalaSoft.MvvmLight.CommandWpf 库中。还有其他的,这就是我用的。

像这样更改组合框:

       <ComboBox ItemsSource="{Binding Path=ProjectList}" 
                 IsSynchronizedWithCurrentItem="True"
                 SelectedItem="{Binding SelectedProject}" >                
       </ComboBox>

视图模型:

private string _selectedObject;
public string SelectedObject
{
    get { return _selectedObject; }
    set
    {
        _selectedObject = value;
        //OnPropertyChanged(); -- INotifyPropertyChanged no need if Fody
        ReloadTasks();
    }
}

private void ReloadTasks()
{
    GetTasks(SelectedProject);
}

when you select Project the next cb should load (run) taskList

那么你应该将 ComboBoxSelectedItem 属性 绑定到字符串源 属性 并调用 GetTask 中的方法 setter 这个,例如:

    private string _selectedProject;
    public string SelectedProject
    {
        get { return _selectedProject; }
        set
        {
            _selectedProject = value;
            GetTask(_selectedProject);
        }
    }

...或在选择更改时调用命令:来自 setter:

set
{
    _selectedProject = value;
    YourCommand.Execute(null);
}

...或使用 interaction trigger.

从 XAML 标记

属性不应该在它们的 setter 中真正启动异步后台操作。请在这里参考我的回答以获取更多相关信息:

Is wrong to invoke an async method from property setter in WPF view model?