|
|
I have encountered an issue with the use of TextBlock->FindText() when the TextBlock is from a TextNode element, The issue is obscure, and I am including a reproducible "test case". The testing function is:
void ChangeFont_newTest(EditElementHandleR eeh, ITextEditP textEdit, DgnFontCP newDgnFont) { T_ITextPartIdPtrVector textPartIds; textEdit->GetTextPartIds(eeh, *ITextQueryOptions::CreateDefault(), textPartIds); for each (ITextPartIdPtr textPartId in textPartIds) { TextBlockPtr textBlock = textEdit->GetTextPart(eeh, *textPartId); if (!textBlock.IsNull()) { if (textBlock.IsValid()) { if (!textBlock->ToString().empty()) { // loop thru each Run
DgnFontCP newDgnFont = DgnFontManager::FindSystemFont(L"Century Gothic"); if (newDgnFont->IsValid()) { RunPropertiesR runProps = textBlock->GetRunPropertiesForAddR(); runProps.SetFont(*newDgnFont); // -> CRASHES ON LAST LINE OF TEXTNODE- why ??? textBlock->SetRunPropertiesForAdd(runProps); } int runIndex = 0; CaretPtr runCaret = textBlock->CreateStartCaret(); do { RunCP run = runCaret->GetCurrentRunCP(); wprintf(L"Run %d [%s]\n", runIndex, run->ToString().c_str()); // use regex search/replace TextBlock::FindTextParametersPtr findParams; TextBlock::FindTextMatchPtr textMatch = nullptr; findParams = TextBlock::FindTextParameters::Create(); findParams->SetUseRegularExpressions(true); findParams->SetMatchWholeWords(true); CaretPtr startCaret = runCaret->Clone(); CaretPtr endCaret = runCaret->Clone(); if (BentleyStatus::ERROR == endCaret->MoveToNextRun() ) { endCaret = textBlock->CreateEndCaret(); } WString regEx(L"[e]"); // while ((textMatch = textBlock->FindText(regEx.c_str(), findParams.get(), startCaret.get(), endCaret.get()/*nullptr*/)).IsValid()) { CaretCR matchStart = textMatch->GetMatchStart(); CaretCR matchEnd = textMatch->GetMatchEnd(); CaretPtr replacementEnd = matchEnd.Clone(); CaretPtr insertCaret; wprintf(L"Match Found\n"); insertCaret = textBlock->Remove(matchStart, *replacementEnd); replacementEnd = textBlock->InsertText(*insertCaret, L"X"); //textBlock->ReplaceText(L"X", matchStart, *replacementEnd); // WORKS - But cannot change font... startCaret = replacementEnd; // matchEnd invalidated } // end of regex wprintf(L"End of Run %d\n", runIndex); runIndex++; } while (BentleyStatus::SUCCESS == runCaret->MoveToNextRun()); textEdit->ReplaceTextPart(eeh, *textPartId, *textBlock); } // if (!str.empty()) } // if (textBlock.IsValid()) } // if (!textBlock.IsNull()) } // for each (ITextPartIdPtr textPartId in textPartIds) } // void ChangeFont_newTest(EditElementHandleR eeh, ITextEditP textEdit, DgnFontCP newDgnFont)
The issue can be seen when there is a multi-line TextNode, such as:
This is Line One
This is Line Two
This is Line Three
This is Line Four
If you set the regex variable to search for L"[e]", all the "e" will be changed to "X" using "Century Gothic" (in this case). However, if you change the regex variable to any character that is on the last line (final paragraph), CONNECT will crash (e.g. L"[u]"). It only happens when you change the RunProperties (SetRUnPropertiesForAdd() AND you are replacing (i.e. using Remove() and InsertText() ) some text that is in the final paragraph of a TextBlock.
Bruce
Hi,
How to delete and create tagset in Microstation V8i using c.
Regards,
Saravanan
When I create a command table in a .NET project (e.g. Commands.xml), the project builds OK but MicroStation doesn't see my command table.
If I edit the Viz Studio project (*.proj) file manually and add a LogicalName element to the command resource specification then MicroStation is able to see my command table...
<ItemGroup><EmbeddedResource Include="Commands.xml"><SubType>Designer</SubType><!-- LogicalName name may be missing --><LogicalName>CommandTable.xml</LogicalName></EmbeddedResource></ItemGroup>
Have I reached the right solution? I can't find anything about this in the help documents.
I saw some examples of how to apply Form into DgnPrimitiveTool, but I saw nothing about WPF together with DgnPrimitiveTool.
Are there any examples of merging DgnPrimitiveTool with WPF?
Thanks!
I wonder if anyone could help please? I've got various unmanaged MDL functions in a C# addin for microstation v8i. The implementation of these is fine and when they work it's great.
Here's some code for background:
[DllImport("stdmdlbltin.dll", CallingConvention = CallingConvention.Cdecl)] internal static extern long mdlView_saveNamed(IntPtr viewNameP, IntPtr descriptionP, IntPtr viewNameSpace, long view);
See the page from MDL Function guide below for the above function. The function returns a 'StatusInt' which indeed does return an integer/long value. But I don't understand what this is or means.
Could someone either point me to a reference that I can look up these codes or give me a clue as to how I can translate them to something string-like.
I've tried assuming they're pointers and tried these:
Marshal.PtrToStringAnsi(pointer) Marshal.PtrToStringAuto(pointer)
Any ideas?
StatusInt | mdlView_saveNamed |
( | |
MSWChar const* | viewNameP , |
MSWChar const* | descriptionP , |
MSWChar const* | viewNameSpace , |
int | view |
); |
Description
Required Header
Required Library
Return Value
Type | Description |
---|---|
StatusInt | SUCCESS if the view element is saved successfully, otherwise MDLERR_BADARG if the view argument is not a valid view number. |
Parameters
Type | Name | Mode | Description |
---|---|---|---|
MSWChar const* | viewNameP | IN | the name to be given to the named view element when it is saved. |
MSWChar const* | descriptionP | IN | the description to be given to the named view element when it is saved. |
MSWChar const* | viewNameSpace | IN | the name space of the named view element. Using NULL will make this named view available to management by the end user via the save views application. Using a non-null value has the effect of making it a protected named view, which is only accessed by the API. |
int | view | IN | the view number to be saved as a named view element. |
Version
VBA Wrapper Declaration
Wondering if anyone would be able to help with an issue I have setting the clip volume for a view using mdlView_setClipBoundaryElement.
Here's the implementation:
[DllImport("stdmdlbltin.dll", CallingConvention = CallingConvention.Cdecl)] internal static extern IntPtr mdlView_setClipBoundaryElement(long viewIndex, ref long elementID); void DoStuff(long viewIndex){ long element = 2950; var result = PInvoke.mdlView_setClipBoundaryElement(viewIndex, ref element); result = PInvoke.mdlView_updateSingle(viewIndex); }
The result here is -168 MDLERR_NOCLIPVOLUME
Doing the reverse yeilds the ID '2950' as expected:
[DllImport("stdmdlbltin.dll", CallingConvention = CallingConvention.Cdecl)] internal static extern IntPtr mdlView_getClipBoundaryElement(ref long pElementId, long viewIndex); void DoStuff(long viewIndex){ long elementId = 0; var result = mdlView_getClipCoundaryElement(ref elementId, viewIndex); }
I'm stumped. I've tried different elements, shapes, simple solids, all of which work when setting the clip manually in Microstation and all of which return the correct element ID when using the getter above.
Thanks in advance.
Jon
How can I acess to each dimension indiviadually thru VBA, when we have one dimension with several segments?
I can only get and change the first segment. I've tried to implement drop method, but it doesn't behave like "drop dimension to segments" command...
Regards
Hi,
I want to import model from dgn file into active design file but I do not know where to start.
thanks
Nenad
Hi,
My system is VS 2015, Framework 4.6.1, c#
I am trying to use DgnDocument in order to copy Model from one dgn file to another.
It looks like function DgnDocument.CreateForLocalFile does not find dgn file.
After executing line DgnDocument.CreateForLocalFile I checked targetDgnDocument.DocState property and it returns "DoesNotExist"
I do not understand what is wrong.
bool test = System.IO.File.Exists("C://Temp//Test3d.dgn"); DgnDocument targetDgnDocument = DgnDocument.CreateForLocalFile("C://Temp//Test3d.dgn"); DgnDocument.Access access= targetDgnDocument.AvailableAccess; DgnFileOwner dgnFileOwner = DgnFile.Create(targetDgnDocument, DgnFileOpenMode.ReadWrite); DgnFile dgnF = dgnFileOwner.DgnFile; ModelIndexCollection mic = dgnF.GetModelIndexCollection(); StatusInt loadDetails; ModelId id = dgnF.FindModelIdByName("291114TH_2001"); DgnModel dgnModel = dgnF.LoadRootModelById(out loadDetails, id); //DoSomeWork(dgnModel); //dgnFile.ProcessChanges(DgnSaveReason.ApplicationInitiated); dgnFileOwner.Dispose();
Appriciate any help
thanks
Nenad
The MicroStationAPI help for mdlCell_getLibraryObject...
StatusInt mdlCell_getLibraryObject ( DgnFileP * ppLibraryObj, WCharCP pLibName, bool unused ) Parameters [out] ppLibraryObj pointer to the cell library object. [in] pLibName name of the cell library to find. [in] unused Unused; pass false.
But, in example cellexp.cpp we see...
iStatus = mdlCell_getLibraryObject (&pLibObj, activeCellLibraryName.c_str(),true);
What value should we assign to that last unused parameter?
Hello,
I launch MicroStation CONNECT updt5 from a bat file setting MS_PAGALLOC=1 and I obtain the alert Window joined.
( My operating system is W7 SP1 64Bit and Microsoft Visual c++ 2015 Redistributable (x64) -v 14.0.2.4112 is installed. I haven't such message with MicroStation CONNECT updt 3 or MicroStation V8i.)
Any idea?
Best regards,
Hi,
How do I activate existing DgnModel using NET API c# ?
thanks
Nenad
Hi Experts,
I am using the Microstation C++ sdk to query model's engineer contents, one issue I notice is the 'Locked' property always return true/locked even I saw the element is `unlocked` in microstation application, please see the image:
And here is the code I used to query out all ECInstasnce properites:
DgnFilePtr dgnFile = OpenDgnFile(filename, DgnFileOpenMode::ReadOnly); DgnModelR dgnModel = GetDefaultModel(*dgnFile); DgnECManagerR dgnECManager = DgnECManager::GetManager(); // Whenever we query for instances, we need to supply a "scope" for the query... // Do we want to query in just one model, or in a model plus all of its attachments? bool includeReferenceAttachments = true; FindInstancesScopePtr scope = FindInstancesScope::CreateScope(*(dgnFile.get()), FindInstancesScopeOption(DgnECHostType_FileAll, includeReferenceAttachments)); ///////////////////////////////////////////////////////////////////////////// // First, we "Find all ECInstances in this model (and its referenced models)" ECQueryPtr findAll = ECQuery::CreateQuery(ECQUERY_PROCESS_SearchAllClasses); // Finds ALL ECInstances, regardless of their ECClass for each (DgnECInstancePtr instance in dgnECManager.FindInstances(*scope, *findAll)) { DgnElementECInstancePtr elementInstance = instance.GetAsElementInstance(); if (elementInstance.IsValid()) { ECClassCR elementClass = elementInstance->GetAsElementInstance()->GetClass(); ECPropertyIterable iter = elementClass.GetProperties(); ECPropertyIterable::const_iterator cit = iter.begin(); while (cit != iter.end()) { ECPropertyP p = *cit; ECValue v; if (SUCCESS == pIECInstance->GetValue(v, p->GetName().c_str())) { wprintf(L"\n Property name =%ls", p->GetName().c_str()); if (v.IsBoolean()) // print out property name and it's values. { wprintf(L" value=%d, ", v.GetBoolean()); } // else if () other types. } } } }
And here is the model I used for testing.
(Please visit the site to view this file)
Could you please help take a look?
Thanks
Danny
When a user opens a V7 file, a Microstation popup is presented that asks the user if they want to "upgrade" to V8 or open the file as V7 ReadOnly. At this point, Microstation has not yet "converted" the file to V8. Is there any way, in code, to "trap" that event? I want to have the user respond to a DialogBox that I hope to display PRIOR to the actual file being converted. Depending on the answer(s), I would either allow the conversion to take place or deny the file upgrade, and open in V7 ReadOnly format.
Bruce
Given a piece of text that uses more than one font usage (e.g. "Note", where the "No" and "te" use different fonts), when you use FindText() to locate that string ("Note"), FindText() does not worry about what font was used. When FindText() returns a match, I create a RunRange() using the MatchStart and MatchEnd carets. For that RunRange, I then use a RunIterator to create get each "part" ( runIter.ToCaret()->GetCurrentRunCP() ).
Now I've got (in my example) two "runs". First is "No" and the second is "te". If I wish to replace "No" with "To" (i.e. go from "Note" to "Tote"), TextBlock->ReplaceText() needs a start and end Caret. The Carets returned by FindText() represent the entire "found" text, NOT the individual "run" parts. How can I get Carets that represent the start and end of the "run" (e.g. ONLY the "No") that comes from the RunIterator? Is it possible ? I think the Carets returned by RunRange.GetStartCaret() and GetEndCaret() are simply the ones used to create the RunRange.
Bruce
In the Wiki for debugging native code mdl application it mentions being able to attach to the microstation process and then select the dll to debug as follows:
Once connected to the MicroStation process, you can add the application to debug. The first step is to include the application's DLL. Select Project > Settings, and select the Debug tab. Change the Category option to Additional DLLs. Select the application's DLL and click OK.
I cannot find where this option to select the additional DLL in Visual studio 2013 is.
Ray
The new code blocks have support for syntax highlighting. Any chance at getting IPlot Design Script as a language? Also might be neat to get MicroStation configuration file variables as a language too.