Tutorial: Sharing data between XAML and openFrameworks in WinRT applications

Now that the openFrameworks porting project on Windows 8 is public , developers can share data between XAML and openFrameworks code. In this Tutorial I will walk you through the simple steps to make it happen in your own app.

Create a XAML-WinRT openFrameworks Project

As I outlined in a previous blog post creating an openFrameworks project with projectGeneratorSimple_winrt.exe (located in your copy of openFrameworks repository) is pretty straightforward.

clip_image002

After generation, the new project will appear in the ...\apps\myapps folder. The directory will contain two Visual Studio solution files as well as several other source files, including the xaml files:

clip_image003

Use Visual Studio 2013 to open the second (*xaml.sln) file, then build and run the application. The application will display the following message:

clip_image005

 

To view more details about the internal project structure, you can open the DirectXPage.xaml in Visual Studio and see the XAML code in the XAML designer. XAML allows you to visually define the screens of your application. The following is a TextBlock control in design mode.

clip_image007

Looking at the page tag within the above XAML code more in detail, we can see:

<TextBlock x:Name="SimpleTextBlock" HorizontalAlignment="Center" FontSize="42" Height="72" Text="Hello, XAML!" Margin="0,0,0,50"/>

To add a button and a textbox on the screen, just drag and drop it from the toolbox on the design surface:

clip_image009

Now there are three lines in the XAML panel:

<TextBlock x:Name="SimpleTextBlock" HorizontalAlignment="Center" FontSize="42"

                                     Height="72" Text="Hello, XAML!" Margin="0,0,0,50"/>

<Button x:Name="conte" HorizontalAlignment="Left" Margin="88,82,0,0"

                                       VerticalAlignment="Top" Height="65" Width="317"/>

<TextBox x:Name="Text1" HorizontalAlignment="Left" Margin="787,85,0,0"

    TextWrapping="Wrap" Text="TextBox" VerticalAlignment="Top" Height="59" Width="361"/>

 

XAML Data Binding

One of the core features of XAML is that it provides a very robust data binding engine. With XAML data binding you can bind to control different types of objects (controls fields, code data, etc.).

To create a binding between the button’s text and the textbox’s text, we recommend that you use the visual tools in the IDE: Visual Studio provides a specialized dialog box for this purpose. Just open the property window for the Button control, and then click the orange button at the right of the Content property as shown below.

clip_image002[11] clip_image004[4]

A lot of binding options are available by simply selecting an element by its name. The tool can then generate a binding property within the XAML tag:

<Button x:Name="conte" Content="{Binding Text, ElementName=Text1}" .../>

 

clip_image015

For a complete overview of Data Binding in C++ with XAML, we encourage you to review Andy Rich’s Introducing C++/CX and XAML article in MSDN magazine, and to learn from him how ‘reflection’ works in a separate article entitled Connecting C++ and XAML.

openFrameworks Application Object is a Singleton

When you derive your application class from the layer object, you define your application object, which is a singleton:

class ofApp : public ofBaseApp {

 

       public:

              void setup();

              void update();

              void draw();

}

This ofApp class is used in the ofXamlAppMain Class to start the OF rendering: 

ofRunAppXaml(ofPtr<ofApp>(new ofApp()));

As the Application instance is unique (singleton), openFrameworks provide a global function to retrieve it: ofGetAppPtr(). So we can use it in XAML code to access data members in the ofApp class.

For example, if my ofApp class contains a data member myvalue exposed by the property SetValue(), we can access it from the XAML scene with a call like this:

int x = ((ofApp*)ofGetAppPtr())->setValue(value); ;

Of course the XAML scene file must include our ofApp declaration:

       #include "src/ofapp.h"

 

Bind OF Data to XAML control

To bind a control to a class, we will need the class to implement the interface INotifyPropertyChanged or at minimum have the Bindable attribute. For this sample, I created a simple Bindable Class and used the following attribute:

[Windows::UI::Xaml::Data::Bindable]

       public ref class SampleBindableClass sealed

       {

       public:

              SampleBindableClass();

              property Platform::String^ string1;

              property float fvalue1{

                     float get();

                     void set(float value);

              }

 

       private:

              float m_fvalue1;    

       };

I then used the visual binding to bind this class to a slider control that I added to the screen definition:

                <Slider x:Name="slider" Value="{Binding fvalue1, Mode=TwoWay}" .../>

Then, when I change the slider value at runtime, fvalue1 will update automatically. (In this case, I set the attribute Mode to TwoWay to demonstrate that the two-way option is available, although it is not necessary in this sample.

This class has a float data member (m_fvalue1) exposed via a property fvalue1. I explicitly implemented the getter and the setter of the property to have the possibility to hook the set calls and propagate the new value to OF scene:

void SampleBindableClass::fvalue1::set(float value) {

 

m_fvalue1 = value;

              ((ofApp*)ofGetAppPtr())->setValue(value);

       }

That’s it. You may run the application again and use myvalue in your OF code, to draw a sphere:  (myvalue is declared in the ofApp class, in the .h file)

                void ofApp::draw(){

              ofNoFill();

              ofSphere(myvalue+100, 500, myvalue);

}

image

 

Et voila - the size of the openFrameworks 3D sphere is now controlled by the XAML slider.

I hope you enjoyed this article! Let me know whether XAML binding is valuable for you as you work with OF code. 

A bientôt,

Eric

 


Leave a Reply