private void GetEntities(Action <List <string> > callback) { var QEplugintracelog = new QueryExpression("plugintracelog"); QEplugintracelog.Distinct = true; QEplugintracelog.ColumnSet.AddColumns("primaryentity"); var asyncinfo = new WorkAsyncInfo() { Message = "Loading entities", Work = (a, args) => { args.Result = Service.RetrieveMultiple(QEplugintracelog); }, PostWorkCallBack = (args) => { if (args.Error != null) { MessageBox.Show($"Failed to load entities:\n{args.Error.Message}", "Load", MessageBoxButtons.OK, MessageBoxIcon.Error); } else if (args.Result is EntityCollection) { var entities = ((EntityCollection)args.Result).Entities; var entitylist = entities.Where(e => e.Attributes.Contains("primaryentity")).Select(e => e.Attributes["primaryentity"].ToString()).ToList(); callback(entitylist); } } }; WorkAsync(asyncinfo); }
private void GetEntities(Action <List <string> > callback) { ptv.LogInfo("GetEntities"); var QEplugintracelog = new QueryExpression("plugintracelog"); QEplugintracelog.Distinct = true; QEplugintracelog.ColumnSet.AddColumns("primaryentity"); var asyncinfo = new WorkAsyncInfo() { Message = "Loading entities", Work = (a, args) => { args.Result = ptv.Service.RetrieveMultiple(QEplugintracelog); }, PostWorkCallBack = (args) => { if (args.Error != null) { ptv.LogError("GetEntities {0}", args.Error.Message); callback(new List <string>()); } else if (args.Result is EntityCollection) { var entities = ((EntityCollection)args.Result).Entities; var entitylist = entities.Where(e => e.Attributes.Contains("primaryentity")).Select(e => e.Attributes["primaryentity"].ToString()).ToList(); ptv.LogInfo("GetEntities = {0}", entitylist.Count); callback(entitylist); } } }; ptv.WorkAsync(asyncinfo); }
internal void PopulateGrid(IEnumerable <Entity> results) { ptv.LogInfo("PopulateGrid with {0} logs", results.Count()); var asyncinfo = new WorkAsyncInfo() { Message = "Populating result view", Work = (a, args) => { ptv.UpdateUI(() => { refreshingGrid = true; crmGridView.DataSource = results; refreshingGrid = false; ptv.SendStatusMessage($"Loaded {results.Count()} trace records"); UpdateColumnsLayout(); }); }, PostWorkCallBack = (args) => { if (args.Error != null) { ptv.ShowErrorDialog(args.Error, "Populating Results"); } } }; ptv.WorkAsync(asyncinfo); }
private void bMove_Click(object sender, EventArgs e) { var targetType = (PluginType)((ComboBox)cbTargetPlugin).SelectedItem; var steps = this.lvSteps.SelectedItems.Cast <ListViewItem>().Select <ListViewItem, Entity>(x => ((ProcessingStep)x.Tag).ToEntity()).ToArray(); var info = new WorkAsyncInfo(); info.Message = "Moving steps..."; info.Work = (worker, a) => { foreach (var step in steps) { step[Constants.Crm.Attributes.PLUGIN_TYPE_ID] = targetType.ToEntity().ToEntityReference(); step.Attributes.Remove("eventhandler"); try { this.Service.Update(step); } catch (Exception) { // Failed to match } } }; info.PostWorkCallBack = (a) => { RetrieveSteps(); }; WorkAsync(info); }
internal void PopulateGrid(EntityCollection results) { ptv.LogInfo("PopulateGrid with {0} logs", results.Entities.Count); var asyncinfo = new WorkAsyncInfo() { Message = "Populating result view", Work = (a, args) => { ptv.UpdateUI(() => { refreshingGrid = true; crmGridView.DataSource = results; refreshingGrid = false; ptv.SendStatusMessage($"Loaded {results.Entities.Count} trace records"); UpdateColumnsLayout(); }); }, PostWorkCallBack = (args) => { if (args.Error != null) { ptv.AlertError($"Failed to populate result view:\n{args.Error.Message}", "Load"); } } }; ptv.WorkAsync(asyncinfo); }
private void dgvRelationships_CellDoubleClick(object sender, DataGridViewCellEventArgs e) { if (e.RowIndex < 0) { return; } WorkAsyncInfo wai = new WorkAsyncInfo { Message = "Retrieving info from CRM...", Work = (worker, args) => { Result result = null; result = Browser.GetEntityResult(Service, cache, dgvRelationships.Rows[e.RowIndex].Cells[3].Value.ToString(), worker); if (result != null) { results.Push(result); if (!result.FromCache) { SaveCache(); } } }, ProgressChanged = ProgressChanged, PostWorkCallBack = NewResultsAvailable, AsyncArgument = null, MessageHeight = 150, MessageWidth = 340 }; WorkAsync(wai); }
private void PopulateGrid(EntityCollection results) { var asyncinfo = new WorkAsyncInfo() { Message = "Populating result view", Work = (a, args) => { UpdateUI(() => { crmGridView.DataSource = results; var dt = crmGridView.GetDataSource <DataTable>(); if (dt != null) { dt.Columns.Add("Exception", typeof(bool), "exceptiondetails <> ''"); } labelInfo.Text = $"Loaded {results.Entities.Count} trace records"; crmGridView.AutoResizeColumns(DataGridViewAutoSizeColumnsMode.AllCells); }); }, PostWorkCallBack = (args) => { if (args.Error != null) { MessageBox.Show($"Failed to populate result view:\n{args.Error.Message}", "Load", MessageBoxButtons.OK, MessageBoxIcon.Error); } } }; WorkAsync(asyncinfo); }
private void GetDateConstraint(string aggregate, Action <DateTime> callback) { var date = DateTime.Today; var fetch = $"<fetch aggregate='true'><entity name='plugintracelog'><attribute name='createdon' alias='created' aggregate='{aggregate}'/></entity></fetch>"; var asyncinfo = new WorkAsyncInfo() { Message = $"Loading {aggregate} date limits", Work = (a, args) => { args.Result = Service.RetrieveMultiple(new FetchExpression(fetch)); }, PostWorkCallBack = (args) => { if (args.Error != null) { MessageBox.Show($"Failed to load date constraints:\n{args.Error.Message}", "Load", MessageBoxButtons.OK, MessageBoxIcon.Error); } else if (args.Result is EntityCollection && ((EntityCollection)args.Result).Entities.Count > 0) { var result = ((EntityCollection)args.Result).Entities[0]; if (result.Contains("created") && result["created"] is AliasedValue) { var created = (AliasedValue)result["created"]; if (created.Value is DateTime) { date = (DateTime)created.Value; callback(date); } } } } }; WorkAsync(asyncinfo); }
public Job(AsyncWorkQueue queue, WorkAsyncInfo work) { this.queue = queue ?? throw new ArgumentNullException(nameof(queue)); this.Work = work ?? throw new ArgumentNullException(nameof(work)); this.postWorkCallBack = work.PostWorkCallBack; this.Work.PostWorkCallBack = PostWorkCallBack; }
public void StartWorkAsync(WorkAsyncInfo work) { if (!queue.Any()) { pluginViewModel.AllowRequests = false; WorkAsync(work); } queue.Enqueue(work); }
private void Analyze() { var groups = listAttributes.Groups.Cast <ListViewGroup>().Where(g => g.Items.Cast <ListViewItem>().Any(i => i.Checked)); foreach (ListViewGroup entity in groups) { var asyncinfo = new WorkAsyncInfo { Message = $"Counting records for\n {entity.Name}", AsyncArgument = entity, Work = (worker, args) => { var group = args.Argument as ListViewGroup; var entityName = group.Name; var fetchAll = $"<fetch aggregate='true' ><entity name='{entityName}' ><attribute name='createdon' alias='Count' aggregate='count' /></entity></fetch>"; EntityCollection fetchResult = null; try { fetchResult = Service.RetrieveMultiple(new FetchExpression(fetchAll)); } finally { var value = ((AliasedValue)fetchResult.Entities[0].Attributes["Count"]).Value as int?; args.Result = new Tuple <ListViewGroup, int?>(group, value); } }, PostWorkCallBack = (args) => { var result = args.Result as Tuple <ListViewGroup, int?>; if (result == null) { MessageBox.Show($"Error while counting total record count for {entity.Header}", "Analyze", MessageBoxButtons.OKCancel, MessageBoxIcon.Error); return; } var group = result.Item1; var value = result.Item2; if (value == null) { group.Header = $"{GetGroupHeader(group)} - Unable to retrieve record count"; if (args.Error != null) { AddItemToGroup(group, "error", args.Error.Message); } } else { group.Header = $"{GetGroupHeader(group)} - {value} records"; foreach (ListViewItem attribute in group.Items.Cast <ListViewItem>().Where(i => i.Checked)) { AnalyzeAttribute(attribute); } } } }; WorkAsync(asyncinfo); } }
public void Enqueue(WorkAsyncInfo work) { var job = new Job(this, work); if (!queue.Any()) { pluginViewModel.AllowRequests = false; solutionPackagerControl.WorkAsync(job.Work); } queue.Enqueue(job); }
private void LoadAttributes() { if (Service == null) { return; } Enabled = false; if (metadata == null) { var asyncinfo = new WorkAsyncInfo() { Message = "Loading entities and attributes", Work = (a, args) => { var eqe = new EntityQueryExpression(); eqe.Properties = new MetadataPropertiesExpression("DisplayName", "Attributes"); eqe.Criteria.Conditions.Add(new MetadataConditionExpression("IsCustomizable", MetadataConditionOperator.Equals, true)); var aqe = new AttributeQueryExpression(); aqe.Properties = new MetadataPropertiesExpression(); aqe.Properties.AllProperties = true; aqe.Criteria.Conditions.Add(new MetadataConditionExpression("AttributeType", MetadataConditionOperator.Equals, AttributeTypeCode.DateTime)); //aqe.Criteria.Conditions.Add(new MetadataConditionExpression("CanChangeDateTimeBehavior", MetadataConditionOperator.Equals, true)); eqe.AttributeQuery = aqe; var req = new RetrieveMetadataChangesRequest() { Query = eqe, ClientVersionStamp = null }; args.Result = Service.Execute(req) as RetrieveMetadataChangesResponse; }, PostWorkCallBack = (args) => { if (args.Error != null) { MessageBox.Show($"Failed to load metadata:\n{args.Error.Message}", "Load", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } if (!(args.Result is RetrieveMetadataChangesResponse)) { MessageBox.Show($"Unexpected result:\n{args.Result}", "Load", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } metadata = ((RetrieveMetadataChangesResponse)args.Result).EntityMetadata; PopulateAttributes(); } }; WorkAsync(asyncinfo); } else { PopulateAttributes(); } }
public void Enqueue(WorkAsyncInfo work) { var job = new Job(this, work); if (!queue.Any()) { if (this.pluginViewModel != null) { this.pluginViewModel.AllowRequests = false; } this.pluginControl.WorkAsync(job.Work); } queue.Enqueue(job); }
private void Refresh() { Result r = results.Peek(); Result newResult = null; WorkAsyncInfo wai = new WorkAsyncInfo { Message = "Retrieving info from CRM...", Work = (worker, args) => { switch (r.DataType) { case Result.ResultType.EntityList: newResult = Browser.GetEntityListResult(Service, worker); newResult.SearchText = r.SearchText; break; case Result.ResultType.Entity: cache.Remove(r.Key); newResult = Browser.GetEntityResult(Service, cache, r.Key, worker); newResult.SearchText = r.SearchText; break; case Result.ResultType.PickList: break; case Result.ResultType.Record: break; default: break; } if (newResult != null) { results.Pop(); results.Push(newResult); } }, ProgressChanged = ProgressChanged, PostWorkCallBack = NewResultsAvailable, AsyncArgument = null, MessageHeight = 150, MessageWidth = 340 }; WorkAsync(wai); }
public void WorkAsync(IWorkAsyncWrapper info) { if (info == null) { throw new ArgumentNullException(nameof(info)); } var workAsyncInfo = new WorkAsyncInfo(); if (info.AsyncArgument != null) { workAsyncInfo.AsyncArgument = info.AsyncArgument; } if (info.Host != null) { workAsyncInfo.Host = info.Host; } if (info.IsCancelable) { workAsyncInfo.IsCancelable = info.IsCancelable; } if (info.Message != null) { workAsyncInfo.Message = info.Message; } if (info.MessageHeight > 0) { workAsyncInfo.MessageHeight = info.MessageHeight; } if (info.MessageWidth > 0) { workAsyncInfo.MessageWidth = info.MessageWidth; } if (info.PostWorkCallBack != null) { workAsyncInfo.PostWorkCallBack = info.PostWorkCallBack; } if (info.ProgressChanged != null) { workAsyncInfo.ProgressChanged = info.ProgressChanged; } if (info.Work != null) { workAsyncInfo.Work = info.Work; } WorkAsync(workAsyncInfo); }
private void MiCreateClass_Click(object sender, EventArgs e) { WorkAsyncInfo wai = new WorkAsyncInfo { Message = "Building class...", Work = (worker, args) => { args.Result = EntityTools.CreateEntityClass(Service, worker, dgvMain.SelectedRows[0].Cells[0].Value.ToString()); }, ProgressChanged = ProgressChanged, PostWorkCallBack = NewResultsAvailable, AsyncArgument = null, MessageHeight = 150, MessageWidth = 340 }; WorkAsync(wai); }
private void RefreshTraces(QueryExpression query) { if (query == null) { return; } if (Service == null) { return; } timerRefresh.Stop(); ClearControls(); LogUse("RetrieveLogs"); var asyncinfo = new WorkAsyncInfo() { Message = "Loading trace log records", Work = (a, args) => { LogInfo("Loading logs"); UpdateUI(() => { Enabled = false; }); args.Result = Service.RetrieveMultiple(query); }, PostWorkCallBack = (args) => { UpdateUI(() => { Enabled = true; }); if (args.Error != null) { AlertError($"Failed to load trace logs:\n{args.Error.Message}", "Load"); } else if (args.Result is EntityCollection) { var results = args.Result as EntityCollection; FriendlyfyCorrelationIds(results); SetTraceSizes(results); ExtractExceptionSummaries(results); gridControl.PopulateGrid(results); StartRefreshTimer(false); } } }; WorkAsync(asyncinfo); }
public static WorkAsyncInfo WithLogger(this WorkAsyncInfo info, PluginControlBase plugin, TextBox output, object asyncArgument = null, string successMessage = "Finished Successfully!", int?successPercent = 99) { plugin.Enabled = false; var oldWork = info.Work; info.Work = (w, args) => { Logger.WireUpToReportProgress(w); try { oldWork(w, args); if (successPercent.HasValue) { w.ReportProgress(successPercent.Value, successMessage); } else { plugin.Enabled = true; } } catch (Exception ex) { w.ReportProgress(int.MinValue, ex.ToString()); } finally { Logger.UnwireFromReportProgress(w); } }; info.AsyncArgument = asyncArgument; info.PostWorkCallBack = e => // Creation has finished. Cleanup { Logger.DisplayLog(e, output); plugin.Enabled = true; }; info.ProgressChanged = e => // Logic wants to display an update { Logger.DisplayLog(e, plugin.SetWorkingMessage, output); }; return(info); }
public static void RetrieveTypes(this ComboBox comboBox, PluginControlBase host, PluginAssembly pluginAssembly, bool allTypesOption = false) { if (comboBox == null || comboBox.Parent == null) { return; } var info = new WorkAsyncInfo(); info.Message = "Loading types..."; info.Work = (worker, a) => { a.Result = host.Service.GetPluginTypes(pluginAssembly.Id); }; info.PostWorkCallBack = (a) => { comboBox.Items.Clear(); if (allTypesOption) { comboBox.Items.Add(new PluginType { FriendlyName = "All types" }); } foreach (var type in ((Entity[])a.Result).Select(x => new PluginType(x, pluginAssembly))) { comboBox.Items.Add(type); } if (allTypesOption) { // Select all types comboBox.SelectedIndex = 0; } }; host.WorkAsync(info); }
private void MiAnalyzeEntity_Click(object sender, EventArgs e) { string entityLogicalName = dgvMain.SelectedRows[0].Cells[0].Value.ToString(); WorkAsyncInfo wai = new WorkAsyncInfo { Message = "Analyzing Entity " + entityLogicalName, Work = (worker, args) => { args.Result = EntityTools.AnalyzeEntity(Service, worker, entityLogicalName); }, ProgressChanged = ProgressChanged, PostWorkCallBack = NewResultsAvailable, AsyncArgument = null, MessageHeight = 150, MessageWidth = 340, }; WorkAsync(wai); }
private void MiOpenRecord_Click(object sender, EventArgs e) { string possibleid = Clipboard.ContainsText() ? Clipboard.GetText() : string.Empty; Guid id = Guid.Empty; if (!Guid.TryParse(possibleid, out id)) { string fetchXML = string.Format(@"<fetch top='1' > <entity name='{0}' > <attribute name='{0}id' /> </entity></fetch>", results.Peek().EntityLogicalName); EntityCollection ec = Service.RetrieveMultiple(new FetchExpression(fetchXML)); if (ec.Entities.Count > 0) { id = ec.Entities[0].Id; } } if (id != Guid.Empty) { WorkAsyncInfo wai = new WorkAsyncInfo { Message = "Retrieving info from CRM...", Work = (worker, args) => { Result result = Browser.GetRecordResult(Service, cache, results.Peek().EntityLogicalName, id, worker); result.Header = string.Format("{0}{{{1}}}", results.Peek().EntityLogicalName, id); if (result != null) { results.Push(result); if (!result.FromCache) { SaveCache(); } } }, ProgressChanged = ProgressChanged, PostWorkCallBack = NewResultsAvailable, AsyncArgument = null, MessageHeight = 150, MessageWidth = 340 }; WorkAsync(wai); } }
private void GetLogSetting(Action <Guid, int> callback) { LogInfo("GetLogSetting"); var qx = new QueryExpression(Const.Organization.EntityName); qx.ColumnSet.AddColumns(Const.Organization.PrimaryName, Const.Organization.PluginTraceLogsetting); var asyncinfo = new WorkAsyncInfo() { Message = "Loading organization settings", Work = (a, args) => { args.Result = Service.RetrieveMultiple(qx); }, PostWorkCallBack = (args) => { if (args.Error != null) { ShowErrorDialog(args.Error, "Load Settings"); } else if (args.Result is EntityCollection) { var entity = ((EntityCollection)args.Result).Entities.FirstOrDefault(); if (entity != null) { var id = entity.Id; var name = entity.Contains(Const.Organization.PrimaryName) ? entity[Const.Organization.PrimaryName] : "?"; var setting = entity.Contains(Const.Organization.PluginTraceLogsetting) ? ((OptionSetValue)entity[Const.Organization.PluginTraceLogsetting]).Value : 0; LogInfo("Found org: {0} with setting {1}", name, setting); callback(id, setting); } else { LogError("No organization data found!"); } } } }; WorkAsync(asyncinfo); }
private void WorkAsyncWithCancel(WorkAsyncInfo info) { WorkAsync(new WorkAsyncInfo { AsyncArgument = info.AsyncArgument, Host = info.Host, IsCancelable = info.IsCancelable, Message = info.Message, MessageHeight = info.MessageHeight, MessageWidth = info.MessageWidth, PostWorkCallBack = (args) => { if (InvokeRequired) { Invoke((Action)(() => { tsbStop.Enabled = false; })); } else { tsbStop.Enabled = false; } info.PostWorkCallBack(args); }, ProgressChanged = info.ProgressChanged, Work = (worker, args) => { if (InvokeRequired) { Invoke((Action)(() => { tsbStop.Enabled = true; })); } else { tsbStop.Enabled = true; } info.Work(worker, args); } }); }
private void GetDateConstraint(string aggregate, Action <DateTime> callback) { ptv.LogInfo("GetDateConstraint {0}", aggregate); var date = DateTime.Today; var fetch = $"<fetch aggregate='true'><entity name='plugintracelog'><attribute name='createdon' alias='created' aggregate='{aggregate}'/></entity></fetch>"; var asyncinfo = new WorkAsyncInfo() { Message = $"Loading {aggregate} date limits", Work = (a, args) => { args.Result = ptv.Service.RetrieveMultiple(new FetchExpression(fetch)); }, PostWorkCallBack = (args) => { if (args.Error != null) { ptv.LogError("GetDateConstraint({0}): {1}", aggregate, args.Error); callback(DateTime.MinValue); } else if (args.Result is EntityCollection && ((EntityCollection)args.Result).Entities.Count > 0) { var result = ((EntityCollection)args.Result).Entities[0]; if (result.Contains("created") && result["created"] is AliasedValue) { var created = (AliasedValue)result["created"]; if (created.Value is DateTime) { date = (DateTime)created.Value; ptv.LogInfo("GetDateConstraint {0} = {1}", aggregate, date); callback(date); } } } } }; ptv.WorkAsync(asyncinfo); }
private void LoadEntityList() { WorkAsyncInfo wai = new WorkAsyncInfo { Message = "Retrieving info from CRM...", Work = (worker, args) => { Result result = Browser.GetEntityListResult(Service, worker); if (result != null) { results.Push(result); } }, ProgressChanged = ProgressChanged, PostWorkCallBack = NewResultsAvailable, AsyncArgument = null, MessageHeight = 150, MessageWidth = 340 }; WorkAsync(wai); }
private void btnDoSomethingWrong_Click(object sender, EventArgs e) { var asyncinfo = new WorkAsyncInfo() { Work = (a, args) => { args.Result = Service.RetrieveMultiple(new QueryExpression("account_oops")); }, PostWorkCallBack = (args) => { if (args.Error != null) { ShowErrorDialog(args.Error, "Loading Accounts"); } else { MessageBox.Show("Tada!"); } } }; WorkAsync(asyncinfo); }
private void MiDocumentEntity_Click(object sender, EventArgs e) { WorkAsyncInfo wai = new WorkAsyncInfo { Message = "Documenting entity...", Work = (worker, args) => { StringBuilder sb = new StringBuilder(); string entityLogicalName = dgvMain.SelectedRows[0].Cells[0].Value.ToString(); string entityDisplayName = dgvMain.SelectedRows[0].Cells[2].Value.ToString(); List <Tuple <string, string, string> > attributes = Browser.GetEntityAttributes(Service, entityLogicalName); sb.AppendLine(string.Format("Entity Logical Name\t{0}", entityLogicalName)); sb.AppendLine(string.Format("Entity Display Name\t{0}", entityDisplayName)); sb.AppendLine(""); sb.AppendLine("Attributes"); sb.AppendLine("Logical Name\tDisplay Name\tType"); attributes.Sort((x, y) => x.Item1.CompareTo(y.Item1)); foreach (Tuple <string, string, string> att in attributes) { sb.AppendLine(string.Format("{0}\t{1}\t{2}", att.Item1, att.Item3, att.Item2)); } args.Result = sb.ToString(); }, ProgressChanged = ProgressChanged, PostWorkCallBack = NewResultsAvailable, AsyncArgument = null, MessageHeight = 150, MessageWidth = 340 }; WorkAsync(wai); }
private void removeSelectedToolStripMenuItem_Click(object sender, EventArgs e) { if (lvSteps.SelectedItems.Count > 0) { var result = MessageBox.Show("Confirmation", string.Format("Do you really want to delete {0} steps?", this.lvSteps.SelectedItems.Count), MessageBoxButtons.YesNo); if (result == DialogResult.Yes) { var info = new WorkAsyncInfo(); info.Message = "Matching types in source and target assemblies..."; info.Work = (worker, a) => { Invoke(new Action(() => { foreach (var step in this.lvSteps.SelectedItems.Cast <ListViewItem>().Select <ListViewItem, Entity>(x => ((ProcessingStep)x.Tag).ToEntity()).ToArray()) { this.Service.Delete(step.LogicalName, step.Id); } })); }; } } }
private void AnalyzeAttribute(ListViewItem item) { var group = item?.Group; if (item != null && group != null) { while (item.SubItems.Count < 5) { item.SubItems.Add(""); } item.SubItems[4].Text = "Counting..."; item.SubItems[4].BackColor = Color.Yellow; var fetchAttr = $"<fetch aggregate='true' ><entity name='{group.Name}' ><attribute name='{item.Name}' alias='Count' aggregate='countcolumn' /></entity></fetch>"; var asyncinfo = new WorkAsyncInfo { Message = $"Analyzing {group.Name}.{item.Name}", Work = (worker, args) => { try { var resultAttr = Service.RetrieveMultiple(new FetchExpression(fetchAttr)); var value = ((AliasedValue)resultAttr.Entities[0].Attributes["Count"]).Value as int?; args.Result = new Tuple <ListViewItem, int?, Exception>(item, value, null); } catch (Exception ex) { args.Result = new Tuple <ListViewItem, int?, Exception>(item, null, ex); } }, PostWorkCallBack = (args) => { var result = args.Result as Tuple <ListViewItem, int?, Exception>; if (result == null) { MessageBox.Show("Fatal unknown error while counting records", "Analyze", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } var attributeItem = result.Item1; var value = result.Item2; var ex = result.Item3; if (value == null) { if (ex != null) { attributeItem.SubItems[4].Text = ex.Message; } else { attributeItem.SubItems[4].Text = "failed"; } attributeItem.SubItems[4].BackColor = Color.Red; } else { attributeItem.SubItems[4].Text = value.ToString(); attributeItem.SubItems[4].Tag = value; attributeItem.SubItems[4].BackColor = Color.LightGreen; } } }; WorkAsync(asyncinfo); } }