Skip to main content

vizia_core/binding/
mod.rs

1//! Data binding provides a way to link views to model data so that view properties update when data changes.
2//!
3//! # Example
4//! First we declare some data for our application:
5//! ```
6//! # use vizia_core::prelude::*;
7//!
8//!
9//! struct AppData {
10//!     count: i32,
11//! }
12//!
13//! ```
14//! 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
15//! to the app data to mutate it and updated values are sent to observers, such as a [`Binding`] view.
16//! ```
17//! enum AppEvent {
18//!     Increment,
19//!     Decrement,
20//! }
21//! ```
22//! Then we implement the [`Model`](crate::model::Model) trait on our data, which allows us to modify the it in response to an [`Event`](crate::events::Event):
23//! ```
24//! # use vizia_core::prelude::*;
25//!
26//!
27//! struct AppData {
28//!     count: i32,
29//! }
30//!
31//! enum AppEvent {
32//!     Increment,
33//!     Decrement,
34//! }
35//!
36//! impl Model for AppData {
37//!     fn event(&mut self, cx: &mut EventContext, event: &mut Event) {
38//!         event.map(|app_event, _| match app_event {
39//!             AppEvent::Increment => {
40//!                 self.count += 1;
41//!             }
42//!
43//!             AppEvent::Decrement => {
44//!                 self.count -= 1;
45//!             }
46//!         });
47//!     }
48//! }
49//! ```
50//! This trait also allows data to be built into the application [Tree](crate::prelude::Tree):
51//! ```ignore
52//! # use vizia_core::prelude::*;
53//!
54//! # use vizia_winit::application::Application;
55//!
56//! struct AppData {
57//!     count: i32,
58//! }
59//!
60//! impl Model for AppData {}
61//!
62//! fn main() {
63//!     Application::new(|cx|{
64//!         AppData {
65//!             count: 0,
66//!         }.build(cx);
67//!     }).run();  
68//! }
69//! ```
70//! A [`Binding`] view is one way in which data can be used by views. It observes a signal and rebuilds whenever the signal changes:
71//! ```ignore
72//! # use vizia_core::prelude::*;
73//!
74//! # use vizia_winit::application::Application;
75//!
76//! struct AppData {
77//!     count: Signal<i32>,
78//! }
79//!
80//! impl Model for AppData {
81//!     fn event(&mut self, cx: &mut EventContext, event: &mut Event) {
82//!         event.map(|app_event, _| match app_event {
83//!             AppEvent::Increment => {
84//!                 self.count.update(|count| *count += 1);
85//!             }
86//!
87//!             AppEvent::Decrement => {
88//!                 self.count.update(|count| *count -= 1);
89//!             }
90//!         });
91//!     }
92//! }
93//!
94//! enum AppEvent {
95//!     Increment,
96//!     Decrement,
97//! }
98//!
99//! fn main() {
100//!     Application::new(|cx|{
101//!         let count = Signal::new(0);
102//!         AppData {
103//!             count,
104//!         }.build(cx);
105//!
106//!         Binding::new(cx, count, |cx|{
107//!             Label::new(cx, count.get().to_string());
108//!         });
109//!
110//!         Button::new(cx, |cx|{
111//!             Label::new(cx, "Increment")
112//!         })
113//!         .on_press(|cx| cx.emit(AppEvent::Increment));
114//!
115//!         Button::new(cx, |cx|{
116//!             Label::new(cx, "Decrement")
117//!         })
118//!         .on_press(|cx| cx.emit(AppEvent::Decrement));
119//!     }).run();
120//! }
121//! ```
122//! Note, the button does not need to be bound to the data to send an event to it. By default events will propagate up the tree.
123//!
124//! Completely rebuilding the `Label` when the data changes is unnecessary in this case. Instead we can pass a signal directly to
125//! the view constructor so only the relevant property updates.
126//! ```ignore
127//! # use vizia_core::prelude::*;
128//! # use vizia_winit::application::Application;
129//!
130//! fn main() {
131//!     Application::new(|cx|{
132//!         let count = Signal::new(0);
133//!
134//!         Label::new(cx, count);
135//!
136//!         Button::new(cx, |cx|{
137//!             Label::new(cx, "Increment")
138//!         })
139//!         .on_press(move |_| count.update(|v| *v += 1));
140//!
141//!         Button::new(cx, |cx|{
142//!             Label::new(cx, "Decrement")
143//!         })
144//!         .on_press(move |_| count.update(|v| *v -= 1));
145//!     }).run();
146//! }
147//! ```
148//!
149//! Note that even though the `count` value is `i32`, the label accepts it because it implements `ToString` and is converted internally.
150//! If the data is the wrong type and cannot be converted internally, use a mapped signal or a custom formatter.
151mod handler;
152pub(crate) use handler::BindingHandler;
153
154mod res;
155pub use res::*;
156
157#[allow(clippy::module_inception)]
158mod binding;
159pub use binding::Binding;