In the last post we took a look at one technique to sort a list of ObjectIds by the associated objects’ layer and type. In this post we’re going to refactor the commonality to have a single extension method that allows us to sort a list of ObjectIds based on any string property.
Here’s the updated C# code:
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Runtime;
using System;
using System.Collections.Generic;
using System.Linq;
namespace ProcessObjectsInOrder
{
public static class Extensions
{
/// <summary>
/// Sorts an array of ObjectIds based on a string property and order.
/// </summary>
/// <param name="ids">The array of IDs to sort.</param>
/// <param name="propertySelector">A function selecting the string property.</param>
/// <param name="orderSelector">A function to specify the selection order.</param>
/// <returns>An ordered enumerable of key-value pairs.</returns>
public static List<KeyValuePair<ObjectId, string>>
Sort(
this ObjectId[] ids,
Func<dynamic, string> propertySelector,
Func<KeyValuePair<ObjectId, string>, string> orderSelector
)
{
var map = new Dictionary<ObjectId, string>();
foreach (dynamic id in ids)
{
map.Add(id, propertySelector(id));
}
return map.OrderBy(orderSelector).ToList();
}
}
public class Commands
{
[CommandMethod("OBL", CommandFlags.UsePickSet)]
public static void ObjectsByLayer()
{
var doc = Application.DocumentManager.MdiActiveDocument;
if (doc == null) return;
var ed = doc.Editor;
// Select the objects to sort
var psr = ed.GetSelection();
if (psr.Status != PromptStatus.OK)
return;
// We'll sort them based on a string value (the layer name)
var map = new Dictionary<ObjectId, string>();
foreach (dynamic id in psr.Value.GetObjectIds())
{
map.Add(id, id.Layer);
}
var sorted = map.OrderBy(kv => kv.Value);
// Print them in order to the command-line
foreach (var item in sorted)
{
ed.WriteMessage("\nObject {0} on layer {1}", item.Key, item.Value);
}
}
[CommandMethod("OBT", CommandFlags.UsePickSet)]
public static void ObjectsByType()
{
var doc = Application.DocumentManager.MdiActiveDocument;
if (doc == null) return;
var ed = doc.Editor;
// Select the objects to sort
var psr = ed.GetSelection();
if (psr.Status != PromptStatus.OK)
return;
// Sort them based on a string value (the class name)
var map = new Dictionary<ObjectId, string>();
foreach (dynamic id in psr.Value.GetObjectIds())
{
map.Add(id, id.ObjectClass.Name);
}
var sorted = map.OrderBy(kv => kv.Value);
// Print them in order to the command-line
foreach (var item in sorted)
{
ed.WriteMessage("\nObject {0} of type {1}", item.Key, item.Value);
}
}
[CommandMethod("OBL2", CommandFlags.UsePickSet)]
public static void ObjectsByLayer2()
{
var doc = Application.DocumentManager.MdiActiveDocument;
if (doc == null) return;
var ed = doc.Editor;
// Select the objects to sort
var psr = ed.GetSelection();
if (psr.Status != PromptStatus.OK)
return;
// Sort them based on a string value (the layer name)
var sorted = psr.Value.GetObjectIds().Sort(id => id.Layer, kv => kv.Value);
// Print them in order to the command-line
foreach (var item in sorted)
{
ed.WriteMessage("\nObject {0} on layer {1}", item.Key, item.Value);
}
}
[CommandMethod("OBT2", CommandFlags.UsePickSet)]
public static void ObjectsByType2()
{
var doc = Application.DocumentManager.MdiActiveDocument;
if (doc == null) return;
var ed = doc.Editor;
// Select the objects to sort
var psr = ed.GetSelection();
if (psr.Status != PromptStatus.OK)
return;
// Sort them based on a string value (the class name)
var sorted =
psr.Value.GetObjectIds().Sort(id => id.ObjectClass.Name, kv => kv.Value);
// Print them in order to the command-line
foreach (var item in sorted)
{
ed.WriteMessage("\nObject {0} of type {1}", item.Key, item.Value);
}
}
}
}
The extension method takes a couple of function parameters: one to select the property to sort on and another to indicate the order.
Here are the new versions of the commands – OBL2 and OBT2 – in action, to make sure they work in the same way as the last ones.
James Maeding made the suggestion of ordering the list directly. That certainly makes sense, if you don’t care about accessing the property the list was sorted on (or don’t mind making the call to query the property again).
I think that in many cases it’ll be important to access the sorting criterion while processing the object, so I’ve decided to leave the implementation as it is. Thanks for the comment, though, James – I can imagine plenty of scenarios where your approach would make sense.
In the next post we’ll convert our extension method into a static template class, allowing us to sort on different property types (such as the color index of an object’s layer).
I’m on vacation up in the mountains, next week, but I’ll at least post the next part (and may well post more – we’ll see how it goes).