ferroui_xaml_interactions/core/
task_completed_trigger.rs1use crate::action_task::{ActionTask, CatchUnwind};
4use ferroui_base::threading::{Dispatcher, DispatcherPriority};
5use ferroui_base::{
6 ferro_class, ferro_class_info, ferro_properties, instantiate, BoxedValue, FerroObjectImpl, FerroObjectImplExt,
7 FerroProperty, FerroPropertyChangedEventArgs, Ref, StyledElementImpl, StyledProperty,
8};
9use ferroui_xaml_interactivity::{Interaction, StyledElementBehaviorImpl, StyledElementTrigger};
10use std::rc::Rc;
11
12#[repr(C)]
17pub struct TaskCompletedTrigger {
18 base: StyledElementTrigger,
19}
20
21ferro_class!(TaskCompletedTrigger: StyledElementTrigger);
22ferro_class_info!(TaskCompletedTrigger { new: TaskCompletedTrigger::new });
23ferroui_base::ferro_impl_classes!(TaskCompletedTrigger: StyledElementImpl, StyledElementBehaviorImpl);
24
25ferro_properties! {
26 impl TaskCompletedTrigger {
27 pub fn task_property() -> StyledProperty<Option<ActionTask>> {
29 FerroProperty::register::<TaskCompletedTrigger, _>("Task", None)
30 }
31 }
32}
33
34ferroui_base::ferro_overrides! {
35 impl FerroObjectImpl for TaskCompletedTrigger {
36 fn on_property_changed(this: &Self, change: &FerroPropertyChangedEventArgs<'_>) {
37 Self::parent_on_property_changed(this, change);
38
39 if change.property() == Self::task_property().as_property() {
40 this.on_task_changed(change.get_new_value::<Option<ActionTask>>());
41 }
42 }
43 }
44}
45
46impl TaskCompletedTrigger {
47 pub fn construct() -> Self {
49 Self { base: StyledElementTrigger::construct() }
50 }
51
52 pub fn new() -> Ref<Self> {
54 instantiate(Self::construct())
55 }
56
57 pub fn task(&self) -> Option<ActionTask> {
59 self.get_value(Self::task_property())
60 }
61
62 pub fn set_task(&self, value: Option<ActionTask>) {
63 self.set_value(Self::task_property(), value)
64 }
65
66 fn on_task_changed(&self, task: Option<ActionTask>) {
67 let Some(task) = task else {
68 return;
69 };
70
71 let trigger: Ref<TaskCompletedTrigger> = self.to_ref();
73 drop(ActionTask::spawn(async move {
74 let _ = CatchUnwind::new(task).await;
75 Dispatcher::ui_thread().post_local(
76 move || {
77 let sender = trigger
78 .associated_object()
79 .map(|associated_object| Rc::new(associated_object) as BoxedValue);
80 Interaction::execute_actions(sender.as_ref(), trigger.actions().as_ref(), None);
81 },
82 DispatcherPriority::DEFAULT,
83 );
84 }));
85 }
86}