Сообщество программистов Autodesk в СНГ

ADN Club => AutoCAD .NET API => Тема начата: simson43 от 16-09-2018, 13:34:29

Название: как передать объект в метод
Отправлено: simson43 от 16-09-2018, 13:34:29
нашел необходимые выноски по тексту. занес их в listview.
при выделении необходимых в listview хочу их изменить.

Код - C# [Выбрать]
  1. public partial class ChangerForm : Form
  2.     {
  3.         public ChangerForm()
  4.         {
  5.             InitializeComponent();
  6.             this.find.Focus();
  7.         }
  8.  
  9.         List<ObjectId> ent = new List<ObjectId>();
  10.  
  11.         private void ButtonFind_Click(object sender, EventArgs e)
  12.         {
  13.             infoList.Items.Clear();
  14.            
  15.             int l = 0, ll = 0, imt=0, iot=0, iml=0;
  16.             Document doc = App.DocumentManager.MdiActiveDocument;
  17.             Database db = doc.Database;
  18.  
  19.             using (DocumentLock dl = doc.LockDocument())
  20.             {
  21.                 using (Transaction tr = doc.TransactionManager.StartTransaction())
  22.                 {
  23.                     BlockTable bt = tr.GetObject(db.BlockTableId, OpenMode.ForRead) as BlockTable;
  24.                     DBDictionary dbl = tr.GetObject(db.LayoutDictionaryId, OpenMode.ForRead) as DBDictionary;
  25.  
  26.                     if (allSpace.Checked) ll = dbl.Count-1;
  27.                     else if (inModel.Checked) ll = 0;
  28.                     else if (inLauouts.Checked && ++l == 1) ll = dbl.Count-1;
  29.  
  30.                     List<ObjectId> item = new List<ObjectId>();
  31.                     foreach (DBDictionaryEntry dblay in dbl) item.Add(dblay.Value);
  32.  
  33.                     for (int i = l; i <= ll; i++)
  34.                     {
  35.                         Layout lay = tr.GetObject(item[i], OpenMode.ForRead) as Layout;
  36.                         BlockTableRecord btlay = tr.GetObject(lay.BlockTableRecordId, OpenMode.ForRead) as BlockTableRecord;
  37.                        
  38.                         foreach (ObjectId obid in btlay)
  39.                         {
  40.                             object obj = obid.GetObject(OpenMode.ForRead);
  41.                             if (obj is MLeader)
  42.                             {
  43.                                 MLeader ml = obj as MLeader;
  44.                                 if (ml.MText.Text.IndexOf(find.Text) >= 0 && (skip.Text == "" || ml.MText.Text.IndexOf(skip.Text) == -1))
  45.                                 {                                    
  46.                                     ent.Add(obid);
  47.                                     infoList.Items.Add(new ListViewItem(new[] { lay.LayoutName, "Выноска", ml.MText.Text }));
  48.                                 }
  49.                             }
  50.                         }
  51.  
  52.                     }
  53.                     tr.Commit();
  54.                 }
  55.             }
  56.         }
  57.  
  58.         private void ChangeHand_Click(object sender, EventArgs e)
  59.         {
  60.             Document doc = App.DocumentManager.MdiActiveDocument;
  61.  
  62.             using (DocumentLock dl = doc.LockDocument())
  63.             {
  64.                 using (Transaction tr = doc.TransactionManager.StartTransaction())
  65.                 {
  66.                     var k = infoList.SelectedIndices;
  67.  
  68.                     MLeader ol = ent.ElementAt(k[0]).GetObject(OpenMode.ForWrite) as MLeader;
  69.  
  70.                     ol.MText.Contents = ol.MText.Text.Replace(find.Text, need.Text);
  71.  
  72.                     tr.Commit();
  73.                 }
  74.             }
  75.         }
  76. }
  77.  
  78.  

Что я не так делаю?
проверил id получаемых выносок те же что в первом методе. вроде все что нужно но текст в итоге не меняется

