AutoCAD .SendStringToExicute ATTEDIT not selecting selected object - c#

Trying to run ATTEDIT from the Command line after double clicking and have it select the previously selected item. I've intercepted the double click event and can run ATTEDIT, but when I try to pass the position through to the "ATTEDIT Select a block:" it doesn't do anything. But will work when I click on the block again. I thought it was just because I had the units in decimal units rather than architectural. But that doesn't work as well. Here is what I have:
using Autodesk.AutoCAD;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Geometry;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
public class DoubleClickProcess
{
// This function gets called when a block reference is double clicked on. It then checks to see if the block reference
// that was double clicked on was double clicked
[CommandMethod("DOUBLECLICK", CommandFlags.UsePickSet)]
public void ContinueDoubleClick()
{
Document doc = Application.DocumentManager.MdiActiveDocument;
Database database = HostApplicationServices.WorkingDatabase;
Editor ed = doc.Editor;
// Get the PickFirst selection set
PromptSelectionResult acSSPrompt;
acSSPrompt = ed.SelectImplied();
SelectionSet selRes;
// If the prompt status is OK, objects were selected before
// the command was started
if (acSSPrompt.Status == PromptStatus.OK)
{
selRes = acSSPrompt.Value;
Transaction tr = doc.TransactionManager.StartTransaction();
using (tr)
{
// Go through all of the objects that were selected...
ObjectId[] objIds = selRes.GetObjectIds();
foreach (ObjectId objId in objIds)
{
Entity theEnt = (Entity)tr.GetObject(objId, OpenMode.ForRead);
// They must be block references...
if (theEnt.GetType().Name.ToUpper() == "BLOCKREFERENCE")
{
BlockReference bRef = theEnt as BlockReference;
BlockTableRecord btr = null;
btr = tr.GetObject(bRef.DynamicBlockTableRecord, OpenMode.ForRead) as BlockTableRecord;
if (bRef != null)
{
// If it is a specific block then we are interested in it
if (btr.Name.ToString().ToUpper() == "specific")
{
doc.SendStringToExecute("SomeCommand ", true, false, true);
}
else
{
// It's not one we're interested in so do what double clicking would normally do
String objPx = Autodesk.AutoCAD.Runtime.Converter.DistanceToString(bRef.Position.X);
objPx = objPx.Replace(" ", "-");
String objPy = Autodesk.AutoCAD.Runtime.Converter.DistanceToString(bRef.Position.Y);
objPy = objPy.Replace(" ", "-");
String objP = objPx +","+ objPy;
doc.SendStringToExecute("ATTEDIT "+ objP + " ", true, false, true);
}
}
}
theEnt.Dispose();
}
tr.Commit();
}
}
// Clear the PickFirst selection set
ObjectId[] idarrayEmpty = new ObjectId[0];
ed.SetImpliedSelection(idarrayEmpty);
}
}
}
Typing in the architectual position of the mouse works(101'-6-7/8",89'-5-1/2"), but if you type the actual position of the block it doesn't select the block attributes.

I believe it should work with SetImpliedSelection:
SelectionSet selset = SelectionSet.FromObjectIds(new ObjectId[] { bRef.ObjectId });
ed.SetImpliedSelection(selset);
doc.SendStringToExecute("ATTEDIT ", true, false, true);

Related

System.ArgumentNullException: 'value can't be null Parametre name: source'

I have a program which connects to a site and gets the list of orders using soap api. But i have a really strange issue. When a i try to get the orders of a day which there is no orders and then try get list of orders of a day i get this error. But strange thing is if a put a break point to line where i got the error and evalute the program step by step i don't get any errors. How could that happen. herre is the code.
https://api.n11.com/ws/OrderService.wsdl
using n11.Deneme.Forms.com.n11.api;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace n11.Deneme.Forms
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
string strStartDate = "18/01/2020";
string strEndDate = "18/01/2020";
long totalCountValue = 50;
int currentPageValue = 0;
int pageCountValue = 1;
int pageSizeValue = 50;
Authentication auth = new Authentication();
auth.appKey = "b891a6b9-cb97-4a7e-9ffb-f7b1e2a593e8";
auth.appSecret = "pHCjYYadxwTG64Ej";
OrderSearchPeriod orderSearchPeriod = new OrderSearchPeriod();
orderSearchPeriod.startDate = strStartDate;
orderSearchPeriod.endDate = strEndDate;
OrderDataListRequest orderDataListRequest = new OrderDataListRequest();
//orderDataListRequest.status = "1";
orderDataListRequest.period = orderSearchPeriod;
//orderDataListRequest.orderNumber = "209524598478";
PagingData pagingData = new PagingData();
pagingData.currentPage = currentPageValue;
pagingData.pageCount = pageCountValue;
pagingData.pageSize = pageSizeValue;
pagingData.totalCount = totalCountValue;
DetailedOrderListRequest request = new DetailedOrderListRequest();
request.auth = auth;
request.pagingData = pagingData;
request.searchData = orderDataListRequest;
OrderServicePortService port = new OrderServicePortService();
DetailedOrderListResponse response = port.DetailedOrderList(request);
List<DetailedOrderData> orderList = response.orderList.ToList();
foreach (var order in orderList)
{
MessageBox.Show(order.totalAmount.ToString() + " - " + order.orderNumber + " - " + order.citizenshipId + " - " + order.createDate);
long orderIdValue = order.id;
OrderDataRequest orderDataRequest = new OrderDataRequest();
orderDataRequest.id = orderIdValue;
OrderDetailRequest orderdetailrequest = new OrderDetailRequest();
orderdetailrequest.auth = auth;
orderdetailrequest.orderRequest = orderDataRequest;
OrderServicePortService port1 = new OrderServicePortService();
OrderDetailResponse orderDetailResponse = port1.OrderDetail(orderdetailrequest);
OrderDetailData orderDetail = orderDetailResponse.orderDetail;
MessageBox.Show(orderDetail.orderNumber);
List<OrderSearchData> orderItemList = orderDetail.itemList.ToList();
foreach (var item in orderItemList)
{
MessageBox.Show(item.shipmentInfo.campaignNumber);
}
}
}
}
}
If you're getting the error on the line:
List<DetailedOrderData> orderList = response.orderList.ToList(); //I GOT THE ERROR ON THIS LINE
then the thing to do is to look at how response.orderList gets a value. In particular, does it do something with threads, tasks, timers, external events, or anything else like that - which could mean that it gets populated shortly after the initial return from DetailedOrderList, which could explain why it works when you debug and step through (adding a crucial delay into things).
You could also simply do:
var tmp = response.orderList;
if (tmp == null) throw new InvalidOperationException(
"hey, response.orderList was null! this is not good!");
List<DetailedOrderData> orderList = tmp.ToList();
return orderList;
which would make it very clear and explicit that this is what is happening. If you don't get this exception, but something else, then: more debugging needed!
if(response.orderList == null)
{
var temp = button1_Click.PerformClick();
return temp;
}
else
{
List<DetailedOrderData> orderList = response.orderList.ToList();
return orderList;
}

