/// <summary> /// Event when an option set attribute is selected. /// </summary> /// <param name="sender">Sender argument.</param> /// <param name="e">Event arguments.</param> private void AttributesList_SelectedValueChanged(object sender, EventArgs e) { OptionsList.DataSource = null; EntityItem currentEntity = (EntityItem)EntitiesList.SelectedItem; EntityItem currentAttribute = (EntityItem)AttributesList.SelectedItem; if (currentAttribute != null) { if (!currentAttribute.Loaded) { this.ExecuteMethod <EntityItem>(this.GetOptions, currentAttribute); } else { OptionsList.DataSource = new BindingList <EntityItem>(currentAttribute.Children); } if (OptionsList.SelectedItem == null) { if (AttributesList.SelectedItem != null) { this.ShowLabels(false); } else { this.ShowLabels(false); } } AddButton.Enabled = AttributesList.SelectedIndex > -1 && OptionsList.Items.Count < 300; } }
/// <summary> /// Event when the add button is clicked. /// </summary> /// <param name="sender">Sender argument.</param> /// <param name="e">Event arguments.</param> private void AddButton_Click(object sender, EventArgs e) { LocalizedLabel[] localLabels = new LocalizedLabel[this.installedLanguages.Count]; LocalizedLabel[] localDescriptions = new LocalizedLabel[this.installedLanguages.Count]; for (int i = 0; i < this.installedLanguages.Count; i++) { localLabels[i] = new LocalizedLabel(string.Empty, this.installedLanguages.Keys.Skip(i).First()); localDescriptions[i] = new LocalizedLabel(string.Empty, this.installedLanguages.Keys.Skip(i).First()); } Microsoft.Xrm.Sdk.Label label = new Microsoft.Xrm.Sdk.Label(new LocalizedLabel(string.Empty, this.DefaultLanguage), localLabels); Microsoft.Xrm.Sdk.Label description = new Microsoft.Xrm.Sdk.Label(new LocalizedLabel(string.Empty, this.DefaultLanguage), localDescriptions); int currentValue = 0; var currentItem = (EntityItem)AttributesList.SelectedItem; for (int i = this.OptionSetPrefix * 10000; i < (this.OptionSetPrefix * 10000) + 9999; i++) { if (!currentItem.Children.Exists(c => c.Value == i)) { currentValue = i; break; } } EntityItem item = new EntityItem(currentValue, label, description, currentItem); currentItem.Children.Add(item); OptionsList.DataSource = new BindingList <EntityItem>(((EntityItem)AttributesList.SelectedItem).Children); OptionsList.SelectedItem = item; AddButton.Enabled = AttributesList.SelectedIndex > -1 && OptionsList.Items.Count < 300; item.Changed = true; item.Parent.Changed = true; PublishMenu.Enabled = true; }
/// <summary> /// Gets the attributes for the selected entity from CRM. /// </summary> /// <param name="entity">The entity whose attributes are to be retrieved.</param> private void GetAttributes(EntityItem entity) { this.WorkAsync(new WorkAsyncInfo { Message = "Retrieving option attributes...", Work = (w, e) => { var request = new RetrieveEntityRequest { LogicalName = entity.LogicalName, EntityFilters = EntityFilters.Attributes }; var response = (RetrieveEntityResponse)Service.Execute(request); e.Result = response.EntityMetadata; }, PostWorkCallBack = e => { AttributeMetadata[] results = ((EntityMetadata)e.Result).Attributes; entity.Children = new List <EntityItem>(); entity.Children.AddRange(results.Where(r => r.AttributeType == AttributeTypeCode.Picklist && r.DisplayName.UserLocalizedLabel != null).Select(r => new EntityItem(r.DisplayName.UserLocalizedLabel.Label, r.LogicalName, entity))); AttributesList.DataSource = new BindingList <EntityItem>(entity.Children.ToArray()); entity.Loaded = true; ImportMenu.Enabled = true; ExportMenu.Enabled = true; }, AsyncArgument = null, IsCancelable = true, MessageWidth = 340, MessageHeight = 150 }); }
/// <summary> /// Moves an item in the given direction /// </summary> /// <param name="direction">positive number to move down, negative number to move down.</param> private void MoveItem(int direction) { int newIndex = OptionsList.SelectedIndex + direction; EntityItem selected = OptionsList.SelectedItem as EntityItem; ((EntityItem)AttributesList.SelectedItem).Children.RemoveAt(OptionsList.SelectedIndex); ((EntityItem)AttributesList.SelectedItem).Children.Insert(newIndex, selected); ((EntityItem)AttributesList.SelectedItem).Changed = true; OptionsList.SetSelected(newIndex, true); }
/// <summary> /// Retrieves the options from CRM for the selected attribute. /// </summary> /// <param name="attribute">The attribute whose options are to be retrieved.</param> private void GetOptions(EntityItem attribute) { var request = new RetrieveAttributeRequest { EntityLogicalName = attribute.Parent.LogicalName, LogicalName = attribute.LogicalName, RetrieveAsIfPublished = true }; var response = (RetrieveAttributeResponse)Service.Execute(request); var attributeMetadata = (EnumAttributeMetadata)response.AttributeMetadata; OptionSetMetadata optionset = attributeMetadata.OptionSet; attribute.GlobalName = optionset.IsGlobal.GetValueOrDefault() ? optionset.Name : null; if (attribute.Global) { foreach (var item in EntitiesList.Items.Cast <EntityItem>()) { var existing = item.Children.Where(i => i.GlobalName == attribute.GlobalName && i.LogicalName != attribute.LogicalName && i.Parent.LogicalName != attribute.Parent.LogicalName); if (existing.Count() > 0) { attribute.Children.AddRange(existing.First().Children); attribute.Loaded = true; OptionsList.DataSource = new BindingList <EntityItem>(attribute.Children); AttributesList.DataSource = null; AttributesList.DataSource = new BindingList <EntityItem>(attribute.Parent.Children.ToArray()); return; } } } attribute.Children = new List <EntityItem>(); attribute.Children.AddRange(optionset.Options.Select(r => new EntityItem(r.Value.GetValueOrDefault(), r.Label, r.Description, attribute))); this.Loading = true; OptionsList.DataSource = new BindingList <EntityItem>(attribute.Children); this.Loading = false; attribute.Loaded = true; if (attribute.Global) { var selected = AttributesList.SelectedItem; AttributesList.DataSource = null; AttributesList.DataSource = new BindingList <EntityItem>(attribute.Parent.Children.ToArray()); AttributesList.SelectedItem = selected; } }
/// <summary> /// Get a request to add to the batch. /// </summary> /// <param name="option">The option for the request.</param> /// <param name="operation">The operation we are doing.</param> /// <returns>The request created.</returns> private static OrganizationRequest GetRequest(EntityItem option, Operation operation) { OrganizationRequest request = null; switch (operation) { case Operation.Insert: request = new InsertOptionValueRequest { OptionSetName = option.Parent.GlobalName, EntityLogicalName = option.Parent.Global ? null : option.Parent.Parent.LogicalName, AttributeLogicalName = option.Parent.Global ? null : option.Parent.LogicalName, Value = option.Value, Label = option.Label, Description = option.Description }; break; case Operation.Update: request = new UpdateOptionValueRequest { OptionSetName = option.Parent.GlobalName, EntityLogicalName = option.Parent.Global ? null : option.Parent.Parent.LogicalName, AttributeLogicalName = option.Parent.Global ? null : option.Parent.LogicalName, Value = option.Value, Label = option.Label, Description = option.Description }; break; case Operation.Delete: request = new DeleteOptionValueRequest { OptionSetName = option.GlobalName, EntityLogicalName = option.Global ? null : option.Parent.LogicalName, AttributeLogicalName = option.Global ? null : option.LogicalName, Value = option.Value }; break; default: break; } return(request); }
/// <summary> /// Exports the changed items to a comma separated file. /// </summary> /// <param name="exportItems">The items that have changed.</param> /// <param name="installedLanguages">The list of languages installed.</param> /// <returns>The comma separated file.</returns> internal string Export(IEnumerable <EntityItem> exportItems, Dictionary <int, string> installedLanguages) { StringBuilder csv = new StringBuilder("Entity,Attribute,Global Name,Value,"); foreach (var item in installedLanguages.OrderBy(l => l.Key)) { csv.Append("Label-"); csv.Append(item.Value); csv.Append(','); } foreach (var item in installedLanguages.OrderBy(l => l.Key)) { csv.Append("Description-"); csv.Append(item.Value); csv.Append(','); } csv.Length = csv.Length - 1; csv.AppendLine(); List <EntityItem> export = new List <EntityItem>(); for (int i = 0; i < exportItems.Count(); i++) { EntityItem exportItem = exportItems.Skip(i).First(); if (!exportItem.Loaded) { this.GetOptions(exportItem); } export.Add(exportItem); } foreach (var item in export) { csv.Append(item.ToCSV(installedLanguages.OrderBy(l => l.Key).Select(l => l.Key))); } return(csv.ToString()); }
/// <summary> /// Event when an item is selected from the entities list. /// </summary> /// <param name="sender">Sender argument.</param> /// <param name="e">Event arguments.</param> private void EntitiesList_SelectedValueChanged(object sender, EventArgs e) { AttributesList.DataSource = null; EntityItem currentItem = (EntityItem)EntitiesList.SelectedItem; if (!currentItem.Loaded) { this.ExecuteMethod <EntityItem>(this.GetAttributes, currentItem); } else { AttributesList.DataSource = new BindingList <EntityItem>(currentItem.Children.ToArray()); ImportMenu.Enabled = true; ExportMenu.Enabled = true; } if (OptionsList.SelectedItem == null) { this.ShowLabels(false); } }
/// <summary> /// Event when the mouse is moved over a list. /// </summary> /// <param name="sender">Sender argument.</param> /// <param name="e">Event arguments.</param> private void List_MouseMove(object sender, MouseEventArgs e) { string toolTipText = string.Empty; System.Windows.Forms.ListBox list = (System.Windows.Forms.ListBox)sender; int index = list.IndexFromPoint(e.Location); if ((index >= 0) && (index < list.Items.Count)) { EntityItem item = (EntityItem)list.Items[index]; if (!string.IsNullOrWhiteSpace(item?.Parent?.GlobalName)) { toolTipText += $"Global optionset\t= {item.Parent.GlobalName}\r\n"; } if (!string.IsNullOrWhiteSpace(item?.GlobalName)) { toolTipText += $"Global optionset\t= {item.GlobalName}\r\n"; } toolTipText += $"Disaplay Name\t= {item.DisplayName}\r\n"; if (item.Value == 0) { toolTipText += $"Logical Name\t= {item.LogicalName}\r\n"; } else { toolTipText += $"Description\t= {item?.Description?.LocalizedLabels.Where(l => l.LanguageCode == DefaultLanguage).FirstOrDefault()?.Label}\r\n"; toolTipText += $"Value\t\t= {item.Value}"; } if (this.toolTip.GetToolTip(list) != toolTipText) { toolTip.SetToolTip(list, toolTipText); } } }
/// <summary> /// Event when an option is selected from the list. /// </summary> /// <param name="sender">Sender argument.</param> /// <param name="e">Event arguments.</param> private void OptionsList_SelectedValueChanged(object sender, EventArgs e) { if (OptionsList.SelectedItem != null) { EntityItem currentOption = (EntityItem)OptionsList.SelectedItem; ValueText.DataBindings.Clear(); this.Loading = true; this.ValueText.DataBindings.Add( "Text", currentOption, "Value", false, DataSourceUpdateMode.OnPropertyChanged); this.LoadLabels(this.LabelsGroup, currentOption.Label); DescriptionsGroup.Top = LabelsGroup.Top + LabelsGroup.Height + 30; this.LoadLabels(this.DescriptionsGroup, currentOption.Description); this.CurrentValue = ValueText.Text; this.Loading = false; } this.ShowArrows(OptionsList.SelectedIndex, OptionsList.Items.Count); }
/// <summary> /// Imports a comma separated file in to the app. /// </summary> /// <param name="fileName">The file name to import.</param> /// <param name="entityItem">The item to import.</param> /// <param name="installedLanguages">The installed languages.</param> internal void Import(string fileName, EntityItem entityItem, Dictionary <int, string> installedLanguages) { var file = File.ReadAllLines(fileName); file = file.Skip(1).ToArray(); var fileEntities = file.GroupBy(f => f.Substring(0, f.IndexOf(','))); foreach (var fileEntity in fileEntities) { Dictionary <string, EntityItem> attributes = new Dictionary <string, EntityItem>(); if (entityItem.LogicalName.ToLower() == fileEntity.Key.ToLower()) { var fileAttributes = fileEntity.GroupBy(f => f.Substring(f.IndexOf(',') + 1, f.IndexOf(',', f.IndexOf(',') + 1) - f.IndexOf(',') - 1)); foreach (var fileAttribute in fileAttributes) { var attributeItem = entityItem.Children.Where(c => c.LogicalName.ToLower() == fileAttribute.Key.ToLower()).FirstOrDefault(); if (attributeItem != null) { if (!attributeItem.Loaded) { this.GetOptions(attributeItem); } var children = attributeItem.Children.ToArray(); attributeItem.Children.Clear(); foreach (var line in fileAttribute) { var columns = line.Split(','); int maxColumns = (installedLanguages.Count() * 2) + 4; if (columns.Count() > maxColumns) { List <int> columnsToDelete = new List <int>(); for (int i = 0; i < columns.Length - 1; i++) { if (columns[i].StartsWith("\"") && columns[i + 1].EndsWith("\"")) { columns[i] = columns[i] + "," + columns[i + 1]; columns[i] = columns[i].Trim('"'); columnsToDelete.Add(i + 1); } } if (columnsToDelete.Count > 0) { var cols = new List <string>(columns); for (int i = columnsToDelete.Count(); i > 0; i--) { cols.RemoveAt(columnsToDelete[i - 1]); } columns = cols.ToArray(); } if (columns.Length != (installedLanguages.Count() * 2) + 4) { MessageBox.Show("Invalid number of columns in the record."); } } Microsoft.Xrm.Sdk.LocalizedLabel[] labels = new Microsoft.Xrm.Sdk.LocalizedLabel[installedLanguages.Count()]; Microsoft.Xrm.Sdk.LocalizedLabel[] descriptions = new Microsoft.Xrm.Sdk.LocalizedLabel[installedLanguages.Count()]; for (int i = 0; i < installedLanguages.Count; i++) { labels[i] = new Microsoft.Xrm.Sdk.LocalizedLabel(columns[i + 4], installedLanguages.Keys.OrderBy(l => l).ToArray()[i]); descriptions[i] = new Microsoft.Xrm.Sdk.LocalizedLabel(columns[i + 4 + installedLanguages.Count], installedLanguages.Keys.OrderBy(l => l).ToArray()[i]); } Microsoft.Xrm.Sdk.Label label = new Microsoft.Xrm.Sdk.Label(); label.LocalizedLabels.AddRange(labels); label.UserLocalizedLabel = label.LocalizedLabels.Where(l => l.LanguageCode == installedLanguages.Keys.First()).First(); Microsoft.Xrm.Sdk.Label description = new Microsoft.Xrm.Sdk.Label(); description.LocalizedLabels.AddRange(descriptions); description.UserLocalizedLabel = description.LocalizedLabels.Where(l => l.LanguageCode == installedLanguages.Keys.First()).First(); int value = 0; if (int.TryParse(columns[3], out value) && value != 2147483647) { EntityItem child = new EntityItem(value, label, description, attributeItem); var found = children.Where(c => c.Equals(child)).FirstOrDefault(); child.Changed = found == null; attributeItem.GlobalName = columns[2]; attributeItem.Children.Add(child); attributeItem.Loaded = true; child.Parent.Changed = true; } else { MessageBox.Show($"Invalid value - {columns[3]}"); } } } else { MessageBox.Show($"Cannot find the attribute - {fileAttribute.Key} on entity {fileEntity.Key}"); } } } else { MessageBox.Show($"You can only import to the currently selected entity\r\nImport entity = {fileEntity.Key}"); } } }
/// <summary> /// Processes the fee type records to update the option set /// </summary> /// <param name="entities">The entity collection.</param> public void PublishOptions(IEnumerable <EntityItem> entities) { this.WorkAsync(new WorkAsyncInfo { Message = "Publishing please wait...", Work = (w, e) => { string message = string.Empty; string caption = "Success"; foreach (var entity in entities) { foreach (var attribute in entity.Children.Where(c => c.Changed)) { if (attribute.Children.Any(i => i.Label == null || string.IsNullOrWhiteSpace(i.Label.UserLocalizedLabel.Label))) { message = "\r\nAll items require a label"; caption = " Error"; break; } } } if (string.IsNullOrWhiteSpace(message)) { XmlDocument publishXml = new XmlDocument(); publishXml.LoadXml("<importexportxml></importexportxml>"); ExecuteMultipleRequest batchRequest = new ExecuteMultipleRequest { Settings = new ExecuteMultipleSettings { ContinueOnError = true, ReturnResponses = true }, Requests = new OrganizationRequestCollection() }; foreach (var entity in entities) { foreach (var attribute in entity.Children.Where(c => c.Changed)) { OptionMetadata[] optionList; if (attribute.Global) { AddNode(publishXml, attribute.GlobalName, true); RetrieveOptionSetRequest request = new RetrieveOptionSetRequest { Name = attribute.GlobalName, RetrieveAsIfPublished = true }; RetrieveOptionSetResponse response = (RetrieveOptionSetResponse)this.Service.Execute(request); OptionSetMetadata optionSet = (OptionSetMetadata)response.OptionSetMetadata; optionList = optionSet.Options.ToArray(); } else { AddNode(publishXml, entity.LogicalName, false); var attributeRequest = new RetrieveAttributeRequest { EntityLogicalName = entity.LogicalName, LogicalName = attribute.LogicalName, RetrieveAsIfPublished = true }; var attributeResponse = (RetrieveAttributeResponse)this.Service.Execute(attributeRequest); var attributeMetadata = (EnumAttributeMetadata)attributeResponse.AttributeMetadata; optionList = attributeMetadata.OptionSet.Options.ToArray(); } var currentValues = optionList.Select(o => o.Value.Value); var removedOptions = currentValues.Where(o => !attribute.Children.Any(i => i.Value == o)); foreach (var removedOption in removedOptions) { EntityItem deletion = new EntityItem(string.Empty, attribute.LogicalName) { GlobalName = attribute.GlobalName, Value = removedOption, Parent = entity }; batchRequest.Requests.Add(GetRequest(deletion, Operation.Delete)); } foreach (EntityItem option in attribute.Children.Where(c => c.Changed)) { OptionMetadata currentOption = optionList.Where(o => o.Value.Value == option.Value).FirstOrDefault(); if (currentOption != null) { batchRequest.Requests.Add(GetRequest(option, Operation.Update)); } else { batchRequest.Requests.Add(GetRequest(option, Operation.Insert)); } } } } PublishXmlRequest publish = new PublishXmlRequest { ParameterXml = publishXml.InnerXml }; batchRequest.Requests.Add(publish); ExecuteMultipleResponse batchResults = (ExecuteMultipleResponse)this.Service.Execute(batchRequest); foreach (var responseItem in batchResults.Responses) { if (responseItem.Fault != null) { message += "\r\n" + batchRequest.Requests[responseItem.RequestIndex].RequestName + ": " + responseItem.Fault.Message; caption = " Error"; } } if (string.IsNullOrWhiteSpace(message)) { message = "Publish Successful"; } else { message = message.Substring(2); } } e.Result = message + caption; }, PostWorkCallBack = e => { string result = e.Result.ToString(); string message = result.Substring(0, result.Length - 7); string caption = result.Substring(result.Length - 7).Trim(); MessageBox.Show(message, caption); }, AsyncArgument = null, IsCancelable = true, MessageWidth = 340, MessageHeight = 150 }); }