Название: Re: как передать объект в метод
Отправлено: Александр Ривилис от 16-09-2018, 14:43:07
Попробуй заменить:
Код - C# [Выбрать]
  1. ol.MText.Contents = ol.MText.Text.Replace(find.Text, "need.Text");
на
Код - C# [Выбрать]
  1. MText mt = ol.MText;
  2. mt.Text = mt.Text.Replace(find.Text, "need.Text");
  3. ol.MText = mt;
Название: Re: как передать объект в метод
Отправлено: simson43 от 16-09-2018, 14:48:27
да точно. должно работать.
только mt.contents мне кажется ибо text только get
Код - C# [Выбрать]
  1. mt.Conents= mt.Text.Replace(find.Text, "need.Text");

спасибо большое
Название: Re: как передать объект в метод
Отправлено: Александр Ривилис от 16-09-2018, 14:54:43
только mt.contents мне кажется ибо text только get
Да. Основная моя мысль в коде была в том, что нужно из MLeader сначала получить MText, потом MText модифицировать и затем установить MLeader.MText в новое значение MText.
Название: Re: как передать объект в метод
Отправлено: simson43 от 16-09-2018, 15:07:17
а как быть с тем что при замене contents на text слетает все форматирование мтекста?
Название: Re: как передать объект в метод
Отправлено: Александр Ривилис от 16-09-2018, 15:09:37
а как быть с тем что при замене contents на text слетает все форматирование мтекста?
Замени:
Код - C# [Выбрать]
  1. mt.Conents= mt.Text.Replace(find.Text, "need.Text");
на
Код - C# [Выбрать]
  1. mt.Conents= mt.Conents.Replace(find.Text, "need.Text");
и надейся, что форматирование не слетит.
Название: Re: как передать объект в метод
Отправлено: simson43 от 16-09-2018, 15:13:46
в таком случае если внутри contents например такое
\О785\о длина
то в text такое
785 длина
и попытаться найти в contents "785 длина" то ничего не выйдет.
ну и так же с любым другим форматированием. это непредсказуемо что там может быть..
искать разумнее мне кажется в Text, а вот как заменить чтоб ничего не испортилось?