Revit API SizeTableManager.RemoveSizeTable() not working?

I'm trying to remove all Lookup Tables that start with a specific prefix inside all families.
The method "sizeTableManager.RemoveSizeTable(tableToRemove)" returns true as if it succeeded but when I go edit the families in the project and bring up the Lookup Tables list they are still there.
The transaction seems to be committing with no errors too, which is even more puzzling...
Any ideas as to what I'm doing wrong?
This is my code so far:
string existingPrefix = "ExistingPrefix_";
Document doc = this.ActiveUIDocument.Document;
FilteredElementCollector collector = new FilteredElementCollector(doc);
ICollection<Element> elements = collector.OfClass(typeof(Family)).ToElements();
foreach (var element in elements)
{
using (Transaction t = new Transaction(doc, "flush old lookup tables"))
{
t.Start();
FamilySizeTableManager sizeTableManager = FamilySizeTableManager.GetFamilySizeTableManager(doc, element.Id);
if(sizeTableManager != null)
{
foreach (var tableToRemove in sizeTableManager.GetAllSizeTableNames())
{
if(tableToRemove.StartsWith(existingPrefix))
{
bool result = sizeTableManager.RemoveSizeTable(tableToRemove);
if(result)
{
// TaskDialog.Show("Success", "Removed " + tableToRemove + " from " + element.Name);
var test = "test";
}
else
{
TaskDialog.Show("Warning", "Unable to remove " + tableToRemove + " from " + element.Name);
}
}
}
}
var commitResult = t.Commit();
}
}
Thanks in advance!
Well, turns out that the RemoveSizeTable() method was indeed working, but that I had to regenerate the document for the changes to take effect:
using (Transaction t = new Transaction(doc, "regenerate document"))
{
t.Start();
doc.Regenerate();
t.Commit();
}
Discovered this after noticing that saving the document caused the changes to take effect.

