Module vizia::binding

source ·
Expand description

Data binding provides a way to link views to model data so that view properties update when data changes.

§Example

Fist we declare some data for our application. The Lens trait has been derived for the data, which allows us to bind to fields of the struct:

#[derive(Lens)]
struct AppData {
    count: i32,
}

Next we’ll declare some events which will be sent by views to modify the data. Data binding in vizia is one-way, events are sent up the tree to the app data to mutate it and updated values are sent to observers, such as a Binding view.

enum AppEvent {
    Increment,
    Decrement,
}

Then we implement the Model trait on our data, which allows us to modify the it in response to an Event:

#[derive(Lens)]
struct AppData {
    count: i32,
}

enum AppEvent {
    Increment,
    Decrement,
}

impl Model for AppData {
    fn event(&mut self, cx: &mut EventContext, event: &mut Event) {
        event.map(|app_event, _| match app_event {
            AppEvent::Increment => {
                self.count += 1;
            }

            AppEvent::Decrement => {
                self.count -= 1;
            }
        });
    }
}

This trait also allows data to be built into the application Tree:

#[derive(Lens)]
struct AppData {
    count: i32,
}

impl Model for AppData {}

fn main() {
    Application::new(|cx|{
        AppData {
            count: 0,
        }.build(cx);
    }).run();  
}

A Binding view is one way in which data can be used by views. A Lens is used to determine what data the binding should react to:

#[derive(Lens)]
struct AppData {
    count: i32,
}

impl Model for AppData {}

fn main() {
    Application::new(|cx|{
        AppData {
            count: 0,
        }.build(cx);

        Binding::new(cx, AppData::count, |cx, count|{
            Label::new(cx, &count.get(cx).to_string());
        });
    }).run();
}

The second parameter to the Binding view is a Lens, allowing us to bind to some field of the application data. The third parameter is a closure which provides the context and the lens, which can be used to retrieve the bound data using the .get() method, which takes the Context as an argument.

Now when the data is modified, the binding will rebuild its contents and the label will update, for example:

#[derive(Lens)]
struct AppData {
    count: i32,
}

impl Model for AppData {
    fn event(&mut self, cx: &mut EventContext, event: &mut Event) {
        event.map(|app_event, _| match app_event {
            AppEvent::Increment => {
                self.count += 1;
            }

            AppEvent::Decrement => {
                self.count -= 1;
            }
        });
    }
}

enum AppEvent {
    Increment,
    Decrement,
}

fn main() {
    Application::new(|cx|{
        AppData {
            count: 0,
        }.build(cx);

        Binding::new(cx, AppData::count, |cx, count|{
            Label::new(cx, &count.get(cx).to_string());
        });

        Button::new(cx, |cx| cx.emit(AppEvent::Increment), |cx|{
            Label::new(cx, "Increment")
        });

        Button::new(cx, |cx| cx.emit(AppEvent::Increment), |cx|{
            Label::new(cx, "Decrement")
        });
    }).run();
}

Note, the checkbox does not need to be bound to the data to send an event to it. By default events will propagate up the tree.

Completely rebuilding the Label when the data changes is unnecessary in this case. Instead we can update just the text of the label by binding the text() property modifier to the application data. This is called a property binding.


fn main() {
    Application::new(|cx|{
        AppData {
            count: 0,
        }.build(cx);

        Label::new(cx, AppData::count);

        Button::new(cx, |cx|{
            Label::new(cx, "Increment")
        })
        .on_press(|cx| cx.emit(AppEvent::Increment));

        Button::new(cx, |cx|{
            Label::new(cx, "Decrement")
        })
        .on_press(|cx| cx.emit(AppEvent::Increment));
    }).run();
}

Note that even though the count value is i32, the label accepts a lens to this data because it implements ToString and is converted internally. If the data is the wrong type and cannot be converted internally, use the map() method on the lens.

Structs§

Enums§

  • A type returned by Lens::view() which contains either a reference to model data or an owned value.

Traits§

  • A trait for fast comparisons of data. Implemented by any type which can be bound to, i.e. can be cached and compared against previous versions.
  • A Lens allows the construction of a reference to a piece of some data, e.g. a field of a struct.
  • Helpers for constructing more complex Lenses.
  • A trait which allows passing a value or a lens to a view or modifier.