И с транзакцие (в разных ее вариациях) и без нее работал, все едино.
Да и не сошелся свет клином именно на этом методе, я его только для примера привел, то же самое поведение будет если я вставлю прогресс бар внутрь любого из методов использующихся в DrawBlocks или в самом DrawBlocks
Вроде как, правильнее делать DoEvents после того, как прогрессметер "пнули", а не до этого, как в коде из #16.
А, Привалов Дмитрий уже поправил это в коде из #17.
Вот результат
Я ранее расписывал общую структуру программы
Тут создаем и блокируем документ.
Сейчас тут AppContextOpenDocument(), ранее было создание базы и ReadDwg(), но теперешний вариант стабильнее и нужно что бы документ после завершения работы оставался открытым
internal static void CreateDWG(string outPutDWG, List<ExcelRow> excelRows)
{
App.DocumentCollection acDocMgr = App.Application.DocumentManager;
//Создается чертеж по шаблону
acDocMgr.AppContextOpenDocument(outPutDWG);
App.Document docA = App.Application.DocumentManager.MdiActiveDocument;
using (App.DocumentLock docLock = docA.LockDocument())
{
using (WorkingDatabaseSwitcher switcher = new WorkingDatabaseSwitcher(docA.Database))
{
//Проверяем регистрацию приложения для группировки
XDataExtension.SetXDataApp(docA.Database);
//Рисуем блоки
DrawBlocks(docA, excelRows);
}
}
docA.Database.SaveAs(outPutDWG, true, Db.DwgVersion.Current, null);
}
Тут собственно создаются, изменяются и растаскиваются по местам блоки
private static void DrawBlocks(App.Document doc, List<ExcelRow> excelRows)
{
Db.Database newDb = doc.Database;
List<Db.ObjectId> eraseIds = new List<Db.ObjectId>();
//Просто очищаем пространство модели
var msId = Db.SymbolUtilityServices.GetBlockModelSpaceId(newDb);
using (var ms = msId.Open(Db.OpenMode.ForRead) as Db.BlockTableRecord)
foreach (Db.ObjectId id in ms)
if (id.ObjectClass.IsDerivedFrom(Rtm.RXObject.GetClass(typeof(Db.Entity))))
eraseIds.Add(id);
//Размещаем блоки
var blockIds_mod = new Dictionary<Db.ObjectId, ExcelRow>();
blockIds_mod = PostBlockRefToDb(newDb, excelRows);
if (blockIds_mod.Count == 0) return;
//Модифицируем блоки
var blockIds = new Dictionary<Db.ObjectId, ExcelRow>();
blockIds = ModifyBlockRefToDb(blockIds_mod);
if (blockIds.Count == 0) return;
//Маркеруем блоки
MarkerGroupb(blockIds);
//Давай сделаем словарик, с номером группы и наибольшей высотой блока в этой группе
Dictionary<int, double> maxBlockRowHeigth = new Dictionary<int, double>();
maxBlockRowHeigth = GetMaxBlockRowHeigth(blockIds.Keys.ToList());
if (maxBlockRowHeigth.Count == 0) return;
//Двигаем блоки, сейчас они все стоят в точке 0,0,0
TransformBlocks(blockIds.Keys.ToList(), maxBlockRowHeigth);
//Удалить объекты из модели, которые были там до начала работы скрипта
foreach (Db.ObjectId id in eraseIds)
using (var ent = id.Open(Db.OpenMode.ForWrite) as Db.DBObject)
ent.Erase();
eraseIds.Clear();
}
Вот это вот: "Удалить объекты из модели, которые были там до начала работы скрипта" , это потому, что я думал что глюки при создании дин. блоков и потому переписывал на копирование блоков которые есть в модели в шаблоне, но нет, не помогает и обратно исправил на создание...
Метод ModifyBlockRefToDb показывал ранее, но вот поправленный вариант с результатом на картинке выше
private static Dictionary<Db.ObjectId, ExcelRow> ModifyBlockRefToDb(Dictionary<Db.ObjectId, ExcelRow> blockRefForSetParam)
{
var pm = new Rtm.ProgressMeter();
pm.Start("Редактирование блоков");
pm.SetLimit(blockRefForSetParam.Count);
//System.Windows.Forms.Application.DoEvents();
var start = DateTime.Now;
var blockRefForSetParamX = new Dictionary<Db.ObjectId, ExcelRow>();
foreach (var ent in blockRefForSetParam)
{
Db.ObjectId id = Db.ObjectId.Null;
using (var blockRef = ent.Key.Open(Db.OpenMode.ForWrite) as Db.BlockReference)
{
foreach (var row in ent.Value.Pairs)
{
blockRef.SetDynamicProperty(row.Key, row.Value);
}
id = blockRef.ObjectId;
}
if (!id.IsNull)
blockRefForSetParamX.Add(id, ent.Value);
pm.MeterProgress();
var difference = DateTime.Now - start;
if (difference.TotalSeconds > 1)
{
System.Windows.Forms.Application.DoEvents();
start = DateTime.Now;
}
}
pm.Stop();
//System.Windows.Forms.Application.DoEvents();
return blockRefForSetParamX;
}
но это все не имеет значения, я даже убирал блокировку в методе CreateDWG и переносил ее DrawBlocks и оборачивал блокированием документа только вызовы методов PostBlockRefToDb, ModifyBlockRefToDb, MarkerGroupb, GetMaxBlockRowHeigth, TransformBlocks, что бы сделать прогресс бар хотя бы по этапам. "Всё фигня, Миша. Начинаем сначала". Я на эту фигню более 30 часов убил и теперь просто принимаю как данность, лучше не использовать прогресс бар и DoEvents при работе с динамическими блоками
if (blockRef != null) //if (!id.IsNull)... 2. какая-то нереализованная проверка?
В моем коде такого нет.
3. Выставляешь динамическое свойство. А существует ли оно и можно ли менять?
Да, существует, да можно менять, да соответствует нужному типу, да укладывается в перечень разрешенных значений.
public static void SetDynamicProperty(this Db.BlockReference acBlockRef, string PropName, object PropValue)
{
if (acBlockRef.IsDynamicBlock)
{
Db.DynamicBlockReferencePropertyCollection acBlockDynProp =
acBlockRef.DynamicBlockReferencePropertyCollection;
if (acBlockDynProp != null)
{
foreach (Db.DynamicBlockReferenceProperty obj in acBlockDynProp)
{
if (!obj.ReadOnly && obj.PropertyName.ToUpper() == PropName.ToUpper())
{
//Если есть что менять...
if (obj.Value.ToString() != PropValue.ToString())
{
object val = null;
if (obj.PropertyTypeCode == (short)DwgDataType.kDwgReal)
{
double v = 0;
if (double.TryParse(PropValue.ToString(), out v))
{
val = v;
}
}
else if (obj.PropertyTypeCode == (short)DwgDataType.kDwgInt32){...}
else if (obj.PropertyTypeCode == (short)DwgDataType.kDwgInt16){...}
else if (obj.PropertyTypeCode == (short)DwgDataType.kDwgInt8){...}
else if (obj.PropertyTypeCode == (short)DwgDataType.kDwgText)
{
val = (object)PropValue.ToString();
}
//А остальное нам не нужно.
if (val != null)
{
var fff = new List<object>(obj.GetAllowedValues());
if (fff.Count == 0 || fff.Any(q => q.ToString() == PropValue.ToString()))
{
obj.Value = val;
break;
}
}
}
}
}
}
}
}
Что-то сложно как-то время вычисляется. Я так и не разобрался - есть там секунда или нет.
Есть, на отладке специально перепроверял. Я сначала пытался через тики 0,1.. 0,5 сек использовать и только потом до 1 секунды дошел. Не помогло.