AutoCAD .net Side loading a dwg with ReadDwgFile then Plotting

I used the example here to side load dwgs into memory combined with the example here of Plot From Model Space. I got things working except for the plots are not respecting whether the layers are frozen or not and printing as if they were all thawed. The data coming in from the dwg is correct. I can iterate the layers while debugging and verify the correct ones are either frozen or thawed. Also If I just saveas the dwg to a new name it matches the original concerning the layer state.Any Ideas?
[CommandMethod("PlotLayout")]
public static void PlotLayout()
{
// Get the current document and database, and start a transaction
Document acDoc = Active.Document;
Database acCurDb = Active.Database;
Editor ed = Active.Editor;
var collection = new List<string>() { "C:\\Test\\440001A.dwg", "C:\\Test\\440001B.dwg", "C:\\Test\\440001C.dwg", "C:\\Test\\440001D.dwg" };
for (int i = 0; i < collection.Count; i++)
{
var dwg = collection[i];
var dir = Path.GetDirectoryName(dwg);
var fn = Path.GetFileNameWithoutExtension(dwg);
var filePath = Path.Combine(dir, fn + "-" + i.ToString() + ".pdf");
Database oldDb = HostApplicationServices.WorkingDatabase;
using (Database db = new Database(false, true))
{
db.ReadDwgFile(dwg, FileOpenMode.OpenForReadAndAllShare, false, null);
db.CloseInput(true);
using (Transaction acTrans = db.TransactionManager.StartTransaction())
try
{
HostApplicationServices.WorkingDatabase = db;
LayoutManager acLayoutMgr = LayoutManager.Current;
// Get the current layout and output its name in the Command Line window
Layout acLayout = acTrans.GetObject(acLayoutMgr.GetLayoutId(acLayoutMgr.CurrentLayout),
OpenMode.ForRead) as Layout;
// Get the PlotInfo from the layout
using (PlotInfo acPlInfo = new PlotInfo())
{
acPlInfo.Layout = acLayout.ObjectId;
// Get a copy of the PlotSettings from the layout
using (PlotSettings acPlSet = new PlotSettings(acLayout.ModelType))
{
acPlSet.CopyFrom(acLayout);
// Update the PlotSettings object
PlotSettingsValidator acPlSetVdr = PlotSettingsValidator.Current;
// Set the plot type
acPlSetVdr.SetPlotType(acPlSet, Autodesk.AutoCAD.DatabaseServices.PlotType.Extents);
// Set the plot scale
acPlSetVdr.SetUseStandardScale(acPlSet, true);
acPlSetVdr.SetStdScaleType(acPlSet, StdScaleType.ScaleToFit);
// Center the plot
acPlSetVdr.SetPlotCentered(acPlSet, true);
// Set the plot device to use
acPlSetVdr.SetPlotConfigurationName(acPlSet, "DWF6 ePlot.pc3", "ANSI_B_(11.00_x_17.00_Inches)");
// Set the plot info as an override since it will
// not be saved back to the layout
acPlInfo.OverrideSettings = acPlSet;
// Validate the plot info
using (PlotInfoValidator acPlInfoVdr = new PlotInfoValidator())
{
acPlInfoVdr.MediaMatchingPolicy = MatchingPolicy.MatchEnabled;
acPlInfoVdr.Validate(acPlInfo);
// Check to see if a plot is already in progress
if (PlotFactory.ProcessPlotState == ProcessPlotState.NotPlotting)
{
using (PlotEngine acPlEng = PlotFactory.CreatePublishEngine())
{
// Track the plot progress with a Progress dialog
using (PlotProgressDialog acPlProgDlg = new PlotProgressDialog(false, 1, true))
{
using ((acPlProgDlg))
{
// Define the status messages to display
// when plotting starts
acPlProgDlg.set_PlotMsgString(PlotMessageIndex.DialogTitle, "Plot Progress");
acPlProgDlg.set_PlotMsgString(PlotMessageIndex.CancelJobButtonMessage, "Cancel Job");
acPlProgDlg.set_PlotMsgString(PlotMessageIndex.CancelSheetButtonMessage, "Cancel Sheet");
acPlProgDlg.set_PlotMsgString(PlotMessageIndex.SheetSetProgressCaption, "Sheet Set Progress");
acPlProgDlg.set_PlotMsgString(PlotMessageIndex.SheetProgressCaption, "Sheet Progress");
// Set the plot progress range
acPlProgDlg.LowerPlotProgressRange = 0;
acPlProgDlg.UpperPlotProgressRange = 100;
acPlProgDlg.PlotProgressPos = 0;
// Display the Progress dialog
acPlProgDlg.OnBeginPlot();
acPlProgDlg.IsVisible = true;
// Start to plot the layout
acPlEng.BeginPlot(acPlProgDlg, null);
// Define the plot output
acPlEng.BeginDocument(acPlInfo, acDoc.Name, null, 1, true, "c:\\myplot");
// Display information about the current plot
acPlProgDlg.set_PlotMsgString(PlotMessageIndex.Status, "Plotting: " + acDoc.Name + " - " + acLayout.LayoutName);
// Set the sheet progress range
acPlProgDlg.OnBeginSheet();
acPlProgDlg.LowerSheetProgressRange = 0;
acPlProgDlg.UpperSheetProgressRange = 100;
acPlProgDlg.SheetProgressPos = 0;
// Plot the first sheet/layout
using (PlotPageInfo acPlPageInfo = new PlotPageInfo())
{
acPlEng.BeginPage(acPlPageInfo, acPlInfo, true, null);
}
acPlEng.BeginGenerateGraphics(null);
acPlEng.EndGenerateGraphics(null);
// Finish plotting the sheet/layout
acPlEng.EndPage(null);
acPlProgDlg.SheetProgressPos = 100;
acPlProgDlg.OnEndSheet();
// Finish plotting the document
acPlEng.EndDocument(null);
// Finish the plot
acPlProgDlg.PlotProgressPos = 100;
acPlProgDlg.OnEndPlot();
acPlEng.EndPlot(null);
}
}
}
}
}
}
}
}
catch (System.Exception ex)
{
ed.WriteMessage(ex.ToString());
}
HostApplicationServices.WorkingDatabase = oldDb;
}
}
}
Not ideal but I found a work around. If I iterate the LayerTable, check for frozen then make IsPlottable false it prints correctly. If a better soultion is available please let me know. Thanks
LayerTable _LayerTable = acTrans.GetObject(db.LayerTableId, OpenMode.ForRead) as LayerTable;
foreach (ObjectId _LayerTableId in _LayerTable)
{
LayerTableRecord _LayerTableRecord =
(LayerTableRecord)acTrans.GetObject(_LayerTableId,
OpenMode.ForWrite);
if (_LayerTableRecord.IsFrozen)
{
_LayerTableRecord.IsPlottable = false;
}
}

