Qml.Net - Qt/QML integration/support for .NET
Find a file
Michael Lamers c80f455185 exporting dll symbols for windows
Q_DECL_EXPORT for all entry points for the native library
removed not needed static definition (DEFINE_NETVALUETYPE), this part is already declared and defined in the header
2018-07-16 20:37:43 +02:00
build Got travis build working. 2018-07-14 14:25:31 -04:00
src exporting dll symbols for windows 2018-07-16 20:37:43 +02:00
tmp/Test Added a rough test to verify we can load qml files. 2017-05-31 15:31:57 -04:00
.gitignore Ignored compiled qml files. 2018-07-12 22:30:16 -04:00
.gitmodules Adding build project. 2018-07-12 21:00:05 -04:00
.travis.yml Got travis build working. 2018-07-14 14:25:31 -04:00
build.sh Adding build project. 2018-07-12 21:00:05 -04:00
LICENSE Initial commit 2017-05-31 14:04:37 -04:00
README.md Update README.md 2018-07-16 07:50:19 -04:00

Qt/Qml support for .NET/.NET Core on Linux/OSX/Windows

This is a work-in-progress (but usable) bridge between .NET and Qml.

The intended platforms to support include:

  • Runtimes:
    • .NET Framework Full
    • .NET Core
    • Mono
  • Operating systems
    • Linux
    • OSX
    • Windows

As of now, the only focus is on .NET Core (Linux/OSX/Window). The other frameworks should theoretically work though. Drop us an issue if you have any problems. When there is enough demand and userbase, I'd be happy to fully bring in other frameworks.

The idea

Define a .NET type (POCO)

public class QmlType
{
    /// <summary>
    /// Properties are exposed to Qml.
    /// </summary>
    public string StringProperty { get; set; }

    /// <summary>
    /// Events get exposed as signals.
    /// </summary>
    public event Action<string> CustomEvent { get; set; }

    /// <summary>
    /// Methods can return .NET types.
    /// The returned type can be invoked from Qml (properties/methods/events/etc).
    /// </summary>
    /// <returns></returns>
    public QmlType CreateNetObject()
    {
        return new QmlType();
    }

    /// <summary>
    /// Qml can pass .NET types to .NET methods.
    /// </summary>
    /// <param name="parameter"></param>
    public void TestMethod(QmlType parameter)
    {
    }

    /// <summary>
    /// Qml can also pass Qml/C++ objects that can be invoked from .NET
    /// </summary>
    /// <param name="qObject"></param>
    public void TestMethodWithQObject(dynamic qObject)
    {
        string result = qObject.PropertyDefinedInCpp;
        qObject.MethodDefinedInCpp(result);
    }
    
    /// <summary>
    /// Async methods can be invoked with continuations happening on Qt's main thread.
    /// </summary>
    public async Task TestAsync()
    {
        Console.WriteLine("Hello from UI thread!");
        await Task.Run(() =>
        {
            Console.WriteLine("Hello from background thread!");
        });
        Console.WriteLine("Welcome back to the UI thread!");
    }
}

Register your new type with Qml.

using (var app = new QGuiApplication(r))
{
    using (var engine = new QQmlApplicationEngine())
    {
        // Register our new type to be used in Qml
        QQmlApplicationEngine.RegisterType<QmlType>("test", 1, 1);
        engine.loadFile("main.qml");
        return app.exec();
    }
}

Use the .NET type in Qml

import QtQuick 2.7
import QtQuick.Controls 2.0
import QtQuick.Layouts 1.0
import test 1.1

ApplicationWindow {
    visible: true
    width: 640
    height: 480
    title: qsTr("Hello World")

    QmlType {
      id: test
      Component.onCompleted: function() {
          // Wire up signal event handlers
          test.CustomEvent.connect(testHandler)
          // And invoke them. This will also trigger any event
          // handlers assigned in .NET.
          test.CustomEvent("Event message")
          // We can read/set properties
          console.log(test.StringProperty)
          test.StringProperty = "New value!"
          // We can return .NET types (even ones not registered with Qml).
          var netObject = test.CreateNetObject();
          // All properties/methods/signals can be invoked on "netObject"
          // We can also pass the .NET object back to .NET
          netObject.TestMethod(netObject)
      }
      function testHandler(message) {
          console.log("Message - " message)
      }
    }
}

Building and running

Setting up an environment takes a little effort, but it is easy enough.

  1. Install Qt and Qt Creator.
  2. Build and deploy src/native/QtNetCoreQml/QtNetCoreQml.pro.
  3. Open src/net/Qt.NetCore.sln and run the sandbox! Mark sure your LD_LIBRARY_PATH (etc) is setup for your app to properly find your QtNetCoreQml installation.

There will be a proper NuGet/MyGet feed shortly.

Also, there is no plans to ever bundle the native libraries into the NuGet packages considering the complexity of a traditional Qt installation. It will always be recommend/required to install the native QtNetCoreQml on the OS of your choice.

Currently implemented

  • Support for all the basic Qml types and the back-and-forth between them (DateTime, string, etc).
  • Reading/setting properties on .NET objects.
  • Invoking methods on .NET obejcts.

Not implemented (but planned)

  • Compiling Qml resource files and bundling them within .NET.
  • Passing dynamic javascript objects to .NET as dynamic. They will be either a live mutable instance, or as a JSON serialized snapshot of the object.
  • Passing QObject types to .NET with support for interacting with signals/slots/properties on them.
  • Cancellable async tasks.
  • Return value from async tasks.
  • INotifyPropertyChanged support for signal notification of property changes in Qml. This will allow Qml to bind to .NET properties.
  • .NET Events to signals
  • Custom V8 type that looks like an array, but wraps a .NET IList<T> instance, for modification of list in Qml, and performance.
  • General perf improvements (particularly with reflection).
  • NuGet/MyGet feed.