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
23pub struct BindingExpressionOptions {
25 pub delay: i32,
28 pub fallback_value: Option<BoxedValue>,
30 pub converter: Option<Rc<dyn IValueConverter>>,
31 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 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
67struct 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
85pub struct BindingExpression {
89 this: Weak<BindingExpression>,
90 base: UntypedBindingExpressionBase,
91 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 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 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 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 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 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 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 pub fn error_type(&self) -> BindingErrorType {
263 self.base.error_type()
264 }
265
266 pub fn to_observable(self: &Rc<Self>, target: Option<&FerroObject>) -> Rc<ObservableSink> {
269 ObservableSink::create(self, target)
270 }
271
272 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 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 if self.mode != BindingMode::OneWayToSource {
297 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 self.base.publish_value(Publish::Unchanged, error, false);
308 }
309 } else if self.mode == BindingMode::OneWayToSource && node_index + 2 == count && value.is_some() {
310 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 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 self.on_node_value_changed(self.nodes.len() - 1, None, None);
333 }
334
335 pub(crate) fn on_node_error(&self, node_index: isize, error: &str) {
338 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 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 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 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 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 if BindingOperations::is_do_nothing(value.as_ref()) {
427 return;
428 }
429
430 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 !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 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 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 #[cfg(all(debug_assertions, feature = "hot-reload"))]
474 if self.base.is_reload_paused() { return; }
475
476 debug_assert!(matches!(self.mode, BindingMode::TwoWay | BindingMode::OneWayToSource));
477 self.stop_delay_timer();
478 if let (Some(target), Some(property)) = (self.base.try_get_target(), self.base.target_property()) {
479 let value = ValueTypes::normalize(target.get_value_untyped(property));
480 self.write_value_to_source(value);
481 }
482 }
483
484 fn convert_fallback(&self, fallback: Option<BoxedValue>, fallback_name: &str) -> Option<BoxedValue> {
485 let target_type = self.base.target_type();
486 if is_unset(&fallback) || (self.base.target_property().is_none() && target_type.is_object()) {
487 return fallback;
488 }
489 let converted = match &self.target_type_converter {
491 Some(converter) => converter.try_convert(fallback.as_ref(), target_type, &self.converter_culture()),
492 None => ValueTypes::try_convert(fallback.as_ref(), target_type),
493 };
494 if let Some(result) = converted {
495 return result;
496 }
497 if let Some(target) = self.base.try_get_target() {
498 self.base.log(
499 &target,
500 &self.description(),
501 &format!(
502 "Could not convert {fallback_name} '{}' to '{target_type}'.",
503 ValueTypes::to_display_string(fallback.as_ref())
504 ),
505 LogEventLevel::Error,
506 );
507 }
508 Some(FerroProperty::unset_value())
509 }
510
511 fn convert_from(&self, value: Option<BoxedValue>, error: &mut Option<ExpressionError>) -> Option<BoxedValue> {
514 let target_type = self.base.target_type();
515 if self.base.target_property().is_none() && target_type.is_object() {
516 return value;
517 }
518 let converted = match &self.target_type_converter {
521 Some(converter) => converter.try_convert(value.as_ref(), target_type, &self.converter_culture()),
522 None => ValueTypes::try_convert(value.as_ref(), target_type),
523 };
524 if let Some(result) = converted {
525 return result;
526 }
527 let message = format!(
528 "Could not convert '{}' ({}) to '{}'.",
529 ValueTypes::to_display_string(value.as_ref()),
530 value.as_ref().map_or("null", |v| (**v).type_name()),
531 target_type
532 );
533 if let Some(target) = self.should_log_error() {
534 self.base.log(&target, &self.description(), &message, LogEventLevel::Warning);
535 }
536 *error = Some(ExpressionError::new(BindingError::message(message), BindingErrorType::Error));
537 Some(FerroProperty::unset_value())
538 }
539
540 fn try_convert_back(&self, value_type: ValueType, value: &mut Option<BoxedValue>) -> bool {
544 let Some(converter) = self.converter() else { return true };
545 if is_unset(value) || BindingOperations::is_do_nothing(value.as_ref()) {
546 return true;
547 }
548 *value = self.base.convert_back(
549 &|| self.should_log_error(),
550 &|| self.description(),
551 &**converter,
552 Some(&self.converter_culture()),
553 self.converter_parameter(),
554 value.as_ref(),
555 value_type,
556 );
557 let converted = value.clone();
558 if let Some(notification) = converted.as_ref().and_then(|v| v.downcast_ref::<BindingNotification>()) {
559 if let Some(error) = notification.error() {
560 match notification.error_type() {
561 BindingErrorType::DataValidationError => {
562 if self.base.is_data_validation_enabled() {
563 self.on_data_validation_error(error);
564 }
565 }
566 _ => {
567 if let Some(target) = self.should_log_error() {
568 self.base.log(&target, &self.description(), &error.to_string(), LogEventLevel::Warning);
569 }
570 self.base.publish_value(
571 Publish::Unchanged,
572 Some(ExpressionError::new(error, BindingErrorType::Error)),
573 false,
574 );
575 }
576 }
577 return false;
578 }
579 *value = notification.value();
580 }
581 true
582 }
583
584 fn on_target_property_changed(&self) {
585 debug_assert!(matches!(self.mode, BindingMode::TwoWay | BindingMode::OneWayToSource));
586 let delay = self.delay();
587 let Some(uncommon) = self.uncommon.as_ref().filter(|_| !delay.is_zero()) else {
588 self.write_target_value_to_source();
591 return;
592 };
593
594 let existing = uncommon.delay_timer.borrow().clone();
595 let timer = match existing {
596 Some(timer) => {
597 timer.stop();
598 timer
599 }
600 None => {
601 let timer = DispatcherTimer::with_interval(
602 delay,
603 DispatcherPriority::DEFAULT,
604 &Dispatcher::current_dispatcher(),
605 );
606 let weak = self.this.clone();
607 let tick = timer.tick(move |_| {
608 if let Some(this) = weak.upgrade() {
609 this.write_target_value_to_source();
610 }
611 });
612 uncommon.delay_tick.replace(Some(tick));
613 uncommon.delay_timer.replace(Some(timer.clone()));
614 timer
615 }
616 };
617 timer.start();
618 }
619}
620
621impl UntypedBindingExpression for BindingExpression {
622 fn base(&self) -> &UntypedBindingExpressionBase {
623 &self.base
624 }
625
626 fn description(&self) -> String {
627 let mut b = String::new();
628 if let Some(leaf) = self.leaf_node() {
629 leaf.build_string_with_nodes(&mut b, &self.nodes);
630 }
631 b
632 }
633
634 fn update_source_core(&self) {
635 if matches!(self.mode, BindingMode::TwoWay | BindingMode::OneWayToSource) {
636 self.write_target_value_to_source();
637 }
638 }
639
640 fn update_target_core(&self) {
641 let Some(first) = self.nodes.first() else { return };
642 let source = first.state().source();
643 self.update_target_depth.set(self.update_target_depth.get() + 1);
644 for node in &self.nodes {
645 node.set_source(NodeSource::Unset, None);
646 }
647 first.set_source(NodeSource::Value(source), None);
650 self.update_target_depth.set(self.update_target_depth.get() - 1);
651 }
652
653 fn write_value_to_source(&self, value: Option<BoxedValue>) -> bool {
654 #[cfg(all(debug_assertions, feature = "hot-reload"))]
655 if self.base.is_reload_paused() {
656 return false;
657 }
658 self.stop_delay_timer();
659 let mut value = value;
660 let Some(leaf) = self.leaf_node() else { return false };
661 let Some(setter) = leaf.as_settable() else { return false };
662 let Some(type_) = setter.value_type() else { return false };
663
664 if !self.try_convert_back(type_, &mut value) {
667 return false;
668 }
669
670 if BindingOperations::is_do_nothing(value.as_ref()) {
672 return true;
673 }
674
675 if let Some(converter) = &self.target_type_converter {
678 if let Some(converted) = converter.try_convert(value.as_ref(), type_, &self.converter_culture()) {
679 value = converted;
680 } else if !is_unset(&self.fallback_value()) {
681 value = self.fallback_value();
682 } else if self.base.is_data_validation_enabled() {
683 self.on_data_validation_error(BindingError::message(format!(
684 "Could not convert '{}' ({}) to {}.",
685 ValueTypes::to_display_string(value.as_ref()),
686 value.as_ref().map_or("null", |v| (**v).type_name()),
687 type_
688 )));
689 return false;
690 } else {
691 return false;
692 }
693 }
694
695 let current = leaf.state().value();
698 let current = current.and_then(ValueTypes::normalize);
699 let new = value.clone().and_then(ValueTypes::normalize);
700 if ValueTypes::identity_equals(current.as_ref(), new.as_ref())
701 && self.base.error_type() == BindingErrorType::None
702 {
703 return true;
704 }
705
706 setter.write_value_to_source(value.as_ref(), &self.nodes).unwrap_or(false)
707 }
708
709 fn should_log_error(&self) -> Option<Ref<FerroObject>> {
710 let target = self.base.try_get_target()?;
711 if let Some(first) = self.nodes.first() {
712 if let Some(source_node) = first.as_source_node() {
713 if !source_node.should_log_errors(first.state(), &target) {
714 return None;
715 }
716 }
717 }
718 Some(target)
719 }
720
721 #[cfg(all(debug_assertions, feature = "hot-reload"))]
722 fn supports_reload_pause(&self) -> bool {
723 matches!(self.mode, BindingMode::OneWay | BindingMode::TwoWay)
724 && self.delay().is_zero()
725 && self.update_source_trigger() == UpdateSourceTrigger::PropertyChanged
726 }
727
728 fn start_core(&self) {
729 let source = self.source.as_ref().and_then(WeakValue::upgrade);
730 let Some(source) = source else {
731 self.on_node_error(-1, "Binding Source is null.");
732 return;
733 };
734
735 match self.nodes.first() {
736 Some(first) => first.set_source(NodeSource::Value(Some(source)), None),
737 None => self.convert_and_publish_value(Some(source), None, false),
738 }
739
740 if matches!(self.mode, BindingMode::TwoWay | BindingMode::OneWayToSource) {
741 if let (Some(target), Some(property)) = (self.base.try_get_target(), self.base.target_property()) {
742 if self.update_source_trigger() == UpdateSourceTrigger::PropertyChanged {
743 let weak = self.this.clone();
744 let id = property.id();
745 let subscription = target.property_changed(move |e| {
746 if e.property().id() == id {
747 if let Some(this) = weak.upgrade() {
748 this.on_target_property_changed();
749 }
750 }
751 });
752 self.target_subscription.replace(Some(subscription));
753 } else if self.update_source_trigger() == UpdateSourceTrigger::LostFocus {
754 if let Some(element) = target.downcast_ref::<InputElement>() {
755 let weak = self.this.clone();
756 let token = element.add_handler(InputElement::lost_focus_event(), move |_, _| {
757 if let Some(this) = weak.upgrade() {
758 this.write_target_value_to_source();
759 }
760 });
761 self.lost_focus_token.replace(Some(token));
762 }
763 }
764 }
765 }
766 }
767
768 fn stop_core(&self) {
769 self.stop_delay_timer();
770 let token = self.lost_focus_token.borrow_mut().take();
771 if let Some(token) = token {
772 if let Some(target) = self.base.try_get_target() {
773 if let Some(element) = target.downcast_ref::<InputElement>() {
774 element.remove_handler(InputElement::lost_focus_event(), token);
775 }
776 }
777 }
778 for node in &self.nodes {
779 node.set_source(NodeSource::Unset, None);
780 }
781 let subscription = self.target_subscription.borrow_mut().take();
782 if let Some(s) = subscription {
783 s.dispose();
784 }
785 }
786}
787
788impl_untyped_binding_expression!(BindingExpression);
789
790impl Drop for BindingExpression {
791 fn drop(&mut self) {
792 if let Some(s) = self.target_subscription.get_mut().take() {
793 s.dispose();
794 }
795 }
796}