Название: Re: как передать объект в метод
Отправлено: Александр Ривилис от 16-09-2018, 15:17:16
а вот как заменить чтоб ничего не испортилось?
Это достаточно сложно. Для этого следует использовать метод MText.ExplodeFragments, выполнять поиск и замену во фрагментах, а потом объединять их. Ну а если поисковый текст окажется сразу в нескольких фрагментах, то это еще сложнее...
Название: Re: как передать объект в метод
Отправлено: simson43 от 16-09-2018, 15:26:05
Спасибо буду пробовать
Название: Re: как передать объект в метод
Отправлено: avc от 16-09-2018, 22:37:48
Несколько комментариев к коду:
1. Куча-мала из объектов транзакций и объектов полученных через ObjectId.GetObject. Я б не стал так рисковать. Это ж работа без транзакций, так? А тогда, объект полученный без транзакции должен быть ликвидирован. Т.е. забыт using
2. MText, полученный из MLeader по документации тоже должен быть ликвидирован. Т.е. тоже берите через using
3. Нет проверки ContentType - на выноске вовсе не обязательно текст, может быть и блок. И тогда надо работать с атрибутами блока. Или менять ContentType
4. И не зачем объявлять переменные типа object.
Код - C# [Выбрать]
  1. object obj = obid.GetObject(OpenMode.ForRead); if (obj is MLeader) {  MLeader ml = obj as MLeader; ...
можно записать как
Код - C# [Выбрать]
  1.  if (tr.GetObject(obid, OpenMode.ForRead) is MLeader ml) {
Название: Re: как передать объект в метод
Отправлено: simson43 от 16-09-2018, 22:57:59
Спасибо за замечания. Учту
По поводу строчки кода последней.
Впервые встречаю такой синтаксис is mleader ml
Т е если обьект является выноской он сразу присовится переменной ml?
Название: Re: как передать объект в метод
Отправлено: avc от 16-09-2018, 23:02:05
Да именно так. Эту фичу только в последней студии добавили к оператору is .
Но даже без этого вы всегда сразу можете присвоить MLeader ml = tr.GetObject(...) as MLeader и потом проверить на null. Если тип не совпадет as выдаст null. Тип object использовать незачем.
Название: Re: как передать объект в метод
Отправлено: Александр Ривилис от 16-09-2018, 23:03:18
1. Куча-мала из объектов транзакций и объектов полученных через ObjectId.GetObject. Я б не стал так рисковать. Это ж работа без транзакций, так?
Нет. Это работа с TopTransaction (если конечно хотя бы одна транзакция запущена).
Название: Re: как передать объект в метод
Отправлено: avc от 16-09-2018, 23:04:35
Нет.
Не явное использование TopTransaction ?
Название: Re: как передать объект в метод
Отправлено: Александр Ривилис от 16-09-2018, 23:05:29
Нет.
Не явное использование TopTransaction ?
Да.
Название: Re: как передать объект в метод
Отправлено: avc от 16-09-2018, 23:07:44
Да
ОК. Как бы запомнить... Тогда пункт 1 чисто про оформление кода. using не нужен
Название: Re: как передать объект в метод
Отправлено: Александр Ривилис от 16-09-2018, 23:14:06
ОК. Как бы запомнить...
Это просто: .GetObject(...) - это транзакция, а .Open(...) - это без транзакции.
Название: Re: как передать объект в метод
Отправлено: simson43 от 16-09-2018, 23:18:56
в итоге... у меня корректно написано в плане транзакций?
только оформление поправить?
Название: Re: как передать объект в метод
Отправлено: Александр Ривилис от 16-09-2018, 23:21:57
у меня корректно написано в плане транзакций?
Корректно, но некрасиво. Если уж используешь tr.GetObject(...) в одном месте, то и в других используй его, а не objId.GetObject(...)
Название: Re: как передать объект в метод
Отправлено: simson43 от 16-09-2018, 23:25:48
т е по факту obid.getobject и tr.getobject(obid) это одно и тоже просто вопрос красоты?
Название: Re: как передать объект в метод
Отправлено: Александр Ривилис от 16-09-2018, 23:27:53
т е по факту obid.getobject и tr.getobject(obid) это одно и тоже просто вопрос красоты?
В твоём коде - одно и тоже. В общем случае нет, если запущено несколько транзакций.
Название: Re: как передать объект в метод
Отправлено: simson43 от 16-09-2018, 23:28:26
Да именно так. Эту фичу только в последней студии добавили к оператору is .
т е "is mleader ml" это еще и объявление переменной как выноски?
предварительно не нужно объявлять?
Название: Re: как передать объект в метод
Отправлено: simson43 от 16-09-2018, 23:30:29
а не затруднит ли вас немножко подробнее?
т е если много транзакция.. то?
tr.getobject я беру объект из какой то конкретной транзакции а obid.getobject.. ?
из той транзакции в которой нахожусь?
Название: Re: как передать объект в метод
Отправлено: Александр Ривилис от 16-09-2018, 23:30:43
т е "is mleader ml" это еще и объявление переменной как выноски?
Да. Только не mleader, а MLeader - C# регистрозависимый язык.
Название: Re: как передать объект в метод
Отправлено: Александр Ривилис от 16-09-2018, 23:34:49
tr.getoblect я беру объект из какой то конкретной транзакции а obid.getobject.. ?
из той транзакции в которой нахожусь?
objId.GetObject берёт из так называемой TopTransaction - самой последней запущенной в данной базе данных (Database) активной транзакции.
Название: Re: как передать объект в метод
Отправлено: simson43 от 16-09-2018, 23:38:08
это я и имел ввиду.
Спасибо всем большое за комментарии. Теперь я знаю еще чуточку больше!
Название: Re: как передать объект в метод
Отправлено: Дмитрий Загорулькин от 17-09-2018, 14:08:38
т е по факту obid.getobject и tr.getobject(obid) это одно и тоже просто вопрос красоты?
В будущем возможно понадобится заменить Transaction на OpenCloseTransaction. И если первая "понимает" ObjectId.GetObject, то вторая - нет. И при замене одного на другое будет фаталить. Так что, в качестве совета: лучше явно использовать метод транзакции.
Название: Re: как передать объект в метод
Отправлено: Привалов Дмитрий от 17-09-2018, 14:44:42
Так что, в качестве совета: лучше явно использовать метод транзакции.
Плюсую. В ряде случаев попытка открыть объект через ObjectId.GetObject(TopTransaction) приводила к фатальным ошибкам, через Transaction проблем не было. Возможно имеют место конфликты повторного открытия объекта, или попытки открыть с другими правами в TopTransaction, которые решаются использованием Transaction.
Название: Re: как передать объект в метод
Отправлено: Александр Ривилис от 17-09-2018, 16:35:26
В ряде случаев попытка открыть объект через ObjectId.GetObject(TopTransaction) приводила к фатальным ошибкам, через Transaction проблем не было
Может не было ни одной транзакции в данном документе/базе?
Название: Re: как передать объект в метод
Отправлено: simson43 от 17-09-2018, 18:50:47
Так что, в качестве совета
Ваши советы очень ценны! Активно впитываю. Благодарю)
Ps: ваши всм этого сообщества
Название: Re: как передать объект в метод
Отправлено: avc от 17-09-2018, 19:06:51
Ваши советы очень ценны! Активно впитываю. Благодарю)
В таком случае тут принято плюсовать карму ;)
Название: Re: как передать объект в метод
Отправлено: simson43 от 17-09-2018, 19:09:52
А можно вкратце чем отличается openclosetransaction
Название: Re: как передать объект в метод
Отправлено: simson43 от 17-09-2018, 19:11:24
Готово) не знал про эту тему)
Название: Re: как передать объект в метод
Отправлено: Александр Ривилис от 17-09-2018, 19:15:22
А можно вкратце чем отличается openclosetransaction
Погугли по нашему форуму и сайту. Найдёшь много ответов (в том числе и мои). Например:
http://adn-cis.org/forum/index.php?topic=7949.0
http://adn-cis.org/forum/index.php?topic=940.0
P.S. Мы забыли главное правило форума "Один вопрос - одна тема". В этой теме только вопросы по этой теме. Для остальных вопросов создавай новые темы.
Название: Re: как передать объект в метод
Отправлено: simson43 от 20-09-2018, 20:32:33
Несколько комментариев к коду:
1. Куча-мала из объектов транзакций и объектов полученных через ObjectId.GetObject. Я б не стал так рисковать. Это ж работа без транзакций, так? А тогда, объект полученный без транзакции должен быть ликвидирован. Т.е. забыт using
2. MText, полученный из MLeader по документации тоже должен быть ликвидирован. Т.е. тоже берите через using
3. Нет проверки ContentType - на выноске вовсе не обязательно текст, может быть и блок. И тогда надо работать с атрибутами блока. Или менять ContentType
4. И не зачем объявлять переменные типа object.
Код - C# [Выбрать]
  1. object obj = obid.GetObject(OpenMode.ForRead); if (obj is MLeader) {  MLeader ml = obj as MLeader; ...
можно записать как
Код - C# [Выбрать]
  1.  if (tr.GetObject(obid, OpenMode.ForRead) is MLeader ml) {

Поправил по замечаниям и получилось что внутри if еще одно if и более ничего-объеденил все в одно условие.. отсюда вопрос: корректен ли следующий код?
смущает что в одной части условия я только объявляю и присваиваю переменную, а в другой уже ее опрашиваю.. И все внутри одного условия

Код - C# [Выбрать]
  1. if ((tr.GetObject(obid,OpenMode.ForWrite) is MText mt) &&
  2.    (mt.Text.IndexOf(find.Text) >= 0 && (skip.Text == "" || mt.Text.IndexOf(skip.Text) == -1)))
  3. {
  4.        ent.Add(obid);
  5.        infoList.Items.Add(new ListViewItem(new[] { lay.LayoutName, "Мтекст", mt.Text }));
  6.        imt++;
  7. }
Название: Re: как передать объект в метод
Отправлено: avc от 20-09-2018, 21:29:53
не вижу проблем. абсолютно нормальная практика использовать переменную в том же выражении, где она определена
Название: Re: как передать объект в метод
Отправлено: simson43 от 20-09-2018, 21:32:05
код порядком сократился)
спасибо)
Название: Re: как передать объект в метод
Отправлено: Александр Ривилис от 20-09-2018, 21:44:40
simson43,
Только по этому коду не понятно нужно ли OpenMode.ForWrite или было бы достаточно OpenMode.ForRead, так как в нём этот примитив не редактируется.
Название: Re: как передать объект в метод
Отправлено: Привалов Дмитрий от 20-09-2018, 21:48:37
Поправил по замечаниям и получилось что внутри if еще одно if и более ничего-объеденил все в одно условие.. отсюда вопрос: корректен ли следующий код?
смущает что в одной части условия я только объявляю и присваиваю переменную, а в другой уже ее опрашиваю.. И все внутри одного условия
код корректен, благодаря "is MText mt) &&" т.е. если он MText только тогда будет обращение к свойству mt.Text

