private void ButtonDeselectAll_Click(object sender, RoutedEventArgs e)
        {
            if (!Fields.Any() && !Relations1N.Any() && !RelationsN1.Any() && !RelationsNN.Any())
            {
                return;
            }

            FieldsSelectAll      = false;
            Relations1NSelectAll = false;
            RelationsN1SelectAll = false;
            RelationsNNSelectAll = false;
        }
        private void SaveFilter()
        {
            if (EntityDataFilter == null)
            {
                return;
            }

            //EntityDataFilter.EnglishLabelField = TextBoxEnglishLabelField.Text;

            EntityDataFilter.Attributes       = Fields.Where(field => field.IsSelected).Select(field => field.Name).ToArray();
            EntityDataFilter.AttributeRenames = Fields.Where(field => !string.IsNullOrWhiteSpace(field.Rename))
                                                .ToDictionary(field => field.Name, field => field.Rename);
            EntityDataFilter.AttributeLanguages = Fields.Where(field => !string.IsNullOrWhiteSpace(field.Language))
                                                  .ToDictionary(field => field.Name, field => field.Language);
            EntityDataFilter.ReadOnly  = Fields.Where(field => field.IsReadOnly).Select(field => field.Name).ToArray();
            EntityDataFilter.ClearFlag = Fields.Where(field => field.IsClearFlag).Select(field => field.Name).ToArray();

            EntityDataFilter.OneToN =
                Relations1N.Where(relation => relation.IsSelected).Select(relation => relation.Name).ToArray();
            EntityDataFilter.OneToNRenames = Relations1N.Where(relation => !string.IsNullOrWhiteSpace(relation.Rename))
                                             .ToDictionary(relation => relation.Name, relation => relation.Rename);
            EntityDataFilter.OneToNReadOnly = Relations1N.ToDictionary(relation => relation.Name, relation => relation.IsReadOnly);

            EntityDataFilter.NToOne =
                RelationsN1.Where(relation => relation.IsSelected).Select(relation => relation.Name).ToArray();
            EntityDataFilter.NToOneRenames = RelationsN1.Where(relation => !string.IsNullOrWhiteSpace(relation.Rename))
                                             .ToDictionary(relation => relation.Name, relation => relation.Rename);
            EntityDataFilter.NToOneFlatten  = RelationsN1.ToDictionary(relation => relation.Name, relation => relation.IsFlatten);
            EntityDataFilter.NToOneReadOnly = RelationsN1.ToDictionary(relation => relation.Name, relation => relation.IsReadOnly);

            EntityDataFilter.NToN =
                RelationsNN.Where(relation => relation.IsSelected).Select(relation => relation.Name).ToArray();
            EntityDataFilter.NToNRenames = RelationsNN.Where(relation => !string.IsNullOrWhiteSpace(relation.Rename))
                                           .ToDictionary(relation => relation.Name, relation => relation.Rename);
            EntityDataFilter.NToNReadOnly = RelationsNN.ToDictionary(relation => relation.Name, relation => relation.IsReadOnly);

            var toSelect = Relations1N.Where(relation => relation.IsSelected).Select(relation => relation.ToEntity)
                           .Union(RelationsN1.Where(relation => relation.IsSelected).Select(relation => relation.ToEntity)
                                  .Union(RelationsNN.Where(relation => relation.IsSelected)
                                         .SelectMany(relation => new[] { relation.ToEntity, relation.IntersectEntity })))
                           .Distinct();

            foreach (var entityRow in Entities.Where(entity => toSelect.Contains(entity.Name) && !entity.IsSelected))
            {
                entityRow.IsSelected = true;
            }
        }
        private void ButtonClearNames_Click(object sender, RoutedEventArgs e)
        {
            foreach (var field in Fields.Where(field => !string.IsNullOrEmpty(field.Rename)))
            {
                field.Rename = "";
            }

            foreach (var relation in Relations1N.Where(relation => !string.IsNullOrEmpty(relation.Rename)))
            {
                relation.Rename = "";
            }

            foreach (var relation in RelationsN1.Where(relation => !string.IsNullOrEmpty(relation.Rename)))
            {
                relation.Rename = "";
            }

            foreach (var relation in RelationsNN.Where(relation => !string.IsNullOrEmpty(relation.Rename)))
            {
                relation.Rename = "";
            }
        }
        private void GenerateLists()
        {
            if (AttributeMetadataCache[LogicalName] == null)
            {
                throw new Exception("Failed to load metadata related to this entity.");
            }

            // choose non-primary attributes, and ones that don't represent others (like names of OptionSetValues)
            // sort by IsSelected, and then by name -- bubbles the selected to the top
            var attributes = from attributeQ in AttributeMetadataCache[LogicalName].Attributes
                             where (!attributeQ.IsPrimaryId.HasValue || !attributeQ.IsPrimaryId.Value) &&
                             string.IsNullOrEmpty(attributeQ.AttributeOf)
                             orderby EntityDataFilter.Attributes == null ||
                             EntityDataFilter.Attributes.Contains(attributeQ.LogicalName) descending,
                attributeQ.LogicalName
            select attributeQ;

            // if no filter, select all
            FieldsSelectAll = EntityDataFilter.Attributes != null &&
                              EntityDataFilter.Attributes.Length == attributes.Count();

            ReadOnlySelectAll = EntityDataFilter.ReadOnly != null &&
                                EntityDataFilter.ReadOnly.Length == attributes.Count();

            ClearFlagSelectAll = EntityDataFilter.ClearFlag != null &&
                                 EntityDataFilter.ClearFlag.Length == attributes.Count();

            foreach (var attribute in attributes)
            {
                var attributeAsync = attribute;

                Dispatcher.Invoke(() =>
                {
                    Fields.Add(new FieldGridRow
                    {
                        IsSelected =
                            EntityDataFilter.Attributes?.Contains(attributeAsync.LogicalName) == true,
                        Name        = attributeAsync.LogicalName,
                        DisplayName =
                            attributeAsync.DisplayName?.UserLocalizedLabel == null || !Settings.UseDisplayNames
                                                                                             ? Naming.GetProperVariableName(attributeAsync, Settings.TitleCaseLogicalNames)
                                                                                             : Naming.Clean(attributeAsync.DisplayName.UserLocalizedLabel.Label),
                        Rename =
                            EntityDataFilter.AttributeRenames?.FirstNotNullOrEmpty(attributeAsync.LogicalName),
                        Language =
                            EntityDataFilter.AttributeLanguages?.FirstNotNullOrEmpty(attributeAsync.LogicalName),
                        IsReadOnly = EntityDataFilter.ReadOnly?.Contains(attributeAsync.LogicalName) == true ||
                                     (attributeAsync.IsValidForCreate != true &&
                                      attributeAsync.IsValidForUpdate != true),
                        IsReadOnlyEnabled = attributeAsync.IsValidForCreate == true ||
                                            attributeAsync.IsValidForUpdate == true,
                        IsClearFlag =
                            EntityDataFilter.ClearFlag?.Contains(attributeAsync.LogicalName) == true
                    });
                });
            }

            var relations1N = from relation1nQ in AttributeMetadataCache[LogicalName].OneToManyRelationships
                              orderby EntityDataFilter.OneToN == null ||
                              EntityDataFilter.OneToN.Contains(relation1nQ.SchemaName) descending,
                relation1nQ.ReferencingEntity, relation1nQ.ReferencingAttribute
            select relation1nQ;

            // if no filter, select all
            Relations1NSelectAll = EntityDataFilter.OneToN != null &&
                                   EntityDataFilter.OneToN.Length == relations1N.Count();

            foreach (var relation1n in relations1N)
            {
                var relation1nAsync = relation1n;

                Dispatcher.Invoke(() =>
                {
                    var row = new Relations1NGridRow
                    {
                        IsSelected = EntityDataFilter.OneToN == null ||
                                     EntityDataFilter.OneToN.Contains(relation1nAsync.SchemaName),
                        Name     = relation1nAsync.SchemaName,
                        ToEntity = relation1nAsync.ReferencingEntity ?? "",
                        ToField  = relation1nAsync.ReferencingAttribute ?? "",
                        Rename   =
                            EntityDataFilter.OneToNRenames?.FirstNotNullOrEmpty(relation1nAsync.SchemaName),
                        IsReadOnlyEnabled = true,
                        IsReadOnly        = EntityDataFilter.OneToNReadOnly != null &&
                                            EntityDataFilter.OneToNReadOnly.ContainsKey(
                            relation1nAsync.SchemaName) &&
                                            EntityDataFilter.OneToNReadOnly[relation1nAsync.SchemaName]
                    };

                    Relations1N.Add(row);
                });
            }

            var relationsN1 = from relationN1Q in AttributeMetadataCache[LogicalName].ManyToOneRelationships
                              orderby EntityDataFilter.NToOne == null ||
                              EntityDataFilter.NToOne.Contains(relationN1Q.SchemaName) descending,
                relationN1Q.ReferencedEntity, relationN1Q.ReferencingAttribute
            select relationN1Q;

            // if no filter, select all
            RelationsN1SelectAll = EntityDataFilter.NToOne != null &&
                                   EntityDataFilter.NToOne.Length == relationsN1.Count();

            foreach (var relationN1 in relationsN1)
            {
                var relationN1Async = relationN1;

                Dispatcher.Invoke(() =>
                {
                    var row = new RelationsN1GridRow
                    {
                        IsSelected = EntityDataFilter.NToOne == null ||
                                     EntityDataFilter.NToOne.Contains(relationN1Async.SchemaName),
                        Name      = relationN1Async.SchemaName,
                        ToEntity  = relationN1Async.ReferencedEntity ?? "",
                        FromField = relationN1Async.ReferencingAttribute ?? "",
                        Rename    = EntityDataFilter.NToOneRenames?
                                    .FirstNotNullOrEmpty(relationN1Async.SchemaName),
                        IsFlatten = EntityDataFilter.NToOneFlatten != null &&
                                    EntityDataFilter.NToOneFlatten.ContainsKey(
                            relationN1Async.SchemaName) &&
                                    EntityDataFilter.NToOneFlatten[relationN1Async.SchemaName],
                        IsReadOnlyEnabled = true,
                        IsReadOnly        = EntityDataFilter.NToOneReadOnly != null &&
                                            EntityDataFilter.NToOneReadOnly.ContainsKey(
                            relationN1Async.SchemaName) &&
                                            EntityDataFilter.NToOneReadOnly[relationN1Async.SchemaName]
                    };

                    RelationsN1.Add(row);
                });
            }

            var relationsNN = from relationNNQ in AttributeMetadataCache[LogicalName].ManyToManyRelationships
                              orderby EntityDataFilter.NToN == null ||
                              EntityDataFilter.NToN.Contains(relationNNQ.SchemaName) descending,
            (relationNNQ.Entity1LogicalName == LogicalName)
                                                          ? relationNNQ.Entity2LogicalName
                                                          : (relationNNQ.Entity1LogicalName ?? ""),
            relationNNQ.IntersectEntityName
            select relationNNQ;

            // if no filter, select all
            RelationsNNSelectAll = EntityDataFilter.NToN != null &&
                                   EntityDataFilter.NToN.Length == relationsNN.Count();

            foreach (var relationNN in relationsNN)
            {
                var relationNNAsync = relationNN;

                Dispatcher.Invoke(() =>
                {
                    var row = new RelationsNNGridRow
                    {
                        IsSelected = EntityDataFilter.NToN == null ||
                                     EntityDataFilter.NToN.Contains(relationNNAsync.SchemaName),
                        Name     = relationNNAsync.SchemaName,
                        ToEntity = relationNNAsync.Entity1LogicalName == LogicalName
                                                                                               ? relationNNAsync.Entity2LogicalName
                                                                                               : (relationNNAsync.Entity1LogicalName ?? ""),
                        IntersectEntity   = relationNNAsync.IntersectEntityName ?? "",
                        Rename            = EntityDataFilter.NToNRenames?.FirstNotNullOrEmpty(relationNNAsync.SchemaName),
                        IsReadOnlyEnabled = true,
                        IsReadOnly        = EntityDataFilter.NToNReadOnly != null &&
                                            EntityDataFilter.NToNReadOnly.ContainsKey(
                            relationNNAsync.SchemaName) &&
                                            EntityDataFilter.NToNReadOnly[relationNNAsync.SchemaName]
                    };

                    RelationsNN.Add(row);
                });
            }
        }