using Comal.Classes; using InABox.Clients; using InABox.Core; using InABox.DynamicGrid; using InABox.Scripting; using InABox.WPF; using PRSDesktop.Configuration; using PRSDesktop.Forms; using PRSDesktop.WidgetGroups; using Syncfusion.UI.Xaml.Grid; using Syncfusion.Windows.Shared; using System; using System.Collections; using System.Collections.Generic; using System.Data; using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Linq.Expressions; using System.Reflection; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; using SelectionChangedEventArgs = System.Windows.Controls.SelectionChangedEventArgs; namespace PRSDesktop { public enum DateFilterType { Today, Yesterday, Week, SevenDays, Month, ThirtyDays, Year, TwelveMonths, Custom } public class DigitalFormsDashboardProperties : IDashboardProperties { public bool ShowJobFilter { get; set; } = false; public bool ShowDateFilter { get; set; } = true; public Guid JobID { get; set; } public DateFilterType DateFilterType { get; set; } = DateFilterType.Today; public DateTime FromDate { get; set; } public DateTime ToDate { get; set; } } public class DigitalFormsDashboardElement : DashboardElement { } /// /// Interaction logic for DigitalFormsDashboard.xaml /// public partial class DigitalFormsDashboard : UserControl, IDashboardWidget, IRequiresSecurity, IHeaderDashboard, IActionsDashboard { public DigitalFormsDashboardProperties Properties { get; set; } private List DigitalForms; private List Jobs; private Dictionary Categories; public DashboardHeader Header { get; set; } = new(); public DigitalFormsDashboard() { InitializeComponent(); } public void Setup() { var results = Client.QueryMultiple( new KeyedQueryDef(new Filter(x => x.Active).IsEqualTo(true)), new KeyedQueryDef( LookupFactory.DefineFilter(), new Columns(x => x.ID) .Add(x => x.JobNumber) .Add(x => x.Name))); DigitalForms = results.Get().ToList(); var categories = new DigitalFormCategoryLookups(null); categories.OnAfterGenerateLookups += (sender, entries) => { entries.Insert(0, new LookupEntry("", "Select Category")); }; Categories = categories.AsTable("AppliesTo") .ToDictionary("AppliesTo", "Display") .Cast>() .ToDictionary(x => (x.Key as string)!, x => x.Value); Jobs = results.Get().ToList(); Jobs.Insert(0, new Job { ID = Guid.Empty, JobNumber = "ALL", Name = "All Jobs" }); SetupHeader(); SetupFilters(); } #region Header private ComboBox CategoryBox; private ComboBox FormBox; private ComboBox JobBox; private ComboBox DateTypeBox; private Label FromLabel; private DatePicker FromPicker; private Label ToLabel; private DatePicker ToPicker; private static Dictionary FilterTypes = new() { { DateFilterType.Today, "Today" }, { DateFilterType.Yesterday, "Yesterday" }, { DateFilterType.Week, "Week to Date" }, { DateFilterType.SevenDays, "Last 7 Days" }, { DateFilterType.Month, "Month to Date" }, { DateFilterType.ThirtyDays, "Last 30 Days" }, { DateFilterType.Year, "Year to Date" }, { DateFilterType.TwelveMonths, "Last 12 Months" }, { DateFilterType.Custom, "Custom" } }; public void SetupHeader() { CategoryBox = new ComboBox { Width = 150, VerticalContentAlignment = VerticalAlignment.Center, Margin = new Thickness(0, 0, 5, 0) }; CategoryBox.ItemsSource = Categories; CategoryBox.SelectedValuePath = "Key"; CategoryBox.DisplayMemberPath = "Value"; CategoryBox.SelectionChanged += Category_SelectionChanged; FormBox = new ComboBox { Width = 250, VerticalContentAlignment = VerticalAlignment.Center, Margin = new Thickness(0, 0, 5, 0), IsEnabled = false }; FormBox.SelectionChanged += FormBox_SelectionChanged; FormBox.ItemsSource = new Dictionary { }; JobBox = new ComboBox { Width = 250, Margin = new Thickness(0, 0, 5, 0), VerticalContentAlignment = VerticalAlignment.Center }; JobBox.ItemsSource = Jobs.ToDictionary(x => x.ID, x => $"{x.JobNumber} : {x.Name}"); JobBox.SelectedIndex = 0; JobBox.SelectedValuePath = "Key"; JobBox.DisplayMemberPath = "Value"; JobBox.SelectionChanged += JobBox_SelectionChanged; DateTypeBox = new ComboBox { Width = 120, VerticalContentAlignment = VerticalAlignment.Center }; DateTypeBox.ItemsSource = FilterTypes; DateTypeBox.SelectedValuePath = "Key"; DateTypeBox.DisplayMemberPath = "Value"; DateTypeBox.SelectedValue = Properties.DateFilterType; DateTypeBox.SelectionChanged += DateTypeBox_SelectionChanged; FromLabel = new Label { Content = "From", VerticalContentAlignment = VerticalAlignment.Center, Margin = new Thickness(0, 0, 5, 0) }; FromPicker = new DatePicker { Width = 100, Background = new SolidColorBrush(Colors.LightYellow), VerticalContentAlignment = VerticalAlignment.Center, FirstDayOfWeek = DayOfWeek.Monday, Margin = new Thickness(0, 0, 5, 0) }; FromPicker.SelectedDateChanged += FromPicker_SelectedDateChanged; ToLabel = new Label { Content = "To", VerticalContentAlignment = VerticalAlignment.Center, Margin = new Thickness(0, 0, 5, 0) }; ToPicker = new DatePicker { Width = 100, Background = new SolidColorBrush(Colors.LightYellow), VerticalContentAlignment = VerticalAlignment.Center, FirstDayOfWeek = DayOfWeek.Monday, Margin = new Thickness(0, 0, 5, 0) }; ToPicker.SelectedDateChanged += ToPicker_SelectedDateChanged; Header.BeginUpdate() .Clear() .Add(CategoryBox) .Add(FormBox) .Add(JobBox) .Add(DateTypeBox) .Add(FromLabel) .Add(FromPicker) .Add(ToLabel) .Add(ToPicker); Header.EndUpdate(); } private void Search_KeyUp(object sender, KeyEventArgs e) { Refresh(); } private void JobBox_SelectionChanged(object sender, SelectionChangedEventArgs e) { Properties.JobID = (Guid)JobBox.SelectedValue; Refresh(); } private void SetDateFilterVisibility(bool visible) { var visibility = visible ? Visibility.Visible : Visibility.Collapsed; FromLabel.Visibility = visibility; FromPicker.Visibility = visibility; ToLabel.Visibility = visibility; ToPicker.Visibility = visibility; DateTypeBox.Visibility = visibility; } private void SetJobFilterVisibility(bool visible) { var visibility = visible ? Visibility.Visible : Visibility.Collapsed; JobBox.Visibility = visibility; } private void DateTypeBox_SelectionChanged(object sender, SelectionChangedEventArgs e) { var filterType = (DateFilterType)DateTypeBox.SelectedValue; Properties.DateFilterType = filterType; if(filterType == DateFilterType.Custom) { if (FromPicker.SelectedDate == null || FromPicker.SelectedDate == DateTime.MinValue) { Properties.FromDate = DateTime.Today; } else { Properties.FromDate = FromPicker.SelectedDate.Value; } if (ToPicker.SelectedDate == null || ToPicker.SelectedDate == DateTime.MinValue) { Properties.ToDate = DateTime.Today; } else { Properties.ToDate = ToPicker.SelectedDate.Value; } } SetupDateFilters(); Refresh(); } private void FromPicker_SelectedDateChanged(object? sender, SelectionChangedEventArgs e) { Properties.FromDate = FromPicker.SelectedDate ?? DateTime.Today; } private void ToPicker_SelectedDateChanged(object? sender, SelectionChangedEventArgs e) { Properties.ToDate = ToPicker.SelectedDate ?? DateTime.Today; } private void Category_SelectionChanged(object sender, SelectionChangedEventArgs e) { SetCategory((CategoryBox.SelectedValue as string)!); var jobLink = FormType is not null ? GetJobLink("", FormType) : ""; if (string.IsNullOrWhiteSpace(jobLink)) { var jobID = Properties.JobID; JobBox.SelectedValue = Guid.Empty; JobBox.IsEnabled = false; Properties.JobID = jobID; } else { JobBox.SelectedValue = Properties.JobID; JobBox.IsEnabled = true; } if (ParentType is null) { FormBox.IsEnabled = false; FormBox.ItemsSource = new Dictionary { }; } else { var forms = DigitalForms.Where(x => x.AppliesTo == ParentType.Name).ToList(); forms.Insert(0, new DigitalForm { ID = Guid.Empty, Description = "Select Form" }); FormBox.ItemsSource = forms; FormBox.DisplayMemberPath = "Description"; FormBox.SelectedIndex = 0; FormBox.IsEnabled = true; } Refresh(); } private void FormBox_SelectionChanged(object sender, SelectionChangedEventArgs e) { Form = (FormBox.SelectedValue as DigitalForm)!; Refresh(); } #endregion private string SectionName { get { if (Form is null || Form.ID == Guid.Empty) return "Digital Forms"; return Form.ID.ToString() ?? "Digital Forms"; } } private DataModel DataModel(Selection selection) { if(FormType is null || Form is null || Form.ID == Guid.Empty) { return new AutoDataModel(new Filter().None()); } IFilter filter; switch (selection) { case Selection.Selected: var formids = DataGrid.SelectedItems.Select(x => (x as DataRowView)!.Row["ID"]).ToArray(); filter = Filter.Create(FormType, x => x.ID).InList(formids); break; case Selection.All: filter = Filter.Create(FormType).All(); break; case Selection.None: default: filter = Filter.Create(FormType).None(); break; } return (Activator.CreateInstance(typeof(DigitalFormReportDataModel<>)! .MakeGenericType(FormType), new object?[] { filter, Form.ID }) as DataModel)!; } public void BuildActionsMenu(ContextMenu menu) { menu.AddCheckItem("Show Date Filter", null, ToggleDateFilter, Properties.ShowDateFilter); menu.AddCheckItem("Show Job Filter", null, ToggleJobFilter, Properties.ShowJobFilter); menu.AddSeparator(); foreach(var (module, image) in CustomModuleUtils.LoadCustomModuleThumbnails(SectionName, DataModel(Selection.None))) { menu.AddItem(module.Name, image, module, ExecuteModule_Click); } if (Security.IsAllowed()) { menu.AddSeparatorIfNeeded(); menu.AddItem("Manage Modules", PRSDesktop.Resources.script, ManageModules_Click); } } private void ExecuteModule_Click(CustomModule obj) { if (!string.IsNullOrWhiteSpace(obj.Script)) try { Selection selection; if (obj.SelectedRecords && obj.AllRecords) selection = RecordSelectionDialog.Execute(); else if (obj.SelectedRecords) selection = Selection.Selected; else if (obj.AllRecords) selection = Selection.All; else selection = Selection.None; var result = ScriptDocument.RunCustomModule(DataModel(selection), new Dictionary(), obj.Script); if (result) Refresh(); } catch (CompileException c) { MessageBox.Show(c.Message); } catch (Exception err) { MessageBox.Show(CoreUtils.FormatException(err)); } else MessageBox.Show("Unable to load " + obj.Name); } private void ManageModules_Click() { var section = SectionName; var dataModel = DataModel(Selection.Selected); var manager = new CustomModuleManager() { Section = section, DataModel = dataModel }; manager.ShowDialog(); } private void ToggleDateFilter(object? tag, bool isChecked) { Properties.ShowDateFilter = isChecked; SetDateFilterVisibility(Properties.ShowDateFilter); } private void ToggleJobFilter(object? tag, bool isChecked) { Properties.ShowJobFilter = isChecked; SetJobFilterVisibility(Properties.ShowJobFilter); Refresh(); } #region Filtering private DateTime From { get; set; } private DateTime To { get; set; } private bool IsEntityForm { get; set; } private Type? ParentType { get; set; } private Type? FormType { get; set; } private DigitalForm? Form { get; set; } private readonly Dictionary QuestionCodes = new(); private static int WeekDay(DateTime date) { if (date.DayOfWeek == DayOfWeek.Sunday) return 7; return (int)date.DayOfWeek - 1; } private void SetupDateFilters() { switch (Properties.DateFilterType) { case DateFilterType.Today: From = DateTime.Today; To = DateTime.Today; break; case DateFilterType.Yesterday: From = DateTime.Today.AddDays(-1); To = DateTime.Today.AddDays(-1); break; case DateFilterType.Week: From = DateTime.Today.AddDays(-WeekDay(DateTime.Today)); To = DateTime.Today; break; case DateFilterType.SevenDays: From = DateTime.Today.AddDays(-6); To = DateTime.Today; break; case DateFilterType.Month: From = new DateTime(DateTime.Today.Year, DateTime.Today.Month, 1); To = DateTime.Today; break; case DateFilterType.ThirtyDays: From = DateTime.Today.AddDays(-29); To = DateTime.Today; break; case DateFilterType.Year: From = new DateTime(DateTime.Today.Year, 1, 1); To = DateTime.Today; break; case DateFilterType.TwelveMonths: From = DateTime.Today.AddYears(-1).AddDays(1); To = DateTime.Today; break; case DateFilterType.Custom: From = Properties.FromDate; To = Properties.ToDate; break; } DateTypeBox.SelectedValue = Properties.DateFilterType; FromPicker.SelectedDate = From; ToPicker.SelectedDate = To; var enabledPicker = Properties.DateFilterType == DateFilterType.Custom; FromPicker.IsEnabled = enabledPicker; ToPicker.IsEnabled = enabledPicker; } private void SetupJobFilter() { JobBox.SelectedValue = Properties.JobID; } private void SetupFilters() { SetupDateFilters(); SetupJobFilter(); SetDateFilterVisibility(Properties.ShowDateFilter); SetJobFilterVisibility(Properties.ShowJobFilter); } #region Categories private static Dictionary>? FormInstanceTypes; private static readonly Dictionary>> parentColumns = new() { { typeof(Kanban), new() { new("Parent.Number", "Task No") } }, { typeof(Job), new() { new("Parent.JobNumber", "Job No") } }, { typeof(JobITP), new() { new("Parent.Code", "Code") } }, { typeof(Assignment), new() { new("Parent.Number", "Ass. No") } }, { typeof(TimeSheet), new() { } }, { typeof(LeaveRequest), new() { } }, { typeof(Employee), new() { new("Parent.Code", "Employee") } }, { typeof(PurchaseOrderItem), new() { new("Parent.PONumber", "PO No") } }, }; private static bool CategoryToType(string category, [NotNullWhen(true)] out Type? formType, [NotNullWhen(true)] out Type? parentType) { FormInstanceTypes ??= CoreUtils.TypeList( AppDomain.CurrentDomain.GetAssemblies(), x => !x.IsAbstract && x.GetInterfaces().Contains(typeof(IDigitalFormInstance)) ).Select(x => { var inter = x.GetInterfaces() .Where(x => x.IsGenericType && x.GetGenericTypeDefinition().Equals(typeof(IDigitalFormInstance<>))).FirstOrDefault(); if (inter is not null) { var link = inter.GenericTypeArguments[0]; var entityLinkDef = link.GetSuperclassDefinition(typeof(EntityLink<>)); if (entityLinkDef is not null) { var entityType = entityLinkDef.GenericTypeArguments[0]; return new Tuple(entityType.Name, x, entityType); } } return null; }).Where(x => x is not null).ToDictionary(x => x!.Item1, x => new Tuple(x!.Item2, x!.Item3)); if (!FormInstanceTypes.TryGetValue(category, out var result)) { formType = null; parentType = null; return false; } formType = result.Item1; parentType = result.Item2; return true; } private void SetCategory(string category) { if (!CategoryToType(category, out var formType, out var parentType)) { IsEntityForm = false; ParentType = null; FormType = null; return; } IsEntityForm = formType.IsSubclassOfRawGeneric(typeof(EntityForm<,>)); ParentType = parentType; FormType = formType; } #endregion private string GetJobLink(string prefix, Type type) { var props = type.GetProperties().Where(x => x.PropertyType.BaseType != null && x.PropertyType.BaseType.IsGenericType && x.PropertyType.BaseType.GetGenericTypeDefinition() == typeof(EntityLink<>)); foreach (var prop in props) { if (prop.PropertyType == typeof(JobLink)) return (string.IsNullOrEmpty(prefix) ? "" : prefix + ".") + prop.Name; var result = GetJobLink((string.IsNullOrEmpty(prefix) ? "" : prefix + ".") + prop.Name, prop.PropertyType); if (!string.IsNullOrEmpty(result)) return result; } return ""; } /// /// Find a link from the form type to an associated , allowing us to filter based on jobs. /// /// The property name of the . private string GetJobLink() where T : IDigitalFormInstance => GetJobLink("", typeof(T)); private IKeyedQueryDef GetFormQuery() where T : Entity, IRemotable, IPersistent, IDigitalFormInstance, new() { var sort = LookupFactory.DefineSort(); var jobLink = GetJobLink(); var filter = new Filter(x => x.FormCompleted).IsGreaterThanOrEqualTo(From) .And(x => x.FormCompleted).IsLessThan(To.AddDays(1)) .And(x => x.Form.ID).IsEqualTo(Form!.ID); if (Properties.JobID != Guid.Empty && Properties.ShowJobFilter) { filter.And(jobLink + ".ID").IsEqualTo(Properties.JobID); } var columns = new Columns(x => x.ID) .Add(x => x.Form.ID) .Add(x => x.FormData) .Add(x => x.FormCompleted) .Add(x => x.FormCompletedBy.UserID) .Add(x => x.Location.Timestamp) .Add(x => x.Location.Latitude) .Add(x => x.Location.Longitude); var parentcols = LookupFactory.DefineColumns(ParentType!); foreach (var col in parentcols.ColumnNames()) columns.Add("Parent." + col); if (parentColumns.TryGetValue(ParentType!, out var pColumns)) { foreach (var (field, name) in pColumns) { columns.Add(field); } } if (IsEntityForm) columns.Add("Processed"); if (!string.IsNullOrWhiteSpace(jobLink)) columns.Add(jobLink + ".JobNumber"); return new KeyedQueryDef(filter, columns, sort); } #endregion private void RefreshData() where TForm : Entity, IRemotable, IPersistent, IDigitalFormInstance, new() { var formQuery = GetFormQuery(); var queries = new List() { new KeyedQueryDef(new Filter(x => x.Form.ID).IsEqualTo(Form!.ID)), new KeyedQueryDef( new Filter(x => x.Form.ID).IsEqualTo(Form.ID), null, new SortOrder(x => x.Sequence)), formQuery }; if (ParentType == typeof(JobITPForm)) { queries.Add(new KeyedQueryDef( new Filter(x => x.ID).InQuery((formQuery.Filter as Filter)!, x => x.Parent.ID), new Columns(x => x.ID, x => x.Job.JobNumber))); } var results = Client.QueryMultiple(queries); var questions = results.Get(); var variables = results.Get().ToList(); var formData = results.Get(formQuery.Key).Rows; var data = new DataTable(); data.Columns.Add("ID", typeof(Guid)); data.Columns.Add("Form_ID", typeof(Guid)); data.Columns.Add("Parent_ID", typeof(Guid)); data.Columns.Add("Location_Timestamp", typeof(DateTime)); data.Columns.Add("Location_Latitude", typeof(double)); data.Columns.Add("Location_Longitude", typeof(double)); data.Columns.Add("FormData", typeof(string)); if (ParentType == typeof(JobITP)) { data.Columns.Add("Job No", typeof(string)); } if (parentColumns.TryGetValue(ParentType!, out var pColumns)) { foreach (var (field, name) in pColumns) { data.Columns.Add(name, typeof(string)); } } data.Columns.Add("Description", typeof(string)); data.Columns.Add("Completed", typeof(DateTime)); data.Columns.Add("Completed By", typeof(string)); if (IsEntityForm) data.Columns.Add("Processed", typeof(bool)); if (variables.Any()) { foreach (var variable in variables) { var code = variable.Code.Replace("/", " "); QuestionCodes[code] = Thread.CurrentThread.CurrentCulture.TextInfo.ToTitleCase(code.ToLower()); data.Columns.Add(code, typeof(string)); } } else if (questions.Rows.Any()) { Progress.SetMessage("Loading Checks"); QAGrid.Clear(); QAGrid.LoadChecks(Form.Description, questions.Rows.Select(x => x.ToObject()), new Dictionary()); QAGrid.CollapseMargins(); var i = 1; foreach (var row in questions.Rows) { var id = row.Get(x => x.ID).ToString(); if (!row.Get(x => x.Answer).Equals(QAAnswer.Comment)) { data.Columns.Add(id, typeof(string)); var code = row.Get(x => x.Code); QuestionCodes[id] = string.IsNullOrEmpty(code) ? string.Format("{0}.", i) : code; i++; } } } foreach (var row in formData) { var form = (row.ToObject(FormType!) as IDigitalFormInstance)!; if (!string.IsNullOrWhiteSpace(form.FormData)) { var dataRow = data.NewRow(); dataRow["ID"] = form.ID; dataRow["Form_ID"] = form.Form.ID; dataRow["Parent_ID"] = form.ParentID(); dataRow["Location_Timestamp"] = form.Location.Timestamp; dataRow["Location_Latitude"] = form.Location.Latitude; dataRow["Location_Longitude"] = form.Location.Longitude; dataRow["FormData"] = form.FormData; var desc = new List(); foreach (var col in formQuery.Columns!.ColumnNames().Where(x => x != "ID")) { if (col.StartsWith("Parent.")) { var val = row[col]; if (val != null && val is not Guid) desc.Add(val.ToString() ?? ""); } } dataRow["Description"] = string.Join(" : ", desc); dataRow["Completed"] = form.FormCompleted; dataRow["Completed By"] = form.FormCompletedBy.UserID; if (IsEntityForm) dataRow["Processed"] = (bool?)row["Processed"] ?? false; if (ParentType == typeof(JobITP)) { var jobITP = results.Get().Rows.FirstOrDefault(x => x.Get(x => x.ID) == form.ParentID()); dataRow["Job No"] = jobITP?.Get(x => x.Job.JobNumber); } if (pColumns != null) { foreach (var (field, name) in pColumns) { dataRow[name] = row[field]?.ToString(); } } //datarow["Job No"] = (String)row[JobLink + ".JobNumber"]; var bHasData = false; if (variables.Any()) { var dict = Serialization.Deserialize>(form.FormData); foreach (var key in dict.Keys) { var variable = variables.FirstOrDefault(x => string.Equals(key, x.Code)); if (variable != null) { var value = variable.ParseValue(dict[key]); object format = variable.FormatValue(value); var sKey = key.Replace("/", " "); if (data.Columns.Contains(sKey)) { dataRow[sKey] = format; bHasData = true; } } } } else { var dict = Serialization.Deserialize>(form.FormData); foreach (var key in dict.Keys) if (data.Columns.Contains(key.ToString())) { dataRow[key.ToString()] = dict[key]; bHasData = true; } } if (bHasData) data.Rows.Add(dataRow); } } DataGrid.ItemsSource = data; QAGrid.Visibility = !variables.Any() && questions.Rows.Any() ? Visibility.Visible : Visibility.Collapsed; DataGrid.Visibility = Visibility.Visible; } public void Refresh() { Progress.Show("Refreshing"); try { QAGrid.Clear(); QAGrid.LoadChecks("", Array.Empty(), new Dictionary()); DataGrid.ItemsSource = null; if (ParentType is null || FormType is null || Form is null || Form.ID == Guid.Empty) { QAGrid.Visibility = Visibility.Collapsed; DataGrid.Visibility = Visibility.Collapsed; return; } Progress.SetMessage("Loading Data"); var refreshMethod = typeof(DigitalFormsDashboard).GetMethod(nameof(RefreshData), BindingFlags.Instance | BindingFlags.NonPublic)!.MakeGenericMethod(FormType); refreshMethod.Invoke(this, Array.Empty()); } finally { Progress.Close(); } } public void Shutdown() { } #region DataGrid Configuration private void DataGrid_AutoGeneratingColumn(object sender, Syncfusion.UI.Xaml.Grid.AutoGeneratingColumnArgs e) { e.Column.TextAlignment = TextAlignment.Center; e.Column.HorizontalHeaderContentAlignment = HorizontalAlignment.Center; e.Column.ColumnSizer = GridLengthUnitType.None; var value = (e.Column.ValueBinding as Binding)!; if (value.Path.Path.Equals("ID") || value.Path.Path.Equals("Form_ID") || value.Path.Path.Equals("Parent_ID") || value.Path.Path.Equals("FormData") || value.Path.Path.Equals("Location_Latitude") || value.Path.Path.Equals("Location_Longitude")) { e.Cancel = true; } else if (value.Path.Path.Equals("Location_Timestamp")) { e.Column = new GridImageColumn(); e.Column.Width = DataGrid.RowHeight; e.Column.HeaderStyle = Resources["TemplateHeaderStyle"] as Style; e.Column.HeaderText = ""; e.Column.Padding = new Thickness(4); e.Column.ValueBinding = new Binding { Path = new PropertyPath(value.Path.Path), Converter = new MileStoneImageConverter() }; e.Column.MappingName = "Location.Timestamp"; } else if (ParentType is not null && parentColumns.TryGetValue(ParentType, out var pColumns) && pColumns.Any(x => x.Item2.Equals(value.Path.Path))) { e.Column.ColumnSizer = GridLengthUnitType.Auto; e.Column.HeaderStyle = Resources["TemplateHeaderStyle"] as Style; } else if (value.Path.Path.Equals("Job No")) { e.Column.Width = 60; e.Column.HeaderStyle = Resources["TemplateHeaderStyle"] as Style; } else if (value.Path.Path.Equals("Description")) { e.Column.TextAlignment = TextAlignment.Left; e.Column.HorizontalHeaderContentAlignment = HorizontalAlignment.Left; e.Column.Width = 450; e.Column.HeaderStyle = Resources["TemplateHeaderStyle"] as Style; } else if (value.Path.Path.Equals("Completed")) { e.Column.Width = 100; e.Column.HeaderStyle = Resources["TemplateHeaderStyle"] as Style; (e.Column as GridDateTimeColumn)!.Pattern = DateTimePattern.CustomPattern; (e.Column as GridDateTimeColumn)!.CustomPattern = "dd MMM yy hh:mm"; } else if (value.Path.Path.Equals("Completed By")) { e.Column.Width = 100; e.Column.HeaderStyle = Resources["TemplateHeaderStyle"] as Style; } else if (value.Path.Path.Equals("Processed")) { e.Column.Width = 100; e.Column.HeaderStyle = Resources["TemplateHeaderStyle"] as Style; } else { var data = DataGrid.ItemsSource as DataTable; //int index = data.Columns.IndexOf(e.Column.MappingName) - 2; //Style style = new Style(typeof(GridCell)); //e.Column.CellStyle = style; e.Column.Width = 100; e.Column.HeaderStyle = Resources["TemplateHeaderStyle"] as Style; e.Column.HeaderText = QuestionCodes[e.Column.MappingName]; } } private Entity? GetEntityForm(Guid id) where T : Entity, IDigitalFormInstance, IRemotable, IPersistent, new() { var columns = new Columns(x => x.ID) .Add(x => x.FormCompleted) .Add(x => x.FormData) .Add(x => x.Form.ID) .Add(x => x.Form.Description); if (typeof(T).HasInterface(typeof(IDigitalFormInstance<>))) { columns.Add("Parent.ID"); } return new Client().Query( new Filter(x => x.ID).IsEqualTo(id), columns).Rows.FirstOrDefault()?.ToObject(); } private void DataGrid_CellDoubleTapped(object sender, Syncfusion.UI.Xaml.Grid.GridCellDoubleTappedEventArgs e) { if (e.RowColumnIndex.RowIndex == 0) return; var table = (DataGrid.ItemsSource as DataTable)!; var formid = (Guid)table.Rows[e.RowColumnIndex.RowIndex - 1]["Form_ID"]; var formdata = (string)table.Rows[e.RowColumnIndex.RowIndex - 1]["FormData"]; var id = (Guid)table.Rows[e.RowColumnIndex.RowIndex - 1]["ID"]; if (FormType is null) return; var entityForm = typeof(DigitalFormsDashboard) .GetMethod(nameof(GetEntityForm), BindingFlags.NonPublic | BindingFlags.Instance)! .MakeGenericMethod(FormType) .Invoke(this, new object[] { id }) as IDigitalFormInstance; if (entityForm is not null) { if (DynamicFormEditWindow.EditDigitalForm(entityForm, out var dataModel)) { dataModel.Update(null); /*typeof(QADashboard) .GetMethod(nameof(SaveEntityForm), System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)! .MakeGenericMethod(formType) .Invoke(this, new object[] { entityForm });*/ Refresh(); } } } private void DataGrid_CellTapped(object sender, Syncfusion.UI.Xaml.Grid.GridCellTappedEventArgs e) { if (e.RowColumnIndex.ColumnIndex == 0) { var timestamp = (DateTime)(e.Record as DataRowView)!.Row["Location_Timestamp"]; var latitude = (double)(e.Record as DataRowView)!.Row["Location_Latitude"]; var longitude = (double)(e.Record as DataRowView)!.Row["Location_Longitude"]; var form = new MapForm(latitude, longitude, timestamp); form.ShowDialog(); } } #endregion } }