Skip to main content

ferroui_base/data/
template_binding.rs

1use crate::data::compiled_binding::binding_properties;
2use crate::data::converters::IValueConverter;
3use crate::data::{BindingBase, BindingExpressionBase, BindingMode, TemplateBindingExpression};
4use crate::utilities::CultureInfo;
5use crate::{BoxedValue, FerroObject, FerroProperty, Ref};
6use std::rc::Rc;
7
8binding_properties! {
9    /// A lightweight binding to a property of an element's templated parent.
10    ///
11    /// A binding is a mutable reference object: it is created with
12    /// [`TemplateBinding::empty`] or [`TemplateBinding::new`], configured
13    /// property by property (or with the chaining `with_*` forms) and shared
14    /// as `Rc<TemplateBinding>`, which converts to `Rc<dyn BindingBase>`.
15    /// Handles compare by identity. The properties are read when the binding
16    /// is instantiated on a target: changing them afterwards affects later
17    /// instances only.
18    pub struct TemplateBinding {
19        /// The converter to use.
20        converter / set_converter / with_converter_value: Option<Rc<dyn IValueConverter>> = None,
21        /// The culture in which to evaluate the converter. `None` (the
22        /// default) uses the current culture.
23        converter_culture / set_converter_culture / with_converter_culture: Option<CultureInfo> = None,
24        /// A parameter to pass to the converter.
25        converter_parameter / set_converter_parameter / with_converter_parameter: Option<BoxedValue> = None,
26        /// The binding mode.
27        mode / set_mode / with_mode: BindingMode = BindingMode::default(),
28        /// The property of the templated parent being bound; `None` binds to
29        /// the templated parent itself.
30        property / set_property / with_property: Option<&'static FerroProperty> = None,
31    }
32}
33
34impl TemplateBinding {
35    /// Creates a binding without a property (the parameterless
36    /// constructor).
37    pub fn empty() -> Rc<Self> {
38        Rc::new(Self::default())
39    }
40
41    /// Creates a binding to the given property of the templated parent.
42    pub fn new(property: &'static FerroProperty) -> Rc<Self> {
43        Self::empty().with_property(Some(property))
44    }
45
46    /// The chaining form of [`set_converter`](Self::set_converter), for a
47    /// converter.
48    pub fn with_converter(self: Rc<Self>, converter: Rc<dyn IValueConverter>) -> Rc<Self> {
49        self.with_converter_value(Some(converter))
50    }
51
52    /// The binding itself: what the markup extension form of the binding
53    /// provides.
54    pub fn provide_value(self: &Rc<Self>) -> Rc<dyn BindingBase> {
55        self.clone()
56    }
57}
58
59impl BindingBase for TemplateBinding {
60    fn as_any(&self) -> Option<&dyn std::any::Any> {
61        Some(self)
62    }
63
64    fn create_instance(
65        &self,
66        _target: &FerroObject,
67        _target_property: Option<&'static FerroProperty>,
68        _anchor: Option<&Ref<FerroObject>>,
69    ) -> Rc<dyn BindingExpressionBase> {
70        let mode = self.mode();
71        if matches!(mode, BindingMode::OneTime | BindingMode::OneWayToSource) {
72            panic!("TemplateBinding does not support OneTime or OneWayToSource bindings.");
73        }
74        TemplateBindingExpression::new(
75            self.property(),
76            self.converter(),
77            self.converter_culture(),
78            self.converter_parameter(),
79            mode,
80        )
81    }
82}