Here is the code I'm happy with. I added a context menu so that when you have a long list of attributes you can right click on the palette anywhere but a combo box and either apply to block or toggle the de-select option.
Thanks for all the help, and all the comments.
/*
* Created by SharpDevelop.
* User: Tim Willey
* Date: 6/1/2007
* Time: 2:55 PM
*
* To change this template use Tools | Options | Coding | Edit Standard Headers.
* v0.2 6/7/07 Changed the command method call and all method calls to static, per Tony T.'s recommendation
* and Luis E.'s example
* v0.3 6/13/07 Changed the code per Kelie's and Luis E.'s request to have the option of de-select the objects once the
* apply button is pressed. Thanks to Paul R. for the code to de-select the objects.
* Changed the code per Tony T.'s suggestions, so that it won't load up the tool palette when a command is active.
* V0.4 6/13/07 Used Glenn R.'s suggestion for de-selection.
* v0.5 6/14/07 Added a context menu to apply to block and toggle the de-selection option, it also displays what
* the option is currently.
*/
using System;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.IO;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using System.Collections;
using System.Data;
using System.Data.OleDb;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.GraphicsInterface;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Windows.ToolPalette;
using AcadApp = Autodesk.AutoCAD.ApplicationServices.Application;
[assembly: CommandClass(typeof(AutoCAD3M.UserControl1))]
namespace AutoCAD3M
{
/// <summary>
/// Description of UserControl1.
/// </summary>
public class UserControl1 : System.Windows.Forms.UserControl
{
public UserControl1()
{
//
// The InitializeComponent() call is required for Windows Forms designer support.
//
InitializeComponent();
//
// TODO: Add constructor code after the InitializeComponent() call.
//
}
#region Windows Forms Designer generated code
/// <summary>
/// This method is required for Windows Forms designer support.
/// Do not change the method contents inside the source code editor. The Forms designer might
/// not be able to load this method if it was changed manually.
/// </summary>
private void InitializeComponent() {
//
// BlankUserControl
//
this.Name = "BlankUserControl";
this.Size = new System.Drawing.Size(232, 408);
}
#endregion
private static Autodesk.AutoCAD.Windows.PaletteSet ps;
private static UserControl1 uc;
private static System.Windows.Forms.Button OkBut;
private static System.Windows.Forms.CheckBox DeSelCkBox;
private static System.Windows.Forms.ContextMenu MyContextMenu;
private static bool FirstLoad = true;
private static bool IsDeSelChecked = true;
private static ObjectId BlockInForm = ObjectId.Null;
[DllImport("acad.exe", CallingConvention = CallingConvention.Cdecl, EntryPoint = "acedSSSetFirst")]
private static extern int acedSSSetFirst(long[] pset, long[] unused);
[CommandMethod("MyAttPalette")]
public static void CreateMyPalette()
{
if (ps == null) {
ps = new Autodesk.AutoCAD.Windows.PaletteSet("My Attribute Palette");
ps.Style = Autodesk.AutoCAD.Windows.PaletteSetStyles.ShowPropertiesMenu |
Autodesk.AutoCAD.Windows.PaletteSetStyles.ShowAutoHideButton |
Autodesk.AutoCAD.Windows.PaletteSetStyles.ShowCloseButton;
ps.Opacity = 90;
ps.Size = new System.Drawing.Size(250, 400);
ps.MinimumSize = new System.Drawing.Size(225, 400);
ps.DockEnabled = Autodesk.AutoCAD.Windows.DockSides.None;
ps.Text = "Edit attributes";
try { ps.AutoRollUp = true; }
catch {}
}
if (ps.Count > 0) ps.Remove(0);
//ObjectId ObjId = SelectBlock();
//if (!ObjId.IsNull) CreateControls(ObjId);
ps.Visible = true;
ps.Dock = Autodesk.AutoCAD.Windows.DockSides.None;
if (FirstLoad) {
foreach (Document Doc in AcadApp.DocumentManager) {
Doc.Editor.SelectionAdded += new SelectionAddedEventHandler(UserControl1.SelectionMade);
}
AcadApp.DocumentManager.DocumentCreated += new DocumentCollectionEventHandler(UserControl1.onDocCreated);
AcadApp.DocumentManager.DocumentToBeDestroyed += new DocumentCollectionEventHandler(UserControl1.onDocToBeDestroyed);
AcadApp.DocumentManager.DocumentBecameCurrent += new DocumentCollectionEventHandler(UserControl1.onDocBecameCurrent);
FirstLoad = false;
}
}
public static void CreateControls (ObjectId ObjId) {
//MessageBox.Show("Creating controls.");
using (DocumentLock DocLock = AcadApp.DocumentManager.MdiActiveDocument.LockDocument()) {
AttributeDefinition AttDef = null;
Document Doc = AcadApp.DocumentManager.MdiActiveDocument;
uc = new UserControl1();
Point StPt = new System.Drawing.Point(2, 45);
bool FoundAtt = false;
using (Transaction Trans = AcadApp.DocumentManager.MdiActiveDocument.TransactionManager.StartTransaction()) {
BlockTable BlkTbl = (BlockTable) Trans.GetObject(Doc.Database.BlockTableId, OpenMode.ForRead);
BlockReference BlkRef = (BlockReference) Trans.GetObject(ObjId, OpenMode.ForWrite);
BlockTableRecord BlkTblRec = (BlockTableRecord) Trans.GetObject(BlkRef.BlockTableRecord, OpenMode.ForRead);
Autodesk.AutoCAD.DatabaseServices.AttributeCollection AttCol = BlkRef.AttributeCollection;
foreach (ObjectId id in AttCol) {
AttributeReference AttRef = (AttributeReference) Trans.GetObject(id, OpenMode.ForRead);
foreach (ObjectId tempId in BlkTblRec) {
AttDef = Trans.GetObject(tempId, OpenMode.ForRead) as AttributeDefinition;
if (AttDef != null && string.Compare(AttDef.Tag, AttRef.Tag) == 0) {
if (string.Equals(AttDef.Prompt, string.Empty))
UserControl1.CreateComboBoxAndLabel(AttRef.Tag, AttRef.TextString, AttRef.ObjectId, StPt, uc);
else UserControl1.CreateComboBoxAndLabel(AttDef.Prompt, AttRef.TextString, AttRef.ObjectId, StPt, uc);
FoundAtt = true;
break;
}
}
if (!FoundAtt) UserControl1.CreateComboBoxAndLabel(AttRef.Tag, AttRef.TextString, AttRef.ObjectId, StPt, uc);
else FoundAtt = false;
StPt = new System.Drawing.Point(StPt.X, StPt.Y + 30);
}
}
OkBut = new System.Windows.Forms.Button();
OkBut.Text = "Apply to block";
OkBut.Name = "Okbutton";
OkBut.BackColor = System.Drawing.Color.Silver;
OkBut.ForeColor = System.Drawing.Color.Navy;
OkBut.Location = new System.Drawing.Point(5, 0);
OkBut.Size = new System.Drawing.Size(220, 25);
OkBut.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right | System.Windows.Forms.AnchorStyles.Top)));
OkBut.Click += new System.EventHandler(UserControl1.OkayButtonClick);
uc.Controls.Add(OkBut);
DeSelCkBox = new System.Windows.Forms.CheckBox();
DeSelCkBox.Text = "De-Select objects after apply?";
DeSelCkBox.Size = new System.Drawing.Size(220, 20);
DeSelCkBox.Checked = IsDeSelChecked;
DeSelCkBox.Location = new System.Drawing.Point(5, 25);
DeSelCkBox.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Top)));
uc.Controls.Add(DeSelCkBox);
uc.Resize += new System.EventHandler(UserControl1.FormResized);
uc.MouseWheel += new MouseEventHandler(UserControl1.WheelMoved);
MyContextMenu = new System.Windows.Forms.ContextMenu();
MyContextMenu.Popup += new System.EventHandler(UserControl1.MyPopupMenu);
uc.ContextMenu = MyContextMenu;
uc.AutoScroll = true;
uc.AutoScrollMinSize = new System.Drawing.Size(0, 400);
if (ps.Count > 0) ps.Remove(0);
ps.Add("Test", uc);
BlockInForm = ObjId;
}
}
public static void CreateComboBoxAndLabel (string cbName, string cbValue, object Obj, Point pt, UserControl1 uc) {
ComboBox cb = new System.Windows.Forms.ComboBox();
cb.BackColor = System.Drawing.Color.Silver;
cb.ForeColor = System.Drawing.Color.Navy;
cb.Name = cbName;
cb.Text = cbValue;
cb.Location = pt;
cb.Size = new System.Drawing.Size(150,25);
cb.DropDownStyle = System.Windows.Forms.ComboBoxStyle.Simple;
cb.Tag = Obj;
Label lb = new System.Windows.Forms.Label();
lb.Name = cbName;
lb.Text = cbName;
lb.Height = 20;
lb.Size = new System.Drawing.Size(200, 25);
lb.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
lb.Location = new System.Drawing.Point(pt.X + 5 + cb.Size.Width, pt.Y);
uc.Controls.Add(cb);
uc.Controls.Add(lb);
}
public static void OkayButtonClick (object sender, System.EventArgs e) {
Document Doc = AcadApp.DocumentManager.MdiActiveDocument;
using (DocumentLock DocLock = Doc.LockDocument()) {
ControlCollection CtrlCol = uc.Controls;
using (Transaction Trans = Doc.TransactionManager.StartTransaction()) {
foreach (Control Ctrl in CtrlCol) {
try {
if (Ctrl.Tag != null) {
ObjectId ObjId = (ObjectId) Ctrl.Tag;
AttributeReference AttRef = Trans.GetObject(ObjId, OpenMode.ForWrite) as AttributeReference;
if (string.Compare(AttRef.TextString, Ctrl.Text) != 0)
AttRef.TextString = Ctrl.Text;
}
}
catch { MessageBox.Show("Could not update attribute value."); }
}
Trans.Commit();
}
if (DeSelCkBox.Checked) {
acedSSSetFirst(null, null);
IsDeSelChecked = true;
}
else IsDeSelChecked = false;
}
AcadApp.UpdateScreen();
BlockInForm = ObjectId.Null;
}
public static void FormResized (object sender, System.EventArgs e) {
OkBut.Size = new System.Drawing.Size(uc.Width - 15, 25);
}
public static void WheelMoved (object sender, MouseEventArgs e) {
MessageBox.Show(e.Delta.ToString());
}
public static void ToggleDeSelect (object sender, System.EventArgs e) {
if (DeSelCkBox.Checked) {
DeSelCkBox.Checked = false;
IsDeSelChecked = false;
}
else {
DeSelCkBox.Checked = true;
IsDeSelChecked = true;
}
}
public static void MyPopupMenu (object sender, System.EventArgs e)
{
string tempStr = "Disabled";
if (DeSelCkBox.Checked) tempStr = "Enabled";
System.Windows.Forms.Menu.MenuItemCollection mic = MyContextMenu.MenuItems;
mic.Clear();
mic.Add("De-Select option is: " + tempStr);
System.Windows.Forms.MenuItem mi1 = new System.Windows.Forms.MenuItem(" &Apply to block.");
mi1.Click += new EventHandler(OkayButtonClick);
mic.Add(mi1);
mi1.Enabled = new EventHandler(OkayButtonClick) != null;
System.Windows.Forms.MenuItem mi2 = new System.Windows.Forms.MenuItem(" &Toggle De-Select.");
mi2.Click += new EventHandler(ToggleDeSelect);
mic.Add(mi2);
mi2.Enabled = new EventHandler(ToggleDeSelect) != null;
}
// Not used.
public ObjectId SelectBlock () {
Document Doc = AcadApp.DocumentManager.MdiActiveDocument;
Editor Ed = Doc.Editor;
PromptEntityOptions Opts = new PromptEntityOptions("\n Select block: ");
Opts.SetRejectMessage("\n Entity not a block.");
Opts.AddAllowedClass(typeof (BlockReference), false);
PromptEntityResult Rslt = Ed.GetEntity(Opts);
return Rslt.ObjectId;
}
public static void SelectionMade (object sender, SelectionAddedEventArgs e) {
//MessageBox.Show("Selection fired.");
if (!ps.Visible || string.Compare(AcadApp.GetSystemVariable("CmdActive").ToString(), "0") != 0) return;
if (e.Selection.Count == 0 && e.AddedObjects.Count != 0)
UserControl1.FillInControl(e.AddedObjects.GetObjectIds());
else if (ps.Count > 0) ps.Remove(0);
}
public static void FillInControl (ObjectId[] ObjIdArray) {
ObjectId BlkId = ObjectId.Null;
int BlkCnt = 0;
using (Transaction Trans = AcadApp.DocumentManager.MdiActiveDocument.TransactionManager.StartTransaction()) {
foreach (ObjectId ObjId in ObjIdArray) {
BlockReference BlkRef = Trans.GetObject(ObjId, OpenMode.ForRead) as BlockReference;
if (BlkRef != null && BlkRef.AttributeCollection.Count > 0) {
++BlkCnt;
BlkId = ObjId;
if (BlkCnt > 1) break;
}
}
}
if (BlkCnt == 1 && (BlockInForm != BlkId || ps.Count == 0)) CreateControls(BlkId);
else if (ps.Count > 0 && BlkCnt != 1 && !object.Equals(BlockInForm, ObjectId.Null)) ps.Remove(0);
}
public static void onDocCreated (object sender, DocumentCollectionEventArgs e) {
Document newDoc = e.Document;
newDoc.Editor.SelectionAdded += new SelectionAddedEventHandler(SelectionMade);
}
public static void onDocToBeDestroyed (object sender, DocumentCollectionEventArgs e) {
Document Doc = e.Document;
Doc.Editor.SelectionAdded -= new SelectionAddedEventHandler(SelectionMade);
}
public static void onDocBecameCurrent (object sender, DocumentCollectionEventArgs e) {
BlockInForm = ObjectId.Null;
if (!ps.Visible || string.Compare(AcadApp.GetSystemVariable("CmdActive").ToString(), "0") != 0) return;
PromptSelectionResult psr = e.Document.Editor.SelectImplied() as PromptSelectionResult;
if (psr == null) return;
SelectionSet ss = psr.Value as SelectionSet;
if (ss != null && ss.Count > 0) UserControl1.FillInControl(ss.GetObjectIds());
else if (ps.Count > 0) ps.Remove(0);
}
}
}