Skip to main content

ferroui_base/data/core/
binding_expression.rs

1use super::expression_nodes::{ExpressionNode, NodeSource};
2use super::{
3    impl_untyped_binding_expression, ExpressionError, ObservableSink, Publish, TargetTypeConverter,
4    UntypedBindingExpression, UntypedBindingExpressionBase, ValueType, ValueTypes, WeakValue,
5};
6use crate::data::converters::{composite_format, IValueConverter};
7use crate::data::{
8    BindingChainException, BindingError, BindingErrorType, BindingMode, BindingNotification, BindingOperations,
9    BindingPriority, UpdateSourceTrigger,
10};
11use crate::logging::{LogArea, LogEventLevel, Logger};
12use crate::input::InputElement;
13use crate::interactivity::RoutedEventHandlerToken;
14use crate::reactive::IDisposable;
15use crate::threading::{Dispatcher, DispatcherPriority, DispatcherTimer};
16use crate::utilities::CultureInfo;
17use crate::{BoxedValue, FerroObject, FerroProperty, Ref, UnsetValueType};
18use std::any::Any;
19use std::cell::{Cell, RefCell};
20use std::rc::{Rc, Weak};
21use std::time::Duration;
22
23/// The options of a [`BindingExpression`].
24pub struct BindingExpressionOptions {
25    /// The amount of time, in milliseconds, to wait before updating the
26    /// binding source after the value on the target changes.
27    pub delay: i32,
28    /// The fallback value; the unset marker for no fallback.
29    pub fallback_value: Option<BoxedValue>,
30    pub converter: Option<Rc<dyn IValueConverter>>,
31    /// The culture in which to evaluate the converter; `None` for the
32    /// current culture.
33    pub converter_culture: Option<CultureInfo>,
34    pub converter_parameter: Option<BoxedValue>,
35    pub enable_data_validation: bool,
36    pub mode: BindingMode,
37    pub priority: BindingPriority,
38    pub string_format: Option<String>,
39    /// The value to use when the binding produces null; the unset marker (or
40    /// null) for none.
41    pub target_null_value: Option<BoxedValue>,
42    pub target_property: Option<&'static FerroProperty>,
43    pub target_type_converter: Option<TargetTypeConverter>,
44    pub update_source_trigger: UpdateSourceTrigger,
45}
46
47impl Default for BindingExpressionOptions {
48    fn default() -> Self {
49        Self {
50            delay: 0,
51            fallback_value: Some(FerroProperty::unset_value()),
52            converter: None,
53            converter_culture: None,
54            converter_parameter: None,
55            enable_data_validation: false,
56            mode: BindingMode::OneWay,
57            priority: BindingPriority::LocalValue,
58            string_format: None,
59            target_null_value: Some(FerroProperty::unset_value()),
60            target_property: None,
61            target_type_converter: None,
62            update_source_trigger: UpdateSourceTrigger::PropertyChanged,
63        }
64    }
65}
66
67/// Uncommonly used fields are separated out to reduce memory usage.
68struct UncommonFields {
69    delay: Duration,
70    delay_timer: RefCell<Option<Rc<DispatcherTimer>>>,
71    delay_tick: RefCell<Option<Rc<dyn IDisposable>>>,
72    converter: Option<Rc<dyn IValueConverter>>,
73    converter_culture: Option<CultureInfo>,
74    converter_parameter: Option<BoxedValue>,
75    fallback_value: Option<BoxedValue>,
76    string_format: Option<String>,
77    target_null_value: Option<BoxedValue>,
78    update_source_trigger: UpdateSourceTrigger,
79}
80
81fn is_unset(value: &Option<BoxedValue>) -> bool {
82    value.as_ref().is_some_and(|v| v.is::<UnsetValueType>())
83}
84
85/// A binding expression which accepts and produces (possibly boxed) untyped
86/// values: a source, a path of expression nodes read from it, and the
87/// conversion of the result to the target.
88pub struct BindingExpression {
89    this: Weak<BindingExpression>,
90    base: UntypedBindingExpressionBase,
91    /// `None` when the binding source is null.
92    source: Option<WeakValue>,
93    mode: BindingMode,
94    nodes: Vec<Rc<dyn ExpressionNode>>,
95    target_type_converter: Option<TargetTypeConverter>,
96    uncommon: Option<Box<UncommonFields>>,
97    update_target_depth: Cell<u32>,
98    should_update_one_time_binding_target: Cell<bool>,
99    target_subscription: RefCell<Option<Rc<dyn IDisposable>>>,
100    lost_focus_token: RefCell<Option<RoutedEventHandlerToken>>,
101}
102
103impl BindingExpression {
104    /// Creates a binding expression.
105    ///
106    /// `source` is the object from which the value is read (null is `None`);
107    /// `nodes` represent the binding path.
108    pub fn new(
109        source: Option<BoxedValue>,
110        nodes: Vec<Rc<dyn ExpressionNode>>,
111        options: BindingExpressionOptions,
112    ) -> Rc<Self> {
113        if options.mode == BindingMode::Default {
114            panic!("Binding mode cannot be Default.");
115        }
116        if options.update_source_trigger == UpdateSourceTrigger::Default {
117            panic!("UpdateSourceTrigger cannot be Default.");
118        }
119        let source = source.filter(|s| !s.is::<UnsetValueType>());
120        let string_format = options.string_format.filter(|s| !s.trim().is_empty());
121        let has_target_null_value = options.target_null_value.as_ref().is_some_and(|v| !v.is::<UnsetValueType>());
122
123        let uncommon = if options.delay > 0
124            || options.converter.is_some()
125            || options.converter_culture.is_some()
126            || options.converter_parameter.is_some()
127            || !is_unset(&options.fallback_value)
128            || string_format.is_some()
129            || has_target_null_value
130            || options.update_source_trigger != UpdateSourceTrigger::PropertyChanged
131        {
132            Some(Box::new(UncommonFields {
133                delay: Duration::from_millis(options.delay.max(0) as u64),
134                delay_timer: RefCell::new(None),
135                delay_tick: RefCell::new(None),
136                converter: options.converter,
137                converter_culture: options.converter_culture,
138                converter_parameter: options.converter_parameter,
139                fallback_value: options.fallback_value,
140                string_format: string_format.map(|s| if s.contains('{') { s } else { format!("{{0:{s}}}") }),
141                target_null_value: if has_target_null_value {
142                    options.target_null_value
143                } else {
144                    Some(FerroProperty::unset_value())
145                },
146                update_source_trigger: options.update_source_trigger,
147            }))
148        } else {
149            None
150        };
151
152        let mode = options.mode;
153        let this = Rc::new_cyclic(|this: &Weak<BindingExpression>| BindingExpression {
154            this: this.clone(),
155            base: UntypedBindingExpressionBase::new(
156                this.clone(),
157                options.priority,
158                options.target_property,
159                options.enable_data_validation,
160            ),
161            source: source.as_ref().map(WeakValue::new),
162            mode,
163            nodes,
164            target_type_converter: options.target_type_converter,
165            uncommon,
166            update_target_depth: Cell::new(0),
167            should_update_one_time_binding_target: Cell::new(mode == BindingMode::OneTime),
168            target_subscription: RefCell::new(None),
169            lost_focus_token: RefCell::new(None),
170        });
171
172        let mut leaf_accessor = None;
173        for (i, node) in this.nodes.iter().enumerate() {
174            node.set_owner(Rc::downgrade(&this), i);
175            if let Some(n) = node.as_property_accessor_node() {
176                leaf_accessor = Some(n);
177            }
178        }
179        if options.enable_data_validation {
180            if let Some(leaf) = leaf_accessor {
181                leaf.enable_data_validation();
182            }
183        }
184        this
185    }
186
187    /// The type of the value accepted by the binding source, if it can be
188    /// written.
189    pub fn source_type(&self) -> Option<ValueType> {
190        self.leaf_node().and_then(|n| n.as_settable().and_then(|s| s.value_type()))
191    }
192
193    pub fn converter(&self) -> Option<&Rc<dyn IValueConverter>> {
194        self.uncommon.as_ref().and_then(|u| u.converter.as_ref())
195    }
196
197    /// The culture in which the converter is evaluated: the converter
198    /// culture of the binding, or the current culture when it names none.
199    pub fn converter_culture(&self) -> CultureInfo {
200        self.uncommon
201            .as_ref()
202            .and_then(|uncommon| uncommon.converter_culture.clone())
203            .unwrap_or_else(CultureInfo::current_culture)
204    }
205
206    pub fn converter_parameter(&self) -> Option<&BoxedValue> {
207        self.uncommon.as_ref().and_then(|u| u.converter_parameter.as_ref())
208    }
209
210    /// The fallback value; the unset marker if there is none.
211    pub fn fallback_value(&self) -> Option<BoxedValue> {
212        match &self.uncommon {
213            Some(u) => u.fallback_value.clone(),
214            None => Some(FerroProperty::unset_value()),
215        }
216    }
217
218    pub fn leaf_node(&self) -> Option<&Rc<dyn ExpressionNode>> {
219        self.nodes.last()
220    }
221
222    pub fn nodes(&self) -> &[Rc<dyn ExpressionNode>] {
223        &self.nodes
224    }
225
226    pub fn mode(&self) -> BindingMode {
227        self.mode
228    }
229
230    pub fn string_format(&self) -> Option<&str> {
231        self.uncommon.as_ref().and_then(|u| u.string_format.as_deref())
232    }
233
234    /// The target null value; the unset marker if there is none.
235    pub fn target_null_value(&self) -> Option<BoxedValue> {
236        match &self.uncommon {
237            Some(u) => u.target_null_value.clone(),
238            None => Some(FerroProperty::unset_value()),
239        }
240    }
241
242    /// The amount of time to wait before updating the binding source after
243    /// the value on the target changes.
244    pub fn delay(&self) -> Duration {
245        self.uncommon.as_ref().map_or(Duration::ZERO, |u| u.delay)
246    }
247
248    fn stop_delay_timer(&self) {
249        if let Some(u) = &self.uncommon {
250            let timer = u.delay_timer.borrow().clone();
251            if let Some(timer) = timer {
252                timer.stop();
253            }
254        }
255    }
256
257    pub fn update_source_trigger(&self) -> UpdateSourceTrigger {
258        self.uncommon.as_ref().map_or(UpdateSourceTrigger::PropertyChanged, |u| u.update_source_trigger)
259    }
260
261    /// The current error state of the binding expression.
262    pub fn error_type(&self) -> BindingErrorType {
263        self.base.error_type()
264    }
265
266    /// Produces an observable subject over the expression, see
267    /// [`ObservableSink`].
268    pub fn to_observable(self: &Rc<Self>, target: Option<&FerroObject>) -> Rc<ObservableSink> {
269        ObservableSink::create(self, target)
270    }
271
272    /// Called by a node belonging to this binding when its value changes.
273    pub(crate) fn on_node_value_changed(
274        &self,
275        node_index: usize,
276        value: Option<BoxedValue>,
277        data_validation_error: Option<&BindingError>,
278    ) {
279        debug_assert!(node_index < self.nodes.len());
280        let count = self.nodes.len();
281
282        if node_index == count - 1 {
283            if self.mode == BindingMode::OneTime {
284                // In OneTime mode, only changing the data context updates the binding.
285                if !self.should_update_one_time_binding_target.get() && !self.nodes[node_index].is_data_context_node() {
286                    return;
287                }
288                self.should_update_one_time_binding_target.set(false);
289            }
290
291            let error = data_validation_error
292                .map(|e| ExpressionError::new(e.clone(), BindingErrorType::DataValidationError));
293
294            // The leaf node has changed. If the binding mode is not
295            // OneWayToSource, publish the value to the target.
296            if self.mode != BindingMode::OneWayToSource {
297                // An explicit target update must reapply the source value
298                // even if this expression already has it cached: a two-way
299                // target may contain an uncommitted local value.
300                let force_update = self.mode == BindingMode::OneWay || self.update_target_depth.get() > 0;
301                self.convert_and_publish_value(value, error, force_update);
302            } else if self.base.is_data_validation_enabled() {
303                // In OneWayToSource mode the value must not be published to
304                // the target, but any data validation error produced when
305                // writing to the source still has to be published (or
306                // cleared) so that it can be displayed.
307                self.base.publish_value(Publish::Unchanged, error, false);
308            }
309        } else if self.mode == BindingMode::OneWayToSource && node_index + 2 == count && value.is_some() {
310            // When the binding mode is OneWayToSource, the value is written
311            // to the source when the object holding the source property
312            // changes; this is the node before the leaf node. First update
313            // the leaf node's source, then write the value to its property.
314            self.nodes[node_index + 1].set_source(NodeSource::Value(value), data_validation_error);
315            self.write_target_value_to_source();
316        } else {
317            if self.mode == BindingMode::OneTime && self.nodes[node_index].is_data_context_node() {
318                self.should_update_one_time_binding_target.set(true);
319            }
320            self.nodes[node_index + 1].set_source(NodeSource::Value(value), data_validation_error);
321        }
322    }
323
324    /// Called by a node belonging to this binding when a null-conditional
325    /// operator applied to it encounters a null source: the remainder of the
326    /// path is short-circuited and null is published as the binding's value.
327    pub(crate) fn on_node_null_short_circuit(&self, node_index: usize) {
328        for node in &self.nodes[node_index + 1..] {
329            node.propagate_null_short_circuit_value();
330        }
331        // Publish the null value as if it were produced by the leaf node.
332        self.on_node_value_changed(self.nodes.len() - 1, None, None);
333    }
334
335    /// Called by a node belonging to this binding when an error occurs
336    /// reading its value. `node_index` is -1 if the source is null.
337    pub(crate) fn on_node_error(&self, node_index: isize, error: &str) {
338        // Set the source of all nodes after the one that errored to unset.
339        // This needs to be done for each node individually because setting
340        // the source to unset does not notify the binding.
341        for node in &self.nodes[(node_index + 1) as usize..] {
342            node.set_source(NodeSource::Unset, None);
343        }
344
345        if self.mode == BindingMode::OneWayToSource {
346            return;
347        }
348
349        let error_point = self.calculate_error_point(node_index);
350        if let Some(target) = self.should_log_error() {
351            self.log_at(&target, error, &error_point, LogEventLevel::Warning);
352        }
353
354        // Clear the current value and publish the error.
355        let binding_error = ExpressionError::new(
356            BindingError::new(BindingChainException::with_expression(error, self.description(), error_point)),
357            BindingErrorType::Error,
358        );
359        self.convert_and_publish_value(Some(FerroProperty::unset_value()), Some(binding_error), false);
360    }
361
362    pub(crate) fn on_data_validation_error(&self, error: BindingError) {
363        let binding_error = ExpressionError::new(error, BindingErrorType::DataValidationError);
364        self.base.publish_value(Publish::Unchanged, Some(binding_error), false);
365    }
366
367    fn calculate_error_point(&self, node_index: isize) -> String {
368        // A string describing the binding chain up to the node that errored.
369        let mut result = String::new();
370        if node_index >= 0 {
371            self.nodes[node_index as usize].build_string(&mut result);
372        } else {
373            result.push_str("(source)");
374        }
375        result
376    }
377
378    fn log_at(&self, target: &FerroObject, error: &str, error_point: &str, level: LogEventLevel) {
379        let Some(log) = Logger::try_get(level, LogArea::BINDING) else { return };
380        let property = self.base.target_property().map_or("(unknown)", |p| p.name());
381        let description = self.description();
382        log.log_with_values(
383            Some(target as &dyn Any),
384            "An error occurred binding {Property} to {Expression} at {ExpressionErrorPoint}: {Message}",
385            &[&property, &description, &error_point, &error],
386        );
387    }
388
389    fn convert_and_publish_value(
390        &self,
391        value: Option<BoxedValue>,
392        error: Option<ExpressionError>,
393        force_update: bool,
394    ) {
395        let mut value = value;
396        let mut error = error;
397        let mut is_target_null_value = false;
398        let target_type = self.base.target_type();
399
400        // All values other than the unset and do-nothing markers are passed
401        // to the converter.
402        if let Some(converter) = self.converter() {
403            if !is_unset(&value) && !BindingOperations::is_do_nothing(value.as_ref()) {
404                value = self.base.convert(
405                    &|| self.should_log_error(),
406                    &|| self.description(),
407                    &**converter,
408                    Some(&self.converter_culture()),
409                    self.converter_parameter(),
410                    value.as_ref(),
411                    target_type,
412                    &mut error,
413                );
414                // A converter may report its result as a notification.
415                let converted = value.clone();
416                if let Some(n) = converted.as_ref().and_then(|v| v.downcast_ref::<BindingNotification>()) {
417                    if let Some(e) = n.error() {
418                        error = Some(ExpressionError::new(e, n.error_type()));
419                    }
420                    value = if n.has_value() { n.value() } else { Some(FerroProperty::unset_value()) };
421                }
422            }
423        }
424
425        // Check this here as the converter may return the do-nothing marker.
426        if BindingOperations::is_do_nothing(value.as_ref()) {
427            return;
428        }
429
430        // The target null value only applies when the value is null: the
431        // unset marker indicates a binding error, for which it is not used.
432        let target_null_value = self.target_null_value();
433        if value.is_none() && !is_unset(&target_null_value) {
434            value = self.convert_fallback(target_null_value, "TargetNullValue");
435            is_target_null_value = true;
436        }
437
438        // If we have a value, try to convert it to the target type.
439        if !is_unset(&value) {
440            match self.string_format() {
441                Some(string_format)
442                    if (target_type.is_object() || target_type.is_string()) && !is_target_null_value =>
443                {
444                    // The string format applies if the target can accept a
445                    // string and the value isn't the target null value.
446                    value = match composite_format::format_values_with(
447                        string_format,
448                        std::slice::from_ref(&value),
449                        &self.converter_culture(),
450                    ) {
451                        Ok(s) => self.convert_from(Some(Rc::new(s)), &mut error),
452                        Err(e) => {
453                            error = Some(ExpressionError::new(BindingError::new(e), BindingErrorType::Error));
454                            Some(FerroProperty::unset_value())
455                        }
456                    };
457                }
458                _ => value = self.convert_from(value, &mut error),
459            }
460        }
461
462        // The fallback value applies if the result from the binding,
463        // converter or target type converter is the unset marker.
464        let fallback_value = self.fallback_value();
465        if is_unset(&value) && !is_unset(&fallback_value) {
466            value = self.convert_fallback(fallback_value, "FallbackValue");
467        }
468
469        self.base.publish_value(Publish::Value(value), error, force_update);
470    }
471
472    fn write_target_value_to_source(&self) {
473        debug_assert!(matches!(self.mode, BindingMode::TwoWay | BindingMode::OneWayToSource));
474        self.stop_delay_timer();
475        if let (Some(target), Some(property)) = (self.base.try_get_target(), self.base.target_property()) {
476            let value = ValueTypes::normalize(target.get_value_untyped(property));
477            self.write_value_to_source(value);
478        }
479    }
480
481    fn convert_fallback(&self, fallback: Option<BoxedValue>, fallback_name: &str) -> Option<BoxedValue> {
482        let target_type = self.base.target_type();
483        if is_unset(&fallback) || (self.base.target_property().is_none() && target_type.is_object()) {
484            return fallback;
485        }
486        // The original converts with its target type converter and the converter culture.
487        let converted = match &self.target_type_converter {
488            Some(converter) => converter.try_convert(fallback.as_ref(), target_type, &self.converter_culture()),
489            None => ValueTypes::try_convert(fallback.as_ref(), target_type),
490        };
491        if let Some(result) = converted {
492            return result;
493        }
494        if let Some(target) = self.base.try_get_target() {
495            self.base.log(
496                &target,
497                &self.description(),
498                &format!(
499                    "Could not convert {fallback_name} '{}' to '{target_type}'.",
500                    ValueTypes::to_display_string(fallback.as_ref())
501                ),
502                LogEventLevel::Error,
503            );
504        }
505        Some(FerroProperty::unset_value())
506    }
507
508    /// Converts a produced value to the target type. Without a target
509    /// property (an expression observed directly) values pass through.
510    fn convert_from(&self, value: Option<BoxedValue>, error: &mut Option<ExpressionError>) -> Option<BoxedValue> {
511        let target_type = self.base.target_type();
512        if self.base.target_property().is_none() && target_type.is_object() {
513            return value;
514        }
515        // The converter of string-path bindings knows conversions the table
516        // of value types does not (the delegate of a method to a command).
517        let converted = match &self.target_type_converter {
518            Some(converter) => converter.try_convert(value.as_ref(), target_type, &self.converter_culture()),
519            None => ValueTypes::try_convert(value.as_ref(), target_type),
520        };
521        if let Some(result) = converted {
522            return result;
523        }
524        let message = format!(
525            "Could not convert '{}' ({}) to '{}'.",
526            ValueTypes::to_display_string(value.as_ref()),
527            value.as_ref().map_or("null", |v| (**v).type_name()),
528            target_type
529        );
530        if let Some(target) = self.should_log_error() {
531            self.base.log(&target, &self.description(), &message, LogEventLevel::Warning);
532        }
533        *error = Some(ExpressionError::new(BindingError::message(message), BindingErrorType::Error));
534        Some(FerroProperty::unset_value())
535    }
536
537    /// Runs the converter on a value on its way to the source. Returns false
538    /// if the converter reported an error, in which case the value is not
539    /// written.
540    fn try_convert_back(&self, value_type: ValueType, value: &mut Option<BoxedValue>) -> bool {
541        let Some(converter) = self.converter() else { return true };
542        if is_unset(value) || BindingOperations::is_do_nothing(value.as_ref()) {
543            return true;
544        }
545        *value = self.base.convert_back(
546            &|| self.should_log_error(),
547            &|| self.description(),
548            &**converter,
549            Some(&self.converter_culture()),
550            self.converter_parameter(),
551            value.as_ref(),
552            value_type,
553        );
554        let converted = value.clone();
555        if let Some(notification) = converted.as_ref().and_then(|v| v.downcast_ref::<BindingNotification>()) {
556            if let Some(error) = notification.error() {
557                match notification.error_type() {
558                    BindingErrorType::DataValidationError => {
559                        if self.base.is_data_validation_enabled() {
560                            self.on_data_validation_error(error);
561                        }
562                    }
563                    _ => {
564                        if let Some(target) = self.should_log_error() {
565                            self.base.log(&target, &self.description(), &error.to_string(), LogEventLevel::Warning);
566                        }
567                        self.base.publish_value(
568                            Publish::Unchanged,
569                            Some(ExpressionError::new(error, BindingErrorType::Error)),
570                            false,
571                        );
572                    }
573                }
574                return false;
575            }
576            *value = notification.value();
577        }
578        true
579    }
580
581    fn on_target_property_changed(&self) {
582        debug_assert!(matches!(self.mode, BindingMode::TwoWay | BindingMode::OneWayToSource));
583        let delay = self.delay();
584        let Some(uncommon) = self.uncommon.as_ref().filter(|_| !delay.is_zero()) else {
585            // The value is read from the target object instead of the change
586            // notification because it may have changed again in between.
587            self.write_target_value_to_source();
588            return;
589        };
590
591        let existing = uncommon.delay_timer.borrow().clone();
592        let timer = match existing {
593            Some(timer) => {
594                timer.stop();
595                timer
596            }
597            None => {
598                let timer = DispatcherTimer::with_interval(
599                    delay,
600                    DispatcherPriority::DEFAULT,
601                    &Dispatcher::current_dispatcher(),
602                );
603                let weak = self.this.clone();
604                let tick = timer.tick(move |_| {
605                    if let Some(this) = weak.upgrade() {
606                        this.write_target_value_to_source();
607                    }
608                });
609                uncommon.delay_tick.replace(Some(tick));
610                uncommon.delay_timer.replace(Some(timer.clone()));
611                timer
612            }
613        };
614        timer.start();
615    }
616}
617
618impl UntypedBindingExpression for BindingExpression {
619    fn base(&self) -> &UntypedBindingExpressionBase {
620        &self.base
621    }
622
623    fn description(&self) -> String {
624        let mut b = String::new();
625        if let Some(leaf) = self.leaf_node() {
626            leaf.build_string_with_nodes(&mut b, &self.nodes);
627        }
628        b
629    }
630
631    fn update_source_core(&self) {
632        if matches!(self.mode, BindingMode::TwoWay | BindingMode::OneWayToSource) {
633            self.write_target_value_to_source();
634        }
635    }
636
637    fn update_target_core(&self) {
638        let Some(first) = self.nodes.first() else { return };
639        let source = first.state().source();
640        self.update_target_depth.set(self.update_target_depth.get() + 1);
641        for node in &self.nodes {
642            node.set_source(NodeSource::Unset, None);
643        }
644        // A dead or null source reads as null, as in the managed
645        // implementation.
646        first.set_source(NodeSource::Value(source), None);
647        self.update_target_depth.set(self.update_target_depth.get() - 1);
648    }
649
650    fn write_value_to_source(&self, value: Option<BoxedValue>) -> bool {
651        self.stop_delay_timer();
652        let mut value = value;
653        let Some(leaf) = self.leaf_node() else { return false };
654        let Some(setter) = leaf.as_settable() else { return false };
655        let Some(type_) = setter.value_type() else { return false };
656
657        // Invoke any converter on the value before writing it to the source.
658        // If the converter returns an error the value is not written.
659        if !self.try_convert_back(type_, &mut value) {
660            return false;
661        }
662
663        // A converter may return the do-nothing marker.
664        if BindingOperations::is_do_nothing(value.as_ref()) {
665            return true;
666        }
667
668        // Use the target type converter to convert the value to the source
669        // type if necessary.
670        if let Some(converter) = &self.target_type_converter {
671            if let Some(converted) = converter.try_convert(value.as_ref(), type_, &self.converter_culture()) {
672                value = converted;
673            } else if !is_unset(&self.fallback_value()) {
674                value = self.fallback_value();
675            } else if self.base.is_data_validation_enabled() {
676                self.on_data_validation_error(BindingError::message(format!(
677                    "Could not convert '{}' ({}) to {}.",
678                    ValueTypes::to_display_string(value.as_ref()),
679                    value.as_ref().map_or("null", |v| (**v).type_name()),
680                    type_
681                )));
682                return false;
683            } else {
684                return false;
685            }
686        }
687
688        // Don't set the value if it's unchanged. If there is a binding
689        // error, the value still has to be set in order to clear the error.
690        let current = leaf.state().value();
691        let current = current.and_then(ValueTypes::normalize);
692        let new = value.clone().and_then(ValueTypes::normalize);
693        if ValueTypes::identity_equals(current.as_ref(), new.as_ref())
694            && self.base.error_type() == BindingErrorType::None
695        {
696            return true;
697        }
698
699        setter.write_value_to_source(value.as_ref(), &self.nodes).unwrap_or(false)
700    }
701
702    fn should_log_error(&self) -> Option<Ref<FerroObject>> {
703        let target = self.base.try_get_target()?;
704        if let Some(first) = self.nodes.first() {
705            if let Some(source_node) = first.as_source_node() {
706                if !source_node.should_log_errors(first.state(), &target) {
707                    return None;
708                }
709            }
710        }
711        Some(target)
712    }
713
714    fn start_core(&self) {
715        let source = self.source.as_ref().and_then(WeakValue::upgrade);
716        let Some(source) = source else {
717            self.on_node_error(-1, "Binding Source is null.");
718            return;
719        };
720
721        match self.nodes.first() {
722            Some(first) => first.set_source(NodeSource::Value(Some(source)), None),
723            None => self.convert_and_publish_value(Some(source), None, false),
724        }
725
726        if matches!(self.mode, BindingMode::TwoWay | BindingMode::OneWayToSource) {
727            if let (Some(target), Some(property)) = (self.base.try_get_target(), self.base.target_property()) {
728                if self.update_source_trigger() == UpdateSourceTrigger::PropertyChanged {
729                    let weak = self.this.clone();
730                    let id = property.id();
731                    let subscription = target.property_changed(move |e| {
732                        if e.property().id() == id {
733                            if let Some(this) = weak.upgrade() {
734                                this.on_target_property_changed();
735                            }
736                        }
737                    });
738                    self.target_subscription.replace(Some(subscription));
739                } else if self.update_source_trigger() == UpdateSourceTrigger::LostFocus {
740                    if let Some(element) = target.downcast_ref::<InputElement>() {
741                        let weak = self.this.clone();
742                        let token = element.add_handler(InputElement::lost_focus_event(), move |_, _| {
743                            if let Some(this) = weak.upgrade() {
744                                this.write_target_value_to_source();
745                            }
746                        });
747                        self.lost_focus_token.replace(Some(token));
748                    }
749                }
750            }
751        }
752    }
753
754    fn stop_core(&self) {
755        self.stop_delay_timer();
756        let token = self.lost_focus_token.borrow_mut().take();
757        if let Some(token) = token {
758            if let Some(target) = self.base.try_get_target() {
759                if let Some(element) = target.downcast_ref::<InputElement>() {
760                    element.remove_handler(InputElement::lost_focus_event(), token);
761                }
762            }
763        }
764        for node in &self.nodes {
765            node.set_source(NodeSource::Unset, None);
766        }
767        let subscription = self.target_subscription.borrow_mut().take();
768        if let Some(s) = subscription {
769            s.dispose();
770        }
771    }
772}
773
774impl_untyped_binding_expression!(BindingExpression);
775
776impl Drop for BindingExpression {
777    fn drop(&mut self) {
778        if let Some(s) = self.target_subscription.get_mut().take() {
779            s.dispose();
780        }
781    }
782}