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);
    }
}

BindableBase.SetProperty Method

当您在构造函数中创建 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 通知和更好的应用程序性能。