I am trying to have a Syncfusion Kanban UI element get populated from items from a viewmodel that gets data from an Azure database via async. The page loads with an empty Kanban (which is fine), but I wrapped my viewmodel collection ("Cards") in NotifyTaskCompletion , with the intention to have the page update once the data is loaded. However no data is ever updated; it looks like my items source is remaining null despite having it in xaml (Binding Cards.Result) and in the .cs for the view (kanban.ItemsSource = viewmodel.Cards.Result;). What am I doing wrong?
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Nito.AsyncEx;
using Syncfusion.SfKanban.XForms;
using UXDivers.Artina.Grial.Helpers;
using UXDivers.Artina.Grial.Models;
namespace UXDivers.Artina.Grial.ViewModel
{
public class ClientDashboardViewModel
{
static Teacher _Teacher;
private static string user_email;
public static List Clients { get; set; }
public NotifyTaskCompletion<ObservableCollection> Cards { get; private set; }
public ClientDashboardViewModel()
{
user_email = App.User.email;
Cards = new NotifyTaskCompletion<ObservableCollection<KanbanModel>>(PopulateParams());
}
public static async Task<ObservableCollection<KanbanModel>> PopulateParams()
{
var _Cards = new ObservableCollection<KanbanModel>();
ClientMatches = new List<Match>();
Clients= new List<Case>();
List<Teacher> foundTeachers = await App.DatabaseService.GetTable<Teacher>().ToListAsync();
_Teacher = foundTeachers.Find(x => x.email == user_email);
Clients =
await App.DatabaseService.GetTable<Case>()
.Where(x => x.Teacherid == _Teacher.id)
.ToListAsync() ;
int id = 1;
foreach (var _obj in Clients)
{
List<Client> clients =
await App.DatabaseService.GetTable<Client>()
.Where(x => x.id.ToString() == _obj.Teacherid.ToString())
.ToListAsync();
Client _client = clients.FirstOrDefault();
KanbanModel model = new KanbanModel()
{
ID = id,
Title = _obj.title,
ImageURL = "logo.png",
Category = "Objects",
Description = _obj.description,
ColorKey = "Red",
Tags = new string[] {_obj.startdate, _obj.cityoccurred,}
};
_Cards.Add(model);
id++;
}
return _Cards;
}
}
}
<?xml version="1.0" encoding="UTF-8"?><StackLayout x:Name="MainLayout" >
<xForms:SfKanban x:Name="kanban" AutoGenerateColumns="False" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" ItemsSource="{Binding Cards.Result}">
<xForms:SfKanban.Columns>
<xForms:KanbanColumn x:Name="objectcolumn" Title="Objects" MinimumLimit="5" MaximumLimit="15" >
</xForms:KanbanColumn>
</xForms:SfKanban.Columns>
</xForms:SfKanban>
</StackLayout>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Syncfusion.SfKanban.XForms;
using UXDivers.Artina.Grial.Helpers;
using UXDivers.Artina.Grial.ViewModel;
using UXDivers.Artina.Grial.Views.Dashboards;
using Xamarin.Forms;
namespace UXDivers.Artina.Grial.Views.Client
{
public partial class ObjectsPage : ContentPage
{
private string client_email;
ClientDashboardViewModel viewmodel= new ClientDashboardViewModel();
protected override void OnAppearing()
{
viewmodel = new ClientDashboardViewModel();
kanban.BindingContext = viewmodel;
casecolumn.Categories = new List() { "Objects" };
KanbanPlaceholderStyle style = new KanbanPlaceholderStyle();
style.SelectedBackgroundColor = Color.FromRgb(250.0f / 255.0f, 199.0f / 255.0f, 173.0f / 255.0f);
kanban.PlaceholderStyle = style;
var test = kanban.ItemsSource;
}
public ObjectsPage(string email)
{
InitializeComponent();
kanban.BindingContext = viewmodel;
if(viewmodel.Cards.Result!=null)
kanban.ItemsSource = viewmodel.Cards.Result.ToList();
casecolumn.Categories = new List<object>() { "Objects" };
KanbanPlaceholderStyle style = new KanbanPlaceholderStyle();
style.SelectedBackgroundColor = Color.FromRgb(250.0f / 255.0f, 199.0f / 255.0f, 173.0f / 255.0f);
kanban.PlaceholderStyle = style;
client_email = email;
}
}
}
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Nito.AsyncEx;
namespace UXDivers.Artina.Grial.Helpers
{
public sealed class NotifyTaskCompletion<TResult> : INotifyPropertyChanged
{
public NotifyTaskCompletion(Task<TResult> task)
{
Task = task;
if (!task.IsCompleted)
{
var _ = WatchTaskAsync(task);
}
}
private async Task WatchTaskAsync(Task task)
{
try
{
await task;
}
catch
{
}
var state = task.AsyncState;
var propertyChanged = PropertyChanged;
if (propertyChanged == null)
return;
propertyChanged(this, new PropertyChangedEventArgs("Status"));
propertyChanged(this, new PropertyChangedEventArgs("IsCompleted"));
propertyChanged(this, new PropertyChangedEventArgs("IsNotCompleted"));
if (task.IsCanceled)
{
propertyChanged(this, new PropertyChangedEventArgs("IsCanceled"));
}
else if (task.IsFaulted)
{
propertyChanged(this, new PropertyChangedEventArgs("IsFaulted"));
propertyChanged(this, new PropertyChangedEventArgs("Exception"));
propertyChanged(this,
new PropertyChangedEventArgs("InnerException"));
propertyChanged(this, new PropertyChangedEventArgs("ErrorMessage"));
}
else
{
propertyChanged(this,
new PropertyChangedEventArgs("IsSuccessfullyCompleted"));
propertyChanged(this, new PropertyChangedEventArgs("Result"));
}
}
public Task<TResult> Task { get; private set; }
public TResult Result
{
get
{
return (Task.Status == TaskStatus.RanToCompletion) ?
Task.Result : default(TResult);
}
}
public TaskStatus Status { get { return Task.Status; } }
public bool IsCompleted { get { return Task.IsCompleted; } }
public bool IsNotCompleted { get { return !Task.IsCompleted; } }
public bool IsSuccessfullyCompleted
{
get
{
return Task.Status ==
TaskStatus.RanToCompletion;
}
}
public bool IsCanceled { get { return Task.IsCanceled; } }
public bool IsFaulted { get { return Task.IsFaulted; } }
public AggregateException Exception { get { return Task.Exception; } }
public Exception InnerException
{
get
{
return (Exception == null) ?
null : Exception.InnerException;
}
}
public string ErrorMessage
{
get
{
return (InnerException == null) ?
null : InnerException.Message;
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
}