Skip to main content

ferroui_xaml_interactivity/behaviors/
disposing_behavior.rs

1//! Port of `Behaviors/DisposingBehavior.cs` (`DisposingBehavior<T>`).
2
3use crate::{StyledElementBehaviorImpl, StyledElementBehaviorImplExt, StyledElementBehaviorOfT};
4use ferroui_base::reactive::IDisposable;
5use ferroui_base::{ferro_class, FerroObjectImpl, StyledElementImpl, TypeInfo};
6use std::cell::RefCell;
7use std::rc::Rc;
8
9/// A base class for behaviors with disposable resources: the resource
10/// [`on_attached_override`](DisposingBehaviorImpl::on_attached_override) creates is disposed when
11/// the behavior is detached.
12///
13/// The class is abstract. The type argument `T` of the reference is the runtime type passed to
14/// [`construct`](Self::construct) (see [`BehaviorOfT`](crate::BehaviorOfT)).
15#[repr(C)]
16pub struct DisposingBehavior {
17    base: StyledElementBehaviorOfT,
18    disposable: RefCell<Option<Rc<dyn IDisposable>>>,
19}
20
21ferro_class! {
22    DisposingBehavior: StyledElementBehaviorOfT, virtuals DisposingBehaviorImpl: StyledElementBehaviorImpl {
23        /// Called after the behavior is attached to the associated object.
24        ///
25        /// Returns a disposable resource to be disposed when the behavior is detached.
26        fn on_attached_override(this) -> Rc<dyn IDisposable>;
27    }
28}
29
30ferroui_base::ferro_impl_classes!(DisposingBehavior: FerroObjectImpl, StyledElementImpl);
31
32impl DisposingBehaviorImpl for DisposingBehavior {
33    fn on_attached_override(_this: &Self) -> Rc<dyn IDisposable> {
34        panic!("DisposingBehavior is abstract: 'on_attached_override' must be implemented by the deriving class")
35    }
36}
37
38ferroui_base::ferro_overrides! {
39    impl StyledElementBehaviorImpl for DisposingBehavior {
40        fn on_attached(this: &Self) {
41            Self::parent_on_attached(this);
42
43            let previous = this.disposable.borrow_mut().take();
44            if let Some(previous) = previous {
45                previous.dispose();
46            }
47            let disposable = this.on_attached_override();
48            *this.disposable.borrow_mut() = Some(disposable);
49        }
50
51        fn on_detaching(this: &Self) {
52            Self::parent_on_detaching(this);
53
54            let disposable = this.disposable.borrow_mut().take();
55            if let Some(disposable) = disposable {
56                disposable.dispose();
57            }
58        }
59    }
60}
61
62impl DisposingBehavior {
63    /// Creates the class data for behaviors attached to objects of `associated_type`; see
64    /// [`ferroui_base::FerroObject::construct`].
65    pub fn construct(associated_type: &'static TypeInfo) -> Self {
66        Self { base: StyledElementBehaviorOfT::construct(associated_type), disposable: RefCell::new(None) }
67    }
68}