ObservableCollection 在设置后不返回新数据
ObservableCollection not returning the new data after it is set
填充可观察集合时,我可以看到当我 "set" 集合中的新数据时 "return" 没有被调用。如果我从程序中的不同位置设置数据,它确实有效,所以我一定不理解它工作方式的一些细微差别。有效的部分是当我取出 "This works" 下的注释代码时,"ChooseFile()" 没有。在调试器中,我可以看到 OptionsToChoose 在这两种情况下都有数据。当它工作时 XAML 被正确更新。
class ScripterViewModel : BindableBase
{
public ScripterViewModel()
{
ScripterModel scripterModel = new ScripterModel();
ObservableCollection<string> tabsChoice = new ObservableCollection<string>();
tabsChoice.Add("Tabs");
tabsChoice.Add("Buttons");
Tabs = tabsChoice;
this.OpenFileBtn = new DelegateCommand(chooseFile, canChooseFile).ObservesProperty(() => OpenFile);
this.SaveFileBtn = new DelegateCommand(saveFile, canSaveFile).ObservesProperty(() => SaveFile);
//This works
//var myJSONDoc = JsonConvert.DeserializeObject<JSONclass>(File.ReadAllText(@"C:\Users\mike\Documents\Haas\Scripter\settings.json"));
//OptionsToChoose = new ObservableCollection<Tabbed>(myJSONDoc.TabbedBtns);
}
public void chooseFile()
{
var myJSONDoc = JsonConvert.DeserializeObject<JSONclass>(File.ReadAllText(@"C:\Users\mike\Documents\Haas\Scripter\settings.json"));
OptionsToChoose = new ObservableCollection<Tabbed>(myJSONDoc.TabbedBtns);
}
public ObservableCollection<Tabbed> _optionsToChoose = new ObservableCollection<Tabbed>();
public ObservableCollection<Tabbed> OptionsToChoose
{
get
{
return _optionsToChoose;
}
set
{
_optionsToChoose = value;
}
}
}
您没有在 OptionsToChoose
的 setter 中引发 PropertyChanged
事件。您已经扩展了 BindableBase
,因此可以通过将当前的 OptionsToChoose
属性 实现替换为以下内容来引发 PropertyChanged
事件:
public ObservableCollection<Tabbed> OptionsToChoose
{
get
{
return _optionsToChoose;
}
set
{
SetProperty(ref _optionsToChoose, value);
}
}
当您在构造函数中创建 OptionsToChoose 时,它将在视图使用视图模型时进行初始化。
在不起作用的示例中,您只是将 ObservableCollection 替换为新的,而不是清除它并添加项目。因此,您需要通知 属性 已更改,如 V.Leon 在他的回答中指出的那样。
或者只清除现有集合并用 json 中的值填充它。
var myJSONDoc = JsonConvert.DeserializeObject<JSONclass>(File.ReadAllText(@"C:\Users\mike\Documents\Haas\Scripter\settings.json"));
OptionsToChoose.Clear();
foreach (var item in myJSONDoc.TabbedBtns)
{
OptionsToChoose.Add(item);
}
理想情况下,您不应在绑定后更改 ObservableCollection 的整个引用。而是清除其中的项目,然后在其中添加新项目。
public ObservableCollection<Tabbed> _optionsToChoose = new ObservableCollection<Tabbed>();
public ObservableCollection<Tabbed> OptionsToChoose
{
get
{
return _optionsToChoose;
}
}
OptionsToChoose.Clear();
OptionsToChoose.Add(foo);
如前所述,如果您要重置 collection,则根据您的代码,您需要为 collection 生成 属性 引发 PropertyChanged。也就是说 ObservableCollection
确实不是理想的 collection 类型。我建议在您的项目中包含 MvvmHelpers 并使用 ObservableRangeCollection
public class MyPageViewModel : BindableBase
{
public MyPageViewModel()
{
OptionsToChoose = new ObservableRangeCollection<Tabbed>();
SomeCommand = new DelegateCommand(OnSomeCommandExecuted);
}
public DelegateCommand SomeCommand { get; }
public ObservableRangeCollection<Tabbed> OptionsToChoose { get; }
private void OnSomeCommandExecuted()
{
// get some updated data
IEnumerable<Tabbed> foo = DoFoo();
OptionsToChoose.ReplaceRange(foo);
}
}
你在那里得到了一些好处。一个是你没有分配和取消分配你的 collection。此外,ObservableRangeCollection 在引发 PropertyChanged 或 CollectionChanged 事件之前更新完整列表,这导致很少 UI 通知和更好的应用程序性能。
填充可观察集合时,我可以看到当我 "set" 集合中的新数据时 "return" 没有被调用。如果我从程序中的不同位置设置数据,它确实有效,所以我一定不理解它工作方式的一些细微差别。有效的部分是当我取出 "This works" 下的注释代码时,"ChooseFile()" 没有。在调试器中,我可以看到 OptionsToChoose 在这两种情况下都有数据。当它工作时 XAML 被正确更新。
class ScripterViewModel : BindableBase
{
public ScripterViewModel()
{
ScripterModel scripterModel = new ScripterModel();
ObservableCollection<string> tabsChoice = new ObservableCollection<string>();
tabsChoice.Add("Tabs");
tabsChoice.Add("Buttons");
Tabs = tabsChoice;
this.OpenFileBtn = new DelegateCommand(chooseFile, canChooseFile).ObservesProperty(() => OpenFile);
this.SaveFileBtn = new DelegateCommand(saveFile, canSaveFile).ObservesProperty(() => SaveFile);
//This works
//var myJSONDoc = JsonConvert.DeserializeObject<JSONclass>(File.ReadAllText(@"C:\Users\mike\Documents\Haas\Scripter\settings.json"));
//OptionsToChoose = new ObservableCollection<Tabbed>(myJSONDoc.TabbedBtns);
}
public void chooseFile()
{
var myJSONDoc = JsonConvert.DeserializeObject<JSONclass>(File.ReadAllText(@"C:\Users\mike\Documents\Haas\Scripter\settings.json"));
OptionsToChoose = new ObservableCollection<Tabbed>(myJSONDoc.TabbedBtns);
}
public ObservableCollection<Tabbed> _optionsToChoose = new ObservableCollection<Tabbed>();
public ObservableCollection<Tabbed> OptionsToChoose
{
get
{
return _optionsToChoose;
}
set
{
_optionsToChoose = value;
}
}
}
您没有在 OptionsToChoose
的 setter 中引发 PropertyChanged
事件。您已经扩展了 BindableBase
,因此可以通过将当前的 OptionsToChoose
属性 实现替换为以下内容来引发 PropertyChanged
事件:
public ObservableCollection<Tabbed> OptionsToChoose
{
get
{
return _optionsToChoose;
}
set
{
SetProperty(ref _optionsToChoose, value);
}
}
当您在构造函数中创建 OptionsToChoose 时,它将在视图使用视图模型时进行初始化。
在不起作用的示例中,您只是将 ObservableCollection 替换为新的,而不是清除它并添加项目。因此,您需要通知 属性 已更改,如 V.Leon 在他的回答中指出的那样。
或者只清除现有集合并用 json 中的值填充它。
var myJSONDoc = JsonConvert.DeserializeObject<JSONclass>(File.ReadAllText(@"C:\Users\mike\Documents\Haas\Scripter\settings.json"));
OptionsToChoose.Clear();
foreach (var item in myJSONDoc.TabbedBtns)
{
OptionsToChoose.Add(item);
}
理想情况下,您不应在绑定后更改 ObservableCollection 的整个引用。而是清除其中的项目,然后在其中添加新项目。
public ObservableCollection<Tabbed> _optionsToChoose = new ObservableCollection<Tabbed>();
public ObservableCollection<Tabbed> OptionsToChoose
{
get
{
return _optionsToChoose;
}
}
OptionsToChoose.Clear();
OptionsToChoose.Add(foo);
如前所述,如果您要重置 collection,则根据您的代码,您需要为 collection 生成 属性 引发 PropertyChanged。也就是说 ObservableCollection
确实不是理想的 collection 类型。我建议在您的项目中包含 MvvmHelpers 并使用 ObservableRangeCollection
public class MyPageViewModel : BindableBase
{
public MyPageViewModel()
{
OptionsToChoose = new ObservableRangeCollection<Tabbed>();
SomeCommand = new DelegateCommand(OnSomeCommandExecuted);
}
public DelegateCommand SomeCommand { get; }
public ObservableRangeCollection<Tabbed> OptionsToChoose { get; }
private void OnSomeCommandExecuted()
{
// get some updated data
IEnumerable<Tabbed> foo = DoFoo();
OptionsToChoose.ReplaceRange(foo);
}
}
你在那里得到了一些好处。一个是你没有分配和取消分配你的 collection。此外,ObservableRangeCollection 在引发 PropertyChanged 或 CollectionChanged 事件之前更新完整列表,这导致很少 UI 通知和更好的应用程序性能。