I have a dialog box that has 2 list boxes. One box has the available layers in it, while the other will contain the selected layers. I want to use those selected layers as a list of layers that will be visible in a particular viewport. I have searched all over to find information on what kind of list I would need and how could I use the list with a viewport, but all I've found is info for one layer becoming visible.
I'm also looking into "FreezeLayersInViewport" but info sure seems limited.
Any help would be appreciated.
Thanks,
Mark
Hi Mark,
I think you are on track with FreezeLayersInViewport() method.
The trick with this method is to:
1. create an ObjectIdCollection that contains the ObjectIds for the layers you want to freeze in the viewport; and
2. pass ObjectIdCollection.GetEnumerator() into the FreezeLayersInViewport method.
Below is a C# sample that I quickly tested. It prompts the user to select a viewport and then freezes layers named "Blue" and "Red".
Hope this helps.
Art.
[CommandMethod("FreezeLayersInViewport")]
public static void FreezeLayersInViewport() {
Document doc = Application.DocumentManager.MdiActiveDocument;
Database db = doc.Database;
Editor ed = doc.Editor;
// Prompt to select paper space Viewport.
PromptEntityOptions peo = newPromptEntityOptions("\nSelect floating paper space viewport: ");
peo.SetRejectMessage("\nFloating paper space viewport not selected. Try again...");
peo.AddAllowedClass(typeof(Autodesk.AutoCAD.DatabaseServices.Viewport), true);
PromptEntityResult per = ed.GetEntity(peo);
// Check prompt result status.
if (per.Status != PromptStatus.OK) {
return;
}
using (Transaction tr = db.TransactionManager.StartTransaction()) {
// ObjectIdCollection for layers to be frozen.
ObjectIdCollection layerIds = newObjectIdCollection();
// Iterate layers and add ObjectIds to ObjectIdCollection.
LayerTable lt = tr.GetObject(db.LayerTableId, OpenMode.ForRead) asLayerTable;
foreach (ObjectId id in lt) {
LayerTableRecord ltr = tr.GetObject(id, OpenMode.ForRead) asLayerTableRecord;
if (ltr.Name == "Blue" || ltr.Name == "Red") {
layerIds.Add(id);
}
}
// Selected Viewport for write.
Autodesk.AutoCAD.DatabaseServices.Viewport vp
= tr.GetObject(per.ObjectId, OpenMode.ForWrite) as AutoCAD.DatabaseServices.Viewport;
// Freeze viewport layers.
vp.FreezeLayersInViewport(layerIds.GetEnumerator());
tr.Commit();
}
}
Just so you know, this is where I found the answer:
http://208.74.205.69/t5/NET/what-is-System-Collections-IEnumerator-I-did-my-homework-I/td-p/1901808
Art
Hi Art,
Thanks for the example and the link. I had actually run across the link in my search, and used some of the info to launch other searches.
I'm going to try and implement your example in my code. I'll let you know how it goes.
Thanks again,
Mark
Hi Mark,
I noticed that when i copy+pasted my sample above there were a couple of typos. I've re-typed the sample below.
Art
[CommandMethod("FreezeLayersInViewport")]
public static void FreezeLayersInViewport() {
Document doc = Application.DocumentManager.MdiActiveDocument;
Database db = doc.Database;
Editor ed = doc.Editor;
// Prompt to select paper space Viewport.
PromptEntityOptions peo = new PromptEntityOptions("\nSelect floating paper space viewport: ");
peo.SetRejectMessage("\nFloating paper space viewport not selected. Try again...");
peo.AddAllowedClass(typeof(Autodesk.AutoCAD.DatabaseServices.Viewport), true);
PromptEntityResult per = ed.GetEntity(peo);
// Check prompt result status.
if (per.Status != PromptStatus.OK) {
return;
}
using (Transaction tr = db.TransactionManager.StartTransaction()) {
// ObjectIdCollection for layers to be frozen.
ObjectIdCollection layerIds = new ObjectIdCollection();
// Iterate layers and add ObjectIds to ObjectIdCollection.
LayerTable lt = tr.GetObject(db.LayerTableId, OpenMode.ForRead) as LayerTable;
foreach (ObjectId id in lt) {
LayerTableRecord ltr = tr.GetObject(id, OpenMode.ForRead) as LayerTableRecord;
if (ltr.Name == "Blue" || ltr.Name == "Red") {
layerIds.Add(id);
}
}
// Selected Viewport for write.
Autodesk.AutoCAD.DatabaseServices.Viewport vp
= tr.GetObject(per.ObjectId, OpenMode.ForWrite) as Autodesk.AutoCAD.DatabaseServices.Viewport;
// Freeze viewport layers.
vp.FreezeLayersInViewport(layerIds.GetEnumerator());
tr.Commit();
}
}
Hi Art,
Thanks a lot. I appreciate the code, plus the comments in the code. It really helps me learn. After taking your code apart and looking up info on ObjectIdCollections, I think I have a better understanding of them.
I do have another question, if you don't mind. I have a dialog that has two listboxes. One is the available layers, and the other is the layers selected from the first listbox. I'm trying to get a layer ID collection of the selected layers, but I don't think I'm going about it the right way.
Here is my code so far, it doesn't work, but I'm still working on it.
Dim layerIds As ObjectIdCollection = New ObjectIdCollection() Dim lt As LayerTable = vpLayertrans.GetObject(db.LayerTableId, OpenMode.ForRead) Dim layerId As ObjectId Dim selectedLayerName As String Dim i As Integer For i = 0 To lstAvailableLayers.SelectedItems.Count - 1 ' Add only the selected layers to the right side list box lstLayersToUse.Items.Add(lstAvailableLayers.SelectedItems(i)) selectedLayerName = (lstAvailableLayers.SelectedItems(i)) Dim ltr As LayerTableRecord = lt(selectedLayerName).GetObject(OpenMode.ForRead) layerId = ltr.ObjectId layerIds.Add(layerId) Next
How do I get the layer ID's from the listbox into the layerIDs collection? I was also thinking I would have to do another "for each" and compare each layer in the layertable to each of the selected layers, but that seemed like a lot extra when the layers being added to the second list box were available as they were being added.
Thanks,
Mark
Hi Mark,
You're welcome.
Looks like you're on the right track. Yes I think you'll need some kind of loop to create the ObjectIdCollection.
One thing you might keep in mind is that you don't actually need to seperately open each LayerTableRecord in order to get each layer's ObjectId. Instead you can simply get the ObjectId for a particular layer as follows:
Dim layerIds As ObjectIdCollection = New ObjectIdCollection()
Dim lt As LayerTable = vpLayertrans.GetObject(db.LayerTableId, OpenMode.ForRead)
For i = 0 To lstLayersToFreeze.SelectedItems.Count - 1
layerIds.Add(lt(lstLayersToFreeze.SelectedItems(i)))
Next
' Insert code here to freeze viewport layers using ObjectIdCollection.
Cheers,
Art
Imports System.Windows.Forms Imports Autodesk.AutoCAD.DatabaseServices Imports Autodesk.AutoCAD Imports Autodesk.AutoCAD.ApplicationServices Imports Autodesk.AutoCAD.ApplicationServices.Application Imports Autodesk.AutoCAD.EditorInput Public Class dialogTitleText Public newTextTitle As String, newTextDieSide As String, layerIds As ObjectIdCollection Public Sub New(ByVal textTitle As String, ByVal textDieSide As String) ' This call is required by the Windows Form Designer. InitializeComponent() ' By default, the label and textbox for the die side text is not visible ' If there actually is text to change, then they becomes visible If textDieSide <> "" Then txtDieSide.Visible = True lblDieSide.Visible = True End If ' This puts the attribute text into the text boxes txtSheetTitle.Text = textTitle txtDieSide.Text = textDieSide End Sub Public Sub MaindialogTitleText_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load Dim myDWG As Autodesk.AutoCAD.ApplicationServices.Document Dim myDB As Autodesk.AutoCAD.DatabaseServices.Database Dim myTransMan As Autodesk.AutoCAD.DatabaseServices.TransactionManager Dim myTrans As Autodesk.AutoCAD.DatabaseServices.Transaction myDWG = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument myDB = myDWG.Database myTransMan = myDWG.TransactionManager myTrans = myTransMan.StartTransaction Dim myLT As Autodesk.AutoCAD.DatabaseServices.LayerTable Dim myLTR As Autodesk.AutoCAD.DatabaseServices.LayerTableRecord Dim mySTE As Autodesk.AutoCAD.DatabaseServices.SymbolTableEnumerator myLT = myDB.LayerTableId.GetObject(Autodesk.AutoCAD.DatabaseServices.OpenMode.ForRead) mySTE = myLT.GetEnumerator While mySTE.MoveNext myLTR = mySTE.Current.GetObject(Autodesk.AutoCAD.DatabaseServices.OpenMode.ForRead) lstAvailableLayers.Items.Add(myLTR.Name) End While myTrans.Dispose() End Sub ReadOnly Property selectedLayers() As ObjectIdCollection Get Return layerIds End Get End Property Private Sub OK_Button_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles OK_Button.Click Me.DialogResult = System.Windows.Forms.DialogResult.OK Me.Close() End Sub Private Sub Cancel_Button_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Cancel_Button.Click Me.DialogResult = System.Windows.Forms.DialogResult.Cancel Me.Close() End Sub Private Sub btnMoveLayers_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnMoveLayers.Click Dim doc As Document = DocumentManager.MdiActiveDocument Dim db As Database = doc.Database Dim ed As Editor = doc.Editor Dim vpLayertrans As Transaction = db.TransactionManager.StartTransaction() ' You must select at least one layer from the list If lstAvailableLayers.SelectedIndex < 0 Then MsgBox("You must select at least one layer", MsgBoxStyle.Exclamation, "Error") Else ' Copies the selected items from the available list to the layers to use list ' Also, it will create an object ID collection of the layers ' ObjectIdCollection for layers to be frozen. Dim layerIds As ObjectIdCollection = New ObjectIdCollection() Dim lt As LayerTable = vpLayertrans.GetObject(db.LayerTableId, OpenMode.ForRead) Dim i As Integer For i = 0 To lstAvailableLayers.SelectedItems.Count - 1 ' Add only the selected layers to the right side list box lstLayersToUse.Items.Add(lstAvailableLayers.SelectedItems(i)) Next For i = 0 To lstAvailableLayers.SelectedItems.Count - 1 layerIds.Add(lt(lstAvailableLayers.SelectedItems(i))) Next End If vpLayertrans.Commit() End Sub End Class
This is the code that calls the form:
If diaTitleText.ShowDialog = System.Windows.Forms.DialogResult.OK Then layerIDs = diaTitleText.selectedLayers ' Freeze viewport layers. If Not vp = Nothing Then vp.FreezeLayersInViewport(layerIDs.GetEnumerator()) End If
Everytime I run it, it seems to be working, but layerIDs always says it equals nothing.
Can you see what's wrong? I really do appreciate the time you've spent helping me.
Thanks,
Mark
Hi Art,
Thanks again, but somethings not working. Here is my forms code now (the whole code):
This does not look right. ReadOnly Property selectedLayers() As ObjectIdCollection
It looks like you are assigning an array() to an objectidecollection.
Try "ReadOnly Property selectedLayers As ObjectIdCollection".
Hi, I try to remove the parenthesis, but they keep reappearing every time I move the cursor off that line.
Thanks,
Mark
I've used it elsewhere in another form in this program to return a string:
ReadOnly Property newPageOption() As String Get Return pageOption End Get End Property
And that one works just great.
I looked real quick and Not sure why you would create a Read-only property when it returns a public field that you can directly access and change?
I am not sure what you are doing but is layerids ever intialized?
Dim layerIds As ObjectIdCollection = new ObjectIdcollection()
Hi Jeff,
Yes I declared it just before I did the ShowDialog.
If textTitle <> "" Then ' After all of the attributes in the block have been checked and the viewport identified Dim diaTitleText As New dialogTitleText(textTitle, textDieSide) Dim layerIDs As ObjectIdCollection If diaTitleText.ShowDialog = System.Windows.Forms.DialogResult.OK Then layerIDs = diaTitleText.selectedLayers
Does it need to be:
Dim layerIds As ObjectIdCollection = new ObjectIdcollection()
Thanks,
Mark
Here is the module that calls the form. It uses layerIDs in the replaceTitleText sub about halfway down.
I just used the Readonly property because I had success with it before. I just want to be able to send the layerIDs ObjectIdCollection from the form to the code that called the form. If there is another way (that will actually work) then I'm all for it.
Mark
Maybe add method to form that returns a collection of strings that are layer names, and in the calling code you can get the ObjectIds from there.
Public Function GetSelectedLayerNames() As List(Of String) Dim objcoll(ListBox1.SelectedItems.Count) As Object Dim layerNames As New List(Of String) ListBox2.SelectedItems.CopyTo(objcoll, 0) layerNames.AddRange(objcoll) Return layerNames End Function
It looks like you need a vacation Jeff. I would have thought you would catch this one.
In the very first line of the class, you (not you Jeff, the OP) declared layerIds as an ObjectIdCollection.
Then in btnMoveLayers_Click, you declared another layerIds as New ObjectIdCollection, and added items to it, but this is not adding items to your class level variable, and the collection that is getting all the items added to it falls out of scope when the btnMoveLayers_Click function ends, and so is not accessible when the code returns to the calling function and tries to use it.
What I would do is add the New keyword to the declaration at the top of the Class (Dim layerIds as NEW ObjectIdCollection), and remove the declaration of layerIds from the click method. Doing so will mean that when the layerIds are accessed by the calling function, the collection will never be nothing, but in the event of failure, may have a count of zero.
Alternatively, you could keep the top declaration the same, and change the line in the click method to:
layerIds = New ObjectIdCollection instead of Dim layerids as ....
this will mean that in the event of a failure prior to adding any layerIds, the collection will be Nothing, instead of a Zero Count.