/// <summary>
        /// Синхронизация вхождений блоков с их определением
        /// via http://sites.google.com/site/bushmansnetlaboratory/moi-zametki/attsynch
        /// </summary>
        /// <param name="btr">Запись таблицы блоков, принятая за определение блока</param>
        /// <param name="directOnly">Следует ли искать только на верхнем уровне, или же нужно
        /// анализировать и вложенные вхождения, т.е. следует ли рекурсивно обрабатывать блок в блоке:
        /// true - только верхний; false - рекурсивно проверять вложенные блоки.</param>
        /// <param name="removeSuperfluous">
        /// Следует ли во вхождениях блока удалять лишние атрибуты (те, которых нет в определении блока).</param>
        /// <param name="setAttDefValues">
        /// Следует ли всем атрибутам, во вхождениях блока, назначить текущим значением значение по умолчанию.</param>
        public static void AttSync(this BlockTableRecord btr, bool directOnly, bool removeSuperfluous, bool setAttDefValues)
        {
            Database db = btr.Database;

//			using (Bushman.AutoCAD.DatabaseServices.WorkingDatabaseSwitcher wdb = new Bushman.AutoCAD.DatabaseServices.WorkingDatabaseSwitcher(db)) {
            using (Transaction t = db.TransactionManager.StartTransaction()) {
                BlockTable bt = (BlockTable)t.GetObject(db.BlockTableId, OpenMode.ForRead);

                //Получаем все определения атрибутов из определения блока
                IEnumerable <AttributeDefinition> attdefs = btr.Cast <ObjectId>()
                                                            .Where(n => n.ObjectClass.Name == "AcDbAttributeDefinition")
                                                            .Select(n => (AttributeDefinition)t.GetObject(n, OpenMode.ForRead))
                                                            .Where(n => !n.Constant);//Исключаем константные атрибуты, т.к. для них AttributeReference не создаются.

                //В цикле перебираем все вхождения искомого определения блока
                foreach (ObjectId brId in btr.GetBlockReferenceIds(directOnly, false))
                {
                    BlockReference br = (BlockReference)t.GetObject(brId, OpenMode.ForWrite);

                    //Проверяем имена на соответствие. В том случае, если вхождение блока "A" вложено в определение блока "B",
                    //то вхождения блока "B" тоже попадут в выборку. Нам нужно их исключить из набора обрабатываемых объектов
                    //- именно поэтому проверяем имена.
                    if (br.Name != btr.Name)
                    {
                        continue;
                    }

                    //Получаем все атрибуты вхождения блока
                    IEnumerable <AttributeReference> attrefs = br.AttributeCollection.Cast <ObjectId>()
                                                               .Select(n => (AttributeReference)t.GetObject(n, OpenMode.ForWrite));

                    //Тэги существующих определений атрибутов
                    IEnumerable <string> dtags = attdefs.Select(n => n.Tag);
                    //Тэги существующих атрибутов во вхождении
                    IEnumerable <string> rtags = attrefs.Select(n => n.Tag);

                    //Если требуется - удаляем те атрибуты, для которых нет определения
                    //в составе определения блока
                    if (removeSuperfluous)
                    {
                        foreach (AttributeReference attref in attrefs.Where(n => rtags
                                                                            .Except(dtags).Contains(n.Tag)))
                        {
                            attref.Erase(true);
                        }
                    }

                    //Свойства существующих атрибутов синхронизируем со свойствами их определений
                    foreach (AttributeReference attref in attrefs.Where(n => dtags
                                                                        .Join(rtags, a => a, b => b, (a, b) => a).Contains(n.Tag)))
                    {
                        AttributeDefinition ad = attdefs.First(n => n.Tag == attref.Tag);

                        //Метод SetAttributeFromBlock, используемый нами далее в коде, сбрасывает
                        //текущее значение многострочного атрибута. Поэтому запоминаем это значение,
                        //чтобы восстановить его сразу после вызова SetAttributeFromBlock.
                        string value = attref.TextString;
                        attref.SetAttributeFromBlock(ad, br.BlockTransform);
                        //Восстанавливаем значение атрибута
                        attref.TextString = value;

                        if (attref.IsMTextAttribute)
                        {
                        }

                        //Если требуется - устанавливаем для атрибута значение по умолчанию
                        if (setAttDefValues)
                        {
                            attref.TextString = ad.TextString;
                        }
                        attref.AdjustAlignment(db);
                    }

                    //Если во вхождении блока отсутствуют нужные атрибуты - создаём их
                    IEnumerable <AttributeDefinition> attdefsNew = attdefs.Where(n => dtags
                                                                                 .Except(rtags).Contains(n.Tag));

                    foreach (AttributeDefinition ad in attdefsNew)
                    {
                        AttributeReference attref = new AttributeReference();
                        attref.SetAttributeFromBlock(ad, br.BlockTransform);
                        attref.AdjustAlignment(db);
                        br.AttributeCollection.AppendAttribute(attref);
                        t.AddNewlyCreatedDBObject(attref, true);
                    }
                }
                btr.UpdateAnonymousBlocks();
                t.Commit();
            }
            //Если это динамический блок
            if (btr.IsDynamicBlock)
            {
                using (Transaction t = db.TransactionManager.StartTransaction()) {
                    foreach (ObjectId id in btr.GetAnonymousBlockIds())
                    {
                        BlockTableRecord _btr = (BlockTableRecord)t.GetObject(id, OpenMode.ForWrite);

                        //Получаем все определения атрибутов из оригинального определения блока
                        IEnumerable <AttributeDefinition> attdefs = btr.Cast <ObjectId>()
                                                                    .Where(n => n.ObjectClass.Name == "AcDbAttributeDefinition")
                                                                    .Select(n => (AttributeDefinition)t.GetObject(n, OpenMode.ForRead));

                        //Получаем все определения атрибутов из определения анонимного блока
                        IEnumerable <AttributeDefinition> attdefs2 = _btr.Cast <ObjectId>()
                                                                     .Where(n => n.ObjectClass.Name == "AcDbAttributeDefinition")
                                                                     .Select(n => (AttributeDefinition)t.GetObject(n, OpenMode.ForWrite));
                        //Определения атрибутов анонимных блоков следует синхронизировать
                        //с определениями атрибутов основного блока
                        //Тэги существующих определений атрибутов
                        IEnumerable <string> dtags  = attdefs.Select(n => n.Tag);
                        IEnumerable <string> dtags2 = attdefs2.Select(n => n.Tag);
                        //1. Удаляем лишние
                        foreach (AttributeDefinition attdef in attdefs2.Where(n => !dtags.Contains(n.Tag)))
                        {
                            attdef.Erase(true);
                        }
                        //2. Синхронизируем существующие
                        foreach (AttributeDefinition attdef in attdefs.Where(n => dtags
                                                                             .Join(dtags2, a => a, b => b, (a, b) => a).Contains(n.Tag)))
                        {
                            AttributeDefinition ad = attdefs2.First(n => n.Tag == attdef.Tag);
                            ad.Position = attdef.Position;
                            #if ACAD2009
                            ad.TextStyle = attdef.TextStyle;
                            #else
                            ad.TextStyleId = attdef.TextStyleId;
                            #endif
                            //Если требуется - устанавливаем для атрибута значение по умолчанию
                            if (setAttDefValues)
                            {
                                ad.TextString = attdef.TextString;
                            }
                            ad.Tag                 = attdef.Tag;
                            ad.Prompt              = attdef.Prompt;
                            ad.LayerId             = attdef.LayerId;
                            ad.Rotation            = attdef.Rotation;
                            ad.LinetypeId          = attdef.LinetypeId;
                            ad.LineWeight          = attdef.LineWeight;
                            ad.LinetypeScale       = attdef.LinetypeScale;
                            ad.Annotative          = attdef.Annotative;
                            ad.Color               = attdef.Color;
                            ad.Height              = attdef.Height;
                            ad.HorizontalMode      = attdef.HorizontalMode;
                            ad.Invisible           = attdef.Invisible;
                            ad.IsMirroredInX       = attdef.IsMirroredInX;
                            ad.IsMirroredInY       = attdef.IsMirroredInY;
                            ad.Justify             = attdef.Justify;
                            ad.LockPositionInBlock = attdef.LockPositionInBlock;
                            ad.MaterialId          = attdef.MaterialId;
                            ad.Oblique             = attdef.Oblique;
                            ad.Thickness           = attdef.Thickness;
                            ad.Transparency        = attdef.Transparency;
                            ad.VerticalMode        = attdef.VerticalMode;
                            ad.Visible             = attdef.Visible;
                            ad.WidthFactor         = attdef.WidthFactor;
                            ad.CastShadows         = attdef.CastShadows;
                            ad.Constant            = attdef.Constant;
                            ad.FieldLength         = attdef.FieldLength;
                            ad.ForceAnnoAllVisible = attdef.ForceAnnoAllVisible;
                            ad.Preset              = attdef.Preset;
                            ad.Prompt              = attdef.Prompt;
                            ad.Verifiable          = attdef.Verifiable;
                            ad.AdjustAlignment(db);
                        }
                        //3. Добавляем недостающие
                        foreach (AttributeDefinition attdef in attdefs.Where(n => !dtags2.Contains(n.Tag)))
                        {
                            AttributeDefinition ad = new AttributeDefinition();
                            ad.SetDatabaseDefaults();
                            ad.Position = attdef.Position;
                            #if ACAD2009
                            ad.TextStyle = attdef.TextStyle;
                            #else
                            ad.TextStyleId = attdef.TextStyleId;
                            #endif
                            ad.TextString          = attdef.TextString;
                            ad.Tag                 = attdef.Tag;
                            ad.Prompt              = attdef.Prompt;
                            ad.LayerId             = attdef.LayerId;
                            ad.Rotation            = attdef.Rotation;
                            ad.LinetypeId          = attdef.LinetypeId;
                            ad.LineWeight          = attdef.LineWeight;
                            ad.LinetypeScale       = attdef.LinetypeScale;
                            ad.Annotative          = attdef.Annotative;
                            ad.Color               = attdef.Color;
                            ad.Height              = attdef.Height;
                            ad.HorizontalMode      = attdef.HorizontalMode;
                            ad.Invisible           = attdef.Invisible;
                            ad.IsMirroredInX       = attdef.IsMirroredInX;
                            ad.IsMirroredInY       = attdef.IsMirroredInY;
                            ad.Justify             = attdef.Justify;
                            ad.LockPositionInBlock = attdef.LockPositionInBlock;
                            ad.MaterialId          = attdef.MaterialId;
                            ad.Oblique             = attdef.Oblique;
                            ad.Thickness           = attdef.Thickness;
                            ad.Transparency        = attdef.Transparency;
                            ad.VerticalMode        = attdef.VerticalMode;
                            ad.Visible             = attdef.Visible;
                            ad.WidthFactor         = attdef.WidthFactor;
                            ad.CastShadows         = attdef.CastShadows;
                            ad.Constant            = attdef.Constant;
                            ad.FieldLength         = attdef.FieldLength;
                            ad.ForceAnnoAllVisible = attdef.ForceAnnoAllVisible;
                            ad.Preset              = attdef.Preset;
                            ad.Prompt              = attdef.Prompt;
                            ad.Verifiable          = attdef.Verifiable;
                            _btr.AppendEntity(ad);
                            t.AddNewlyCreatedDBObject(ad, true);
                            ad.AdjustAlignment(db);
                        }
                        //Синхронизируем все вхождения данного анонимного определения блока
                        _btr.AttSync(directOnly, removeSuperfluous, setAttDefValues);
                    }
                    //Обновляем геометрию определений анонимных блоков, полученных на основе
                    //этого динамического блока
                    btr.UpdateAnonymousBlocks();
                    t.Commit();
                }
            }
//			}
        }
 /// <summary>
 /// Синхронизация вхождений блоков с их определением
 /// via http://sites.google.com/site/bushmansnetlaboratory/moi-zametki/attsynch
 /// Вхождения обрабатываются рекурсивно, в них удаляются лишние атрибуты,
 /// значения по умолчанию не назначаются
 /// </summary>
 /// <param name="btr">Запись таблицы блоков, принятая за определение блока</param>
 public static void AttSync(this BlockTableRecord btr)
 {
     btr.AttSync(false, true, false);
 }