使用 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
那么你应该将 ComboBox
的 SelectedItem
属性 绑定到字符串源 属性 并调用 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?
我有 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
那么你应该将 ComboBox
的 SelectedItem
属性 绑定到字符串源 属性 并调用 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?