Но не зря у тебя сомнения возникли, правильно или нет. Т.к. ты все в один if записал и сделал "плохо читаемый код".
единого совета быть не может как сделать "хорошо читаемый код" но разбив условие например на 2 if и перенеся каждое условие на новую строку ты свой код сделаешь читабельнее.
не экономь на строчках кода или количестве if ;-)
Название: Re: как передать объект в метод
Отправлено: simson43 от 20-09-2018, 22:29:40
simson43,
Только по этому коду не понятно нужно ли OpenMode.ForWrite или было бы достаточно OpenMode.ForRead, так как в нём этот примитив не редактируется.
будет редактироваться, это не весь код
Название: Re: как передать объект в метод
Отправлено: Дмитрий Загорулькин от 21-09-2018, 15:14:04
Т.к. ты все в один if записал и сделал "плохо читаемый код".
единого совета быть не может как сделать "хорошо читаемый код"
Есть хорошие рекомендации в книге "Совершенный код" С.Макконнелла. Глава 19.1.
Название: Re: как передать объект в метод
Отправлено: simson43 от 21-09-2018, 16:06:45
Почитаю. Спасибо.
Название: Re: как передать объект в метод
Отправлено: simson43 от 23-09-2018, 11:25:47
MText mt = ol.MText;
mt.Text = mt.Text.Replace(find.Text, "need.Text");
ol.MText = mt;

наткнулся на Ваши комментарии в похожих темах:
"mt потом неплохо бы освободить (mt.Dispose), а то будет утечка памяти."

выходит после этих моих махинацией тоже следует удалить mt?
Название: Re: как передать объект в метод
Отправлено: Александр Ривилис от 23-09-2018, 12:12:00
выходит после этих моих махинацией тоже следует удалить mt?
Да. Об этом в этой теме уже писал avc:
2. MText, полученный из MLeader по документации тоже должен быть ликвидирован. Т.е. тоже берите через using
Название: Re: как передать объект в метод
Отправлено: simson43 от 23-09-2018, 12:33:35
это аналогично mt.Dispose?
Код - C# [Выбрать]
  1. using (MText mt = ol.MText)
  2.         {
  3.  
  4.         }
Название: Re: как передать объект в метод
Отправлено: Александр Ривилис от 23-09-2018, 13:29:56
это аналогично mt.Dispose?
Код - C# [Выбрать]
  1. using (MText mt = ol.MText)
  2.         {
  3.  
  4.         }

Да.
Название: Re: как передать объект в метод
Отправлено: simson43 от 23-09-2018, 13:46:33
благодарю!