AutoCad NET use EntLast with asynchronous command

As I discovered in a previous question:
AutoCad Command Rejected "Undo" when using Application.Invoke()
it appears sending commands such c:wd_insym2 (ACad Electrical command) cannot be called synchronously as it calls additional commands such as Undo, causing it to fail.
However, I need to store the EntityID of the entity I have just created with the command, using either the Lisp (entlast) or Autodesk.AutoCad.Internal.Utils.EntLast(). Obviously if I send my command asynchronously this will not give me the correct result.
Maxence suggested using the doc.CommandEnded handler, however I cannot imagine how this will fit in my program flow, as I need to execute each command individually and then store the new EntityID in a .NET variable.
Is there ANY way for me to either send such commands synchronously without running into reentrancy issues, or alternatively send commands asynchronously and wait for them to execute before continuing?
Have you tried Editor.CommandAsync (AutoCAD 2015 and +):
[CommandMethod("CMD1")]
public async void Command1()
{
Document doc = Application.DocumentManager.MdiActiveDocument;
Editor ed = doc.Editor;
await ed.CommandAsync("_CMD2");
ed.WriteMessage("Last entity handle: {0}", Utils.EntLast().Handle);
}
[CommandMethod("CMD2")]
public void Command2()
{
Document doc = Application.DocumentManager.MdiActiveDocument;
Database db = doc.Database;
using (Transaction tr = db.TransactionManager.StartTransaction())
{
var line = new Line(new Point3d(), new Point3d(10, 20, 30));
var currentSpace = (BlockTableRecord) tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
currentSpace.AppendEntity(line);
tr.AddNewlyCreatedDBObject(line, true);
tr.Commit();
}
}
If you want to do this in an older version of AutoCAD, it will be more complicated:
List<ObjectId> ids;
[CommandMethod("CMD1")]
public void Cmd1()
{
Document doc = Application.DocumentManager.MdiActiveDocument;
ids = new List<ObjectId>();
doc.CommandEnded += Doc_CommandEnded;
doc.SendStringToExecute("_CMD2 0 ", false, false, true);
}
private void Doc_CommandEnded(object sender, CommandEventArgs e)
{
if (e.GlobalCommandName != "CMD2") return;
ids.Add(Utils.EntLast());
var doc = (Document) sender;
if (ids.Count < 10)
{
double angle = ids.Count * Math.PI / 10;
doc.SendStringToExecute("_CMD2 " + Converter.AngleToString(angle) + "\n", false, false, true);
}
else
{
doc.CommandEnded -= Doc_CommandEnded;
doc.Editor.WriteMessage("\nHandles: {0}", string.Join(", ", ids.Select(id => id.Handle.ToString())));
}
}
[CommandMethod("CMD2")]
public void Cmd2()
{
Document doc = Application.DocumentManager.MdiActiveDocument;
Database db = doc.Database;
PromptDoubleResult pdr = doc.Editor.GetAngle("\nAngle: ");
if (pdr.Status == PromptStatus.Cancel) return;
using (Transaction tr = db.TransactionManager.StartTransaction())
{
var line = new Line(new Point3d(), new Point3d(Math.Cos(pdr.Value), Math.Sin(pdr.Value), 0));
var currentSpace = (BlockTableRecord) tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
currentSpace.AppendEntity(line);
tr.AddNewlyCreatedDBObject(line, true);
tr.Commit();
}
}

