Neuron®
The Neuron® is the basis for the creation of open and secure federated networks for smart societies.
Loading...
Searching...
No Matches
TaskView.cs
1using System;
3using System.ComponentModel;
4using System.Linq;
5using System.Text;
6using System.Threading.Tasks;
8
10{
96 public class TaskView<TProgress> : ContentView
97 {
98 #region Bindable Properties
99
100 // The bound ObservableTask.
101 public static readonly BindableProperty TaskProperty =
102 BindableProperty.Create(nameof(Task), typeof(ObservableTask), typeof(TaskView<TProgress>),
103 default(ObservableTask), propertyChanged: OnTaskChanged);
104
105 public ObservableTask Task
106 {
107 get => (ObservableTask)this.GetValue(TaskProperty);
108 set => this.SetValue(TaskProperty, value);
109 }
110
111 // --- DataTemplate properties ---
112 public static readonly BindableProperty PendingTemplateProperty =
113 BindableProperty.Create(nameof(PendingTemplate), typeof(DataTemplate), typeof(TaskView<TProgress>), default(DataTemplate));
114 public DataTemplate PendingTemplate
115 {
116 get => (DataTemplate)this.GetValue(PendingTemplateProperty);
117 set => this.SetValue(PendingTemplateProperty, value);
118 }
119
120 public static readonly BindableProperty RunningTemplateProperty =
121 BindableProperty.Create(nameof(RunningTemplate), typeof(DataTemplate), typeof(TaskView<TProgress>), default(DataTemplate));
122 public DataTemplate RunningTemplate
123 {
124 get => (DataTemplate)this.GetValue(RunningTemplateProperty);
125 set => this.SetValue(RunningTemplateProperty, value);
126 }
127
128 public static readonly BindableProperty RefreshingTemplateProperty =
129 BindableProperty.Create(nameof(RefreshingTemplate), typeof(DataTemplate), typeof(TaskView<TProgress>), default(DataTemplate));
130 public DataTemplate RefreshingTemplate
131 {
132 get => (DataTemplate)this.GetValue(RefreshingTemplateProperty);
133 set => this.SetValue(RefreshingTemplateProperty, value);
134 }
135
136 public static readonly BindableProperty SucceededTemplateProperty =
137 BindableProperty.Create(nameof(SucceededTemplate), typeof(DataTemplate), typeof(TaskView<TProgress>), default(DataTemplate));
138 public DataTemplate SucceededTemplate
139 {
140 get => (DataTemplate)this.GetValue(SucceededTemplateProperty);
141 set => this.SetValue(SucceededTemplateProperty, value);
142 }
143
144 public static readonly BindableProperty ErrorTemplateProperty =
145 BindableProperty.Create(nameof(ErrorTemplate), typeof(DataTemplate), typeof(TaskView<TProgress>), default(DataTemplate));
146 public DataTemplate ErrorTemplate
147 {
148 get => (DataTemplate)this.GetValue(ErrorTemplateProperty);
149 set => this.SetValue(ErrorTemplateProperty, value);
150 }
151
152 public static readonly BindableProperty DefaultTemplateProperty =
153 BindableProperty.Create(nameof(DefaultTemplate), typeof(DataTemplate), typeof(TaskView<TProgress>), default(DataTemplate));
154 public DataTemplate DefaultTemplate
155 {
156 get => (DataTemplate)this.GetValue(DefaultTemplateProperty);
157 set => this.SetValue(DefaultTemplateProperty, value);
158 }
159
160 // --- Inline View properties ---
161 public static readonly BindableProperty PendingViewProperty =
162 BindableProperty.Create(nameof(PendingView), typeof(View), typeof(TaskView<TProgress>), default(View));
163 public View PendingView
164 {
165 get => (View)this.GetValue(PendingViewProperty);
166 set => this.SetValue(PendingViewProperty, value);
167 }
168
169 public static readonly BindableProperty RunningViewProperty =
170 BindableProperty.Create(nameof(RunningView), typeof(View), typeof(TaskView<TProgress>), default(View));
171 public View RunningView
172 {
173 get => (View)this.GetValue(RunningViewProperty);
174 set => this.SetValue(RunningViewProperty, value);
175 }
176
177 public static readonly BindableProperty RefreshingViewProperty =
178 BindableProperty.Create(nameof(RefreshingView), typeof(View), typeof(TaskView<TProgress>), default(View));
179 public View RefreshingView
180 {
181 get => (View)this.GetValue(RefreshingViewProperty);
182 set => this.SetValue(RefreshingViewProperty, value);
183 }
184
185 public static readonly BindableProperty SucceededViewProperty =
186 BindableProperty.Create(nameof(SucceededView), typeof(View), typeof(TaskView<TProgress>), default(View));
187 public View SucceededView
188 {
189 get => (View)this.GetValue(SucceededViewProperty);
190 set => this.SetValue(SucceededViewProperty, value);
191 }
192
193 public static readonly BindableProperty ErrorViewProperty =
194 BindableProperty.Create(nameof(ErrorView), typeof(View), typeof(TaskView<TProgress>), default(View));
195 public View ErrorView
196 {
197 get => (View)this.GetValue(ErrorViewProperty);
198 set => this.SetValue(ErrorViewProperty, value);
199 }
200
201 public static readonly BindableProperty DefaultViewProperty =
202 BindableProperty.Create(nameof(DefaultView), typeof(View), typeof(TaskView<TProgress>), default(View));
203 public View DefaultView
204 {
205 get => (View)this.GetValue(DefaultViewProperty);
206 set => this.SetValue(DefaultViewProperty, value);
207 }
208
209 // --- ControlTemplate properties ---
210 public static readonly BindableProperty PendingControlTemplateProperty =
211 BindableProperty.Create(nameof(PendingControlTemplate), typeof(ControlTemplate), typeof(TaskView<TProgress>), default(ControlTemplate));
212 public ControlTemplate PendingControlTemplate
213 {
214 get => (ControlTemplate)this.GetValue(PendingControlTemplateProperty);
215 set => this.SetValue(PendingControlTemplateProperty, value);
216 }
217
218 public static readonly BindableProperty RunningControlTemplateProperty =
219 BindableProperty.Create(nameof(RunningControlTemplate), typeof(ControlTemplate), typeof(TaskView<TProgress>), default(ControlTemplate));
220 public ControlTemplate RunningControlTemplate
221 {
222 get => (ControlTemplate)this.GetValue(RunningControlTemplateProperty);
223 set => this.SetValue(RunningControlTemplateProperty, value);
224 }
225
226 public static readonly BindableProperty RefreshingControlTemplateProperty =
227 BindableProperty.Create(nameof(RefreshingControlTemplate), typeof(ControlTemplate), typeof(TaskView<TProgress>), default(ControlTemplate));
228 public ControlTemplate RefreshingControlTemplate
229 {
230 get => (ControlTemplate)this.GetValue(RefreshingControlTemplateProperty);
231 set => this.SetValue(RefreshingControlTemplateProperty, value);
232 }
233
234 public static readonly BindableProperty SucceededControlTemplateProperty =
235 BindableProperty.Create(nameof(SucceededControlTemplate), typeof(ControlTemplate), typeof(TaskView<TProgress>), default(ControlTemplate));
236 public ControlTemplate SucceededControlTemplate
237 {
238 get => (ControlTemplate)this.GetValue(SucceededControlTemplateProperty);
239 set => this.SetValue(SucceededControlTemplateProperty, value);
240 }
241
242 public static readonly BindableProperty ErrorControlTemplateProperty =
243 BindableProperty.Create(nameof(ErrorControlTemplate), typeof(ControlTemplate), typeof(TaskView<TProgress>), default(ControlTemplate));
244 public ControlTemplate ErrorControlTemplate
245 {
246 get => (ControlTemplate)this.GetValue(ErrorControlTemplateProperty);
247 set => this.SetValue(ErrorControlTemplateProperty, value);
248 }
249
250 public static readonly BindableProperty DefaultControlTemplateProperty =
251 BindableProperty.Create(nameof(DefaultControlTemplate), typeof(ControlTemplate), typeof(TaskView<TProgress>), default(ControlTemplate));
252 public ControlTemplate DefaultControlTemplate
253 {
254 get => (ControlTemplate)this.GetValue(DefaultControlTemplateProperty);
255 set => this.SetValue(DefaultControlTemplateProperty, value);
256 }
257
258 #endregion
259
260 #region Task Change Handling
261
262 private static void OnTaskChanged(BindableObject bindable, object oldValue, object newValue)
263 {
264 TaskView<TProgress> Control = (TaskView<TProgress>)bindable;
265 if (oldValue is ObservableTask OldTask)
266 {
267 OldTask.PropertyChanged -= Control.Task_PropertyChanged;
268 }
269 if (newValue is ObservableTask NewTask)
270 {
271 NewTask.PropertyChanged += Control.Task_PropertyChanged;
272 }
273 Control.UpdateContent();
274 }
275
276 private void Task_PropertyChanged(object? sender, PropertyChangedEventArgs e)
277 {
278 if (e.PropertyName == nameof(ObservableTask.State) ||
279 e.PropertyName == nameof(ObservableTask.IsRefreshing))
280 {
281 MainThread.BeginInvokeOnMainThread(this.UpdateContent);
282 }
283 }
284
285 #endregion
286
287 #region Content Selection & Creation
288
295 private View? GetContent(View inlineView, DataTemplate? template, ControlTemplate? controlTemplate)
296 {
297 if (inlineView is not null)
298 return inlineView;
299
300 if (template is not null)
301 {
302 object Content = template.CreateContent();
303 if (Content is View View)
304 return View;
305 if (Content is ViewCell Cell)
306 return Cell.View;
307 }
308
309 if (controlTemplate is not null)
310 {
311 ContentView View = new ContentView { ControlTemplate = controlTemplate };
312 return View;
313 }
314
315 return null;
316 }
317
321 private View? GetDefaultContent() => this.GetContent(this.DefaultView, this.DefaultTemplate, this.DefaultControlTemplate);
322
326 private View? SelectContent()
327 {
328 if (this.Task is null)
329 return this.GetDefaultContent();
330
331 // For Pending state: first try Pending-specific content, then fallback to Running.
332 if (this.Task.IsPending)
333 {
334 View? Content = this.GetContent(this.PendingView, this.PendingTemplate, this.PendingControlTemplate);
335 if (Content is not null)
336 return Content;
337
338 Content = this.GetContent(this.RunningView, this.RunningTemplate, this.RunningControlTemplate);
339 if (Content is not null)
340 return Content;
341 }
342
343 // For Running state: if refreshing try the refresh-specific content.
344 if (this.Task.IsRunning)
345 {
346 if (this.Task.IsRefreshing)
347 {
348 View? Content = this.GetContent(this.RefreshingView, this.RefreshingTemplate, this.RefreshingControlTemplate);
349 if (Content is not null)
350 return Content;
351 }
352
353 View? RunningContent = this.GetContent(this.RunningView, this.RunningTemplate, this.RunningControlTemplate);
354 if (RunningContent is not null)
355 return RunningContent;
356 }
357
358 // For Succeeded state.
359 if (this.Task.IsSucceeded)
360 {
361 View? Content = this.GetContent(this.SucceededView, this.SucceededTemplate, this.SucceededControlTemplate);
362 if (Content is not null)
363 return Content;
364 }
365
366 // For error conditions (Failed or Canceled).
367 if (this.Task.IsFailed || this.Task.IsCanceled)
368 {
369 View? Content = this.GetContent(this.ErrorView, this.ErrorTemplate, this.ErrorControlTemplate);
370 if (Content is not null)
371 return Content;
372 }
373
374 return this.GetDefaultContent();
375 }
376
377 #endregion
378
379 #region Animation & Content Update
380
384 private async void UpdateContent()
385 {
386 View? NewContent = this.SelectContent();
387 if (NewContent is null)
388 return;
389
390 NewContent.BindingContext = this.BindingContext;
391
392 try
393 {
394 if (this.Content is not null)
395 {
396 View OldContent = this.Content;
397 await OldContent.FadeToAsync(0, 250);
398 this.Content = NewContent;
399 NewContent.Opacity = 0;
400 await NewContent.FadeToAsync(1, 250);
401 }
402 else
403 {
404 this.Content = NewContent;
405 NewContent.Opacity = 0;
406 await NewContent.FadeToAsync(1, 250);
407 }
408 }
409 catch (Exception)
410 {
411 this.Content.Opacity = 1;
412 }
413 }
414
415 protected override void OnBindingContextChanged()
416 {
417 base.OnBindingContextChanged();
418
419 if (this.Content is not null)
420 this.Content.BindingContext = this.BindingContext;
421 }
422 #endregion
423 }
424
426 public class TaskView : TaskView<int>
427 {
428 // You may customize the non-generic version further if needed.
429 }
430}
A ContentView control that displays the state of an asynchronous operation defined by an ObservableTa...
Definition: TaskView.cs:97
Provides a data-binding friendly mechanism to manage and report the status of asynchronous operations...
ObservableTaskStatus State
Gets the current state.