Запуск команды ССЫЛРЕД (REFEDIT) с выбранным примитивом средствами .NET
Действительно интересная проблема возникла в ходе внутренней дискуссии на этой неделе: кому-то понадобилось запустить команду REFEDIT для выбранной внешней ссылки с предварительно выбранным примитивом. И этот примитив должен быть частью выбранной внешней ссылки.
Это оказалось весьма непростым делом, но мы нашли способ, решающий её в несколько строк кода. Хитростью было найти правильный примитив в наборе и соответствующий ему примитив во внешней ссылке.
Вот подход, который я в конечном итоге использовал:
- Попросить пользователя выбрать вложенный примитив
- Получить первый примитив, содержащийся в списке контейнеров внешней ссылки
- Нам понадобится примитив верхнего уровня, который может быть выбран во внешней ссылке: это может быть сам выбранный объект
- Добавляем обработчик, соответствующий событию “check out” менеджера длинных транзакций
- Этот обработчик будет проверять «отображение глубокого клонирования» для данной длинной транзакции
- Если он найдёт исходный примитив (примитив, определённый на шаге 2) тогда получим целевой примитив и добавим его в набор предварительного выбора (pickfirst)
- Вызываем команду ССЫЛРЕД (_REFEDIT), передавая ей точку указанную пользователем при выборе примитива
- Удаляем обработчик события
Так как нам нужно будет модифицировать набор предварительного выбора (pickfirst) нам понадобится установить команде флаг “redraw”.
Вот C#-код определяющий команду RS (RefeditSelect):
- using Autodesk.AutoCAD.ApplicationServices;
- using Autodesk.AutoCAD.DatabaseServices;
- using Autodesk.AutoCAD.EditorInput;
- using Autodesk.AutoCAD.Runtime;
- namespace RefeditSelected
- {
- public static class Extensions
- {
- ///<summary>
- /// Получаем вложенный примитив из первой внешней ссылки в выборе.
- ///</summary>
- ///<returns>ObjectId объекта верхнего уровня из внешней ссылки.</returns>
- public static ObjectId GetFirstXrefChild(this PromptNestedEntityResult res)
- {
- var retId = ObjectId.Null;
- var selId = res.ObjectId;
- var conts = res.GetContainers();
- var db = selId.Database;
- // Используем транзакцию типа «open-close» в вспомогательной функции
- using (var tr = db.TransactionManager.StartOpenCloseTransaction())
- {
- // Проходим от конца к началу в контейнере и ищем внешнюю ссылку
- for (int i = conts.Length-1; i >= 0; i--)
- {
- var br = tr.GetObject(conts[i], OpenMode.ForRead) as BlockReference;
- if (br != null)
- {
- var btr =
- (BlockTableRecord)tr.GetObject(
- br.BlockTableRecord, OpenMode.ForRead
- );
- // Если это внешняя ссылка мы вернём следующий контейнер
- // или выбранный примитив, если это самый внутренний контейнер
- if (btr.IsFromExternalReference)
- {
- retId = i > 0 ? conts[i-1] : selId;
- break;
- }
- }
- }
- tr.Commit();
- }
- return retId;
- }
- }
- public class Commands
- {
- [CommandMethod("RS", CommandFlags.Redraw)]
- public void RefeditSelected()
- {
- var doc = Application.DocumentManager.MdiActiveDocument;
- if (doc == null) return;
- var db = doc.Database;
- var ed = doc.Editor;
- // Выбираем примитив внутри внешней ссылки
- var pner = ed.GetNestedEntity("\nВыберите примитив во внешней ссылке ");
- if (pner.Status != PromptStatus.OK)
- return;
- // Получаем ID примитива, который мы хотим выбрать во внешней ссылке
- // (это первый примитив во внешней ссылке)
- var selId = pner.GetFirstXrefChild();
- // Обрабатываем только если что-то есть подходящее
- if (selId != ObjectId.Null)
- {
- // Определяем наш обработчик события
- LongTransactionEventHandler func = (s, e) =>
- {
- // Получаем «отображение глубокого клонирования» для длинной транзакции
- var map = e.Transaction.ActiveIdMap;
- // Если есть отображение для выбранного нами объекта...
- if (map.Contains(selId))
- {
- // ... добавляем его к набору предварительного выбора
- ed.SetImpliedSelection(new ObjectId[] { map[selId].Value });
- ed.WriteMessage("\nSelected one entity.");
- }
- };
- // Добавляем наш обработчик, вызываем _REFEDIT и удаляем его
- Application.LongTransactionManager.CheckedOut += func;
- ed.Command("_.-REFEDIT", pner.PickedPoint, "_O", "_A", "_N");
- Application.LongTransactionManager.CheckedOut -= func;
- }
- }
- }
- }
Вот что происходит, когда мы запускаем команду RS и выбираем объекты, принадлежащие внешней ссылке:
Важно отметить, что не все примитивы, выбранные выше на одном уровне в иерархии чертежа: когда мы выбираем дверь, к примеру, процесс выбора вложенного примитива на самом деле находит полилинию, входящую в наш дверной блок. Мы должны найти объект в иерархии, который соответствует примитиву верхнего уровня во внешней ссылке - в данном вставку блока двери - и выбрать его: если примитив не существует в внешней ссылке, то мы получим ошибку eInvalidInput, когда мы вызовем Editor.SetImpliedSelection().
Обсуждение: http://adn-cis.org/forum/index.php?topic=2986
Опубликовано 06.09.2015Отредактировано 06.09.2015 в 11:38:05