Programmatically Import Block Into AutoCAD (C#)

I'm writing a plugin for AutoCAD and want to import all the blocks it will use at the beginning to make sure that they are available when needed. To do that, I use this method
public static void ImportBlocks(string[] filesToTryToImport, string filter = "")
{
foreach (string blockToImport in filesToTryToImport)
{
if (blockToImport.Contains(filter))
{
Database sourceDb = new Database(false, true); //Temporary database to hold data for block we want to import
try
{
sourceDb.ReadDwgFile(blockToImport, System.IO.FileShare.Read, true, ""); //Read the DWG into a side database
ObjectIdCollection blockIds = new ObjectIdCollection(); // Create a variable to store the list of block identifiers
Autodesk.AutoCAD.DatabaseServices.TransactionManager tm = sourceDb.TransactionManager;
using (Transaction myT = tm.StartTransaction())
{
// Open the block table
BlockTable bt = (BlockTable)tm.GetObject(sourceDb.BlockTableId, OpenMode.ForRead, false);
// Check each block in the block table
foreach (ObjectId btrId in bt)
{
BlockTableRecord btr = (BlockTableRecord)tm.GetObject(btrId, OpenMode.ForRead, false);
// Only add named & non-layout blocks to the copy list
if (!btr.IsAnonymous && !btr.IsLayout)
{
blockIds.Add(btrId);
}
btr.Dispose();
}
}
// Copy blocks from source to destination database
IdMapping mapping = new IdMapping();
sourceDb.WblockCloneObjects(blockIds, _database.BlockTableId, mapping, DuplicateRecordCloning.Replace, false);
_editor.WriteMessage("\nCopied " + blockIds.Count.ToString() + " block definitions from " + blockToImport + " to the current drawing.");
}
catch (Autodesk.AutoCAD.Runtime.Exception ex)
{
_editor.WriteMessage("\nError during copy: " + ex.Message);
}
finally
{
sourceDb.Dispose();
}
}
}
}
That method appears to work because it successfully executes. However when I go to insert a block in the drawing via AutoCAD's interface it doesn't show up as an option and when I try to insert it programmatically it throws a FileNotFound exception meaning it didn't work. What's wrong with this method? Thanks in advance!
EDIT: Here is a less complicated method with a test method
public static void ImportSingleBlock(string fileToTryToImport)
{
using (Transaction tr = _database.TransactionManager.StartTransaction())
{
Database sourceDb = new Database(false, true); //Temporary database to hold data for block we want to import
try
{
sourceDb.ReadDwgFile(fileToTryToImport, System.IO.FileShare.Read, true, ""); //Read the DWG into a side database
_database.Insert(fileToTryToImport, sourceDb, false);
_editor.WriteMessage("\nSUCCESS: " + fileToTryToImport);
}
catch (Autodesk.AutoCAD.Runtime.Exception ex)
{
_editor.WriteMessage("\nERROR: " + fileToTryToImport);
}
finally
{
sourceDb.Dispose();
}
tr.Commit();
}
}
[CommandMethod("TESTSINGLEBLOCKIMPORTING")]
public void TestSingleBlockImporting()
{
OpenFileDialog ofd = new OpenFileDialog();
DialogResult result = ofd.ShowDialog();
if (result == DialogResult.Cancel) //Ending method on cancel
{
return;
}
string fileToTryToImport = ofd.FileName;
using (Transaction tr = _database.TransactionManager.StartTransaction())
{
EntityMethods.ImportSingleBlock(fileToTryToImport);
tr.Commit();
}
}
This file is the block I'm trying to import. Hope this inspires someone cause I am desperately lost right now.
Your code is correct and should work. In fact I did tried it and works fine. You're probably missing to Commit() a outer transaction (where you call this ImportBlocs() method). Check:
using (Transaction trans = _database.TransactionManager.StartTransaction())
{
ImportBlocks(... parameters here ...);
trans.Commit(); // remember to call this commit, if omitted, Abort() is assumed
}
I had the same issue, very similar code. Issue was that
_database.Insert(fileToTryToImport, sourceDb, false);
should be
_database.Insert(blockName, sourceDb, false);
You can see that the first parameter has to be "blockName", and not the file path.

Categories