如何在Qt/C++/QML中实现类似WPF的MVVM?

joh*_*son 11 wpf qt mvvm qml

我正在编写一个概念验证应用程序,这非常简单.基本上它由一个UI组成,其中"Note"类型对象列表显示在QML ListView中.

然后,我有几个类,这是类似的东西:

#ifndef NOTE_H
#define NOTE_H

#include <string>

using namespace std;
class Note
{
public:
    Note(QObject* parent = 0)
        : QObject(parent)
    {

    }

    Note(const int id, const string& text)
        : _id(id), _text(text)
    {
    }

    int id()
    {
        return _id;
    }

    const string text()
    {
        return _text;
    }

    void setText(string newText)
    {
        _text = newText;
    }

private:
    int _id;
    string _text;
};

#endif // NOTE_H
Run Code Online (Sandbox Code Playgroud)

然后一个存储库:

class NoteRepository : public Repository<Note>
{
public:
    NoteRepository();
    ~NoteRepository();

    virtual shared_ptr<Note> getOne(const int id);
    virtual const unique_ptr<vector<Note>> getAll();
    virtual void add(shared_ptr<Note> item);
private:
    map<int, shared_ptr<Note>> _cachedObjects;
};
Run Code Online (Sandbox Code Playgroud)

最后是一个向QML公开Note的ViewModel

class MainViewModel : public QObject
{
    Q_OBJECT
    Q_PROPERTY(QQmlListProperty<Note> notes READ notes NOTIFY notesChanged)
    Q_PROPERTY(int count READ count() NOTIFY countChanged)
public:
    MainViewModel(QObject *newParent = 0);
    int count();
    QQmlListProperty<Note> notes();
signals:
    void notesChanged();
    void countChanged();
public slots:
private:
    std::shared_ptr<UnitOfWork> _unitOfWork;
    static void appendNote(QQmlListProperty<Note> *list, Note *note);
    QList<Note*> _notes;
};
Run Code Online (Sandbox Code Playgroud)

请不要在这里发现任何C++错误并且认为它们是不完整的,现在不是重点,因为我在学习的过程中不断适应这一点.

我正在努力的地方是,如何向QML公开类似列表的对象?要求是此列表必须是动态的,应该能够添加,删除和修改注释的文本.当列表被C++修改时,它也应该通知UI(信号).

我尝试了QQmlListProperty,但无法想办法将它暴露给QML.然后我读了另一个SO帖子这个类型不能被QML修改(??),我偶然发现了QAbstractItemModel.

无论如何,有人能指出我正确的方向吗?

Rei*_*ica 9

我在另一个答案中发布了一个相当完整的例子.

一般程序是:

  1. 创建一个派生自的模型QAbstractItemModel.例如,您可以重用Qt已经提供的任何模型QStringListModel.

  2. 将其暴露给QML.例如使用setContextProperty()QML Engine rootContext().

  3. 模型的角色在QML中的委托上下文中可见.Qt 在默认实现中提供DisplayRole(display)和EditRole(edit)的名称和角色之间的默认映射roleNames().

    delegate: Component {
        TextInput {
            width: view.width // assuming that view is the id of the view object
            text: edit // "edit" role of the model, to break the binding loop
            onTextChanged: model.display = text // "display" role of the model
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)
  4. 如果需要,可以通过在视图和后端模型之间附加代理模型来创建中间视图模型.您可以QAbstractProxyModel从其子类派生或其中一个子类派生.