use crate::collections::FerroList;
use crate::data::compiled_binding::binding_properties;
use crate::data::converters::{IMultiValueConverter, StringFormatMultiValueConverter};
use crate::data::core::plugins::property_value_type;
use crate::data::core::{MultiBindingExpression, ValueType};
use crate::data::{BindingBase, BindingExpressionBase, BindingMode, BindingPriority, RelativeSource};
use crate::utilities::CultureInfo;
use crate::{BoxedValue, FerroObject, FerroProperty, Ref};
use std::rc::Rc;
binding_properties! {
pub struct MultiBinding {
bindings / set_bindings / with_bindings_list: FerroList<Rc<dyn BindingBase>> = FerroList::new(),
converter / set_converter / with_converter_value: Option<Rc<dyn IMultiValueConverter>> = None,
converter_culture / set_converter_culture / with_converter_culture: Option<CultureInfo> = None,
converter_parameter / set_converter_parameter / with_converter_parameter: Option<BoxedValue> = None,
fallback_value / set_fallback_value / with_fallback_value: Option<BoxedValue> = Some(FerroProperty::unset_value()),
mode / set_mode / with_mode: BindingMode = BindingMode::OneWay,
priority / set_priority / with_priority: BindingPriority = BindingPriority::LocalValue,
relative_source / set_relative_source / with_relative_source: Option<Rc<RelativeSource>> = None,
string_format / set_string_format / with_string_format: Option<String> = None,
target_null_value / set_target_null_value / with_target_null_value: Option<BoxedValue> = Some(FerroProperty::unset_value()),
}
}
impl MultiBinding {
pub fn new() -> Rc<Self> {
Rc::new(Self::default())
}
pub fn with_bindings(self: Rc<Self>, bindings: Vec<Rc<dyn BindingBase>>) -> Rc<Self> {
let list = self.bindings();
list.clear();
list.add_range(bindings);
self
}
pub fn with_converter(self: Rc<Self>, converter: Rc<dyn IMultiValueConverter>) -> Rc<Self> {
self.with_converter_value(Some(converter))
}
}
impl BindingBase for MultiBinding {
fn as_any(&self) -> Option<&dyn std::any::Any> {
Some(self)
}
fn create_instance(
&self,
_target: &FerroObject,
target_property: Option<&'static FerroProperty>,
_anchor: Option<&Ref<FerroObject>>,
) -> Rc<dyn BindingExpressionBase> {
let target_type = target_property.map_or_else(ValueType::object, property_value_type);
let mut converter = self.converter();
let string_format = self.string_format();
if let Some(format) = string_format.as_deref().filter(|s| !s.trim().is_empty()) {
if target_type.is_string() || target_type.is_object() {
converter = Some(Rc::new(StringFormatMultiValueConverter::new(format, converter)));
}
}
MultiBindingExpression::new(
self.priority(),
self.bindings().to_vec(),
converter,
self.converter_culture(),
self.converter_parameter(),
self.fallback_value(),
self.target_null_value(),
)
}
}