A more MVVM way.
XAML
<UserControl x:Class="ZoomToEntityPaletteSample.PaletteTab"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:ZoomToEntityPaletteSample"
mc:Ignorable="d"
d:DesignHeight="150" d:DesignWidth="250">
<Grid Background="WhiteSmoke">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<ListBox Margin="10" Width="200" ItemsSource="{Binding Ids}" SelectedItem="{Binding SelectedId}"/>
<Button Grid.Row="1" Margin="10" Width="100" Command="{Binding ButtonCmd}">Zoom to Entity</Button>
</Grid>
</UserControl>
Code behind
using System.Windows.Controls;
namespace ZoomToEntityPaletteSample
{
public partial class PaletteTab : UserControl
{
public PaletteTab()
{
InitializeComponent();
DataContext = new PaletteTabViewModel();
}
}
}
The CustomPaletteSet class (with auto hide in zero doc state behavior)
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.Windows;
using System;
namespace ZoomToEntityPaletteSample
{
public class CustomPaletteSet : PaletteSet
{
bool wasVisible, hiddenInZeroDocState;
public CustomPaletteSet()
: base("Palette", "SHOWPALETTE", new Guid("{9E7570A4-CFDB-4843-A035-C0B892B695C4}"))
{
Style = PaletteSetStyles.ShowAutoHideButton |
PaletteSetStyles.ShowCloseButton |
PaletteSetStyles.ShowPropertiesMenu;
MinimumSize = new System.Drawing.Size(250, 150);
AddVisual("Tab 1", new PaletteTab());
// hide the palette in zero document state
var docs = Application.DocumentManager;
Application.QuitWillStart += (s, e) => Visible = Visible || hiddenInZeroDocState;
docs.DocumentActivated += (s, e) => Visible = e.Document == null ? false : wasVisible;
docs.DocumentCreated += (s, e) => Visible = wasVisible;
docs.DocumentToBeDeactivated += (s, e) => wasVisible = Visible;
docs.DocumentToBeDestroyed += (s, e) =>
{
wasVisible = Visible;
if (docs.Count == 1 && Visible)
{
hiddenInZeroDocState = true;
Visible = false;
}
};
}
}
}
In the command class, the ZoomToEntity command can be run independently to the palette by prompting the user to select an entity or, use the implied selection if it contains a single entity (CommandFlags.UsePickSet).
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.Windows;
using AcAp = Autodesk.AutoCAD.ApplicationServices.Application;
namespace ZoomToEntityPaletteSample
{
public class Commands
{
static PaletteSet palette;
[CommandMethod("SHOWPALETTE")]
public void CmdPalette()
{
if (palette == null)
palette = new CustomPaletteSet();
palette.Visible = true;
}
[CommandMethod("ZoomToEntity", CommandFlags.UsePickSet | CommandFlags.NoPaperSpace | CommandFlags.Redraw)]
public void ZoomToEntity()
{
var ed = AcAp.DocumentManager.MdiActiveDocument.Editor;
if (ed.SelectImplied().Status == PromptStatus.OK &&
ed.SelectImplied().Value.Count > 1)
ed.SetImpliedSelection(new ObjectId[0]);
var options = new PromptSelectionOptions();
options.SelectEverythingInAperture = true;
options.SingleOnly = true;
var sel = ed.GetSelection(options);
if (sel.Status == PromptStatus.OK)
{
using (var tr = new OpenCloseTransaction())
{
var entity = (Entity)tr.GetObject(sel.Value[0].ObjectId, OpenMode.ForRead);
var extents = entity.GeometricExtents;
dynamic acadApp = Application.AcadApplication;
acadApp.ZoomWindow(extents.MinPoint.ToArray(), extents.MaxPoint.ToArray());
acadApp.ZoomScaled(0.8, 1);
}
ed.SetImpliedSelection(sel.Value);
}
}
}
}
The PaletteTabViewModel class.
As we do not know how you get the ObjectId to fill the list box, here it gets all entities in model space.
The Cmd() method (the action of the ICommand property bound to the button) calls SetImpliedSelection with the selected ObjectId before calling the ZoomToEntity command.
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using AcAp = Autodesk.AutoCAD.ApplicationServices.Application;
namespace ZoomToEntityPaletteSample
{
public class PaletteTabViewModel : INotifyPropertyChanged
{
IEnumerable<ObjectId> ids;
ObjectId selectedId;
public PaletteTabViewModel()
{
var docs = AcAp.DocumentManager;
Ids = GetIds(docs.MdiActiveDocument);
foreach (Document doc in docs)
{
doc.Database.ObjectAppended += (s, e) => Ids = GetIds(doc);
doc.Database.ObjectErased += (s, e) => Ids = GetIds(doc);
}
docs.DocumentActivated += (s, e) => Ids = GetIds(e.Document);
AcAp.DocumentManager.DocumentCreated += (sender, e) =>
{
var doc = e.Document;
doc.Database.ObjectAppended += (s, _) => Ids = GetIds(doc);
doc.Database.ObjectErased += (s, _) => Ids = GetIds(doc);
};
}
public IEnumerable<ObjectId> Ids
{
get { return ids; }
set { ids = value; RaisePropertyChanged(nameof(Ids)); }
}
public ObjectId SelectedId
{
get { return selectedId; }
set { selectedId = value; RaisePropertyChanged(nameof(SelectedId)); }
}
public RelayCommand ButtonCmd =>
new RelayCommand((_) => Cmd(), (_) => !SelectedId.IsNull);
private void Cmd()
{
var doc = AcAp.DocumentManager.MdiActiveDocument;
if (doc != null)
{
doc.Editor.SetImpliedSelection(new[] { selectedId });
doc.SendStringToExecute("ZoomToEntity ", false, false, false);
}
}
private IEnumerable<ObjectId> GetIds(Document doc)
{
using (var tr = new OpenCloseTransaction())
{
var ms = (BlockTableRecord)tr.GetObject(
SymbolUtilityServices.GetBlockModelSpaceId(doc.Database), OpenMode.ForRead);
return ms.Cast<ObjectId>();
}
}
#region INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
public void RaisePropertyChanged(string propertyName) =>
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
#endregion
}
}
The RelayCommand class is an helper which implements ICommand.
using System;
using System.Windows.Input;
namespace ZoomToEntityPaletteSample
{
public class RelayCommand : ICommand
{
readonly Action<object> execute;
readonly Predicate<object> canExecute;
public RelayCommand(Action<object> execute, Predicate<object> canExecute = null)
{
this.execute = execute ?? throw new ArgumentNullException("execute");
this.canExecute = canExecute ?? (o => true);
}
public void Execute(object parameter) => execute(parameter);
public bool CanExecute(object parameter) => canExecute(parameter);
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
}
}