Selecting an Object using its ObjectID via WPF

Selecting an Object using its ObjectID via WPF

BKSpurgeon
Collaborator Collaborator
1,771 Views
10 Replies
Message 1 of 11

Selecting an Object using its ObjectID via WPF

BKSpurgeon
Collaborator
Collaborator

I am using WPF within the .net API.

 

What I am trying to do:

  1. I have a list of object Ids.
  2. I am displaying this list to the user.
  3. Upon the user clicking a button, I want the associated ObjectId to be selected.

 

Right now, I am able to zoom in on the relevant object, but for some reason, I can’t seem to select the actual object itself. The below code runs when the button is clicked:

 

any assistance much appreciated

 

 

 

public void SelectEntity(ObjectId objectId)

        {

            using (Transaction tr = objectId.Database.TransactionManager.StartTransaction())

            {

                    // I want to zoom in on the relevant object Id - this works fine

                Entity en = tr.GetObject(objectId, OpenMode.ForRead) as Entity;

                Extents3d extents = en.GeometricExtents;

                Plane plane = new Plane(Point3d.Origin, Vector3d.ZAxis);

                Point2d max = extents.MaxPoint.Convert2d(plane);

                Point2d min = extents.MinPoint.Convert2d(plane);

                string lower =   min.ToString().Substring( 1, min.ToString().Length - 2 );

                string upper =   max.ToString().Substring(1,max.ToString().Length - 2 );

                tr.Commit();

                string cmd = "ZOOM _W " + lower + " " + upper + " ";

                Application.DocumentManager.MdiActiveDocument.SendStringToExecute(cmd, false, false, false);

 

                    // Now I am trying to select the relevant ObjectId but the below attempts

                    // are not working and I have no idea why.

                    // any assistance much appreciated.

 

                Application.DocumentManager.MdiActiveDocument.Editor.SetImpliedSelection(new ObjectId[1] { objectId });

                Application.DocumentManager.MdiActiveDocument.Editor.GetSelection();

 

                Autodesk.AutoCAD.Internal.Utils.SelectObjects(new ObjectId[1] { objectId });               

            }

        }

 

0 Likes
Accepted solutions (2)
1,772 Views
10 Replies
Replies (10)
Message 2 of 11

ActivistInvestor
Mentor
Mentor

SendStringToExecute() doesn't execute the commands you pass it, until after your function returns, so the commands are executing after the setting of the Pickfirst selection set, and the execution of the commands are causing the selected object to be unselected.

 

If you select an object with your mouse and then issue the zoom command, after the zoom command has finished, is the object still selected?

 

Wrap your code inside of a command method, and get rid of the calls to SendStringToExecute(), replacing them with calls to Editor.Command(), and then execute your command method from your button click handler using SendStringToExecute(). 

 

Set the CommandFlags.Redraw flag on the CommandMethod, so that the command can leave objects selected when it ends.

 

 


@BKSpurgeon wrote:

I am using WPF within the .net API.

 

What I am trying to do:

  1. I have a list of object Ids.
  2. I am displaying this list to the user.
  3. Upon the user clicking a button, I want the associated ObjectId to be selected.

 

Right now, I am able to zoom in on the relevant object, but for some reason, I can’t seem to select the actual object itself. The below code runs when the button is clicked:

 

any assistance much appreciated

 

 

 

public void SelectEntity(ObjectId objectId)

        {

            using (Transaction tr = objectId.Database.TransactionManager.StartTransaction())

            {

                    // I want to zoom in on the relevant object Id - this works fine

                Entity en = tr.GetObject(objectId, OpenMode.ForRead) as Entity;

                Extents3d extents = en.GeometricExtents;

                Plane plane = new Plane(Point3d.Origin, Vector3d.ZAxis);

                Point2d max = extents.MaxPoint.Convert2d(plane);

                Point2d min = extents.MinPoint.Convert2d(plane);

                string lower =   min.ToString().Substring( 1, min.ToString().Length - 2 );

                string upper =   max.ToString().Substring(1,max.ToString().Length - 2 );

                tr.Commit();

                string cmd = "ZOOM _W " + lower + " " + upper + " ";

                Application.DocumentManager.MdiActiveDocument.SendStringToExecute(cmd, false, false, false);

 

                    // Now I am trying to select the relevant ObjectId but the below attempts

                    // are not working and I have no idea why.

                    // any assistance much appreciated.

 

                Application.DocumentManager.MdiActiveDocument.Editor.SetImpliedSelection(new ObjectId[1] { objectId });

                Application.DocumentManager.MdiActiveDocument.Editor.GetSelection();

 

                Autodesk.AutoCAD.Internal.Utils.SelectObjects(new ObjectId[1] { objectId });               

            }

        }

 


 

Message 3 of 11

BKSpurgeon
Collaborator
Collaborator

Thank you for your answer Activist.

 

I have a clarification to make:

 

Given the new command method ZoomToEntity below, would you know how I can pass an objectId to this method?

 

As I understand it, all command methods must be in a single class with a commandclass attribute. so i cannot register such a method from within my user control.

 

Would you know how I can pass an objectId to the ZoomEntity method from within my button event handler (which is located in the PanelHighlighter class (of type UserControl) as you've suggested above?

Any advice much appreciated.

 

 

 

 

        [CommandMethod("ZoomToEntity", CommandFlags.Redraw)]
        public void ZoomToEntity() 
        {
                 // I can put the code here, but any ideas how to pass in an objectId to here?
        }
private static PaletteSet ps = null;
public static PanelHighlighter ph = null; // UI - i.e. UserControl
[CommandMethod("CPWin", CommandFlags.Redraw)] public void CPWin() { try { if (ps == null) { ps = new PaletteSet("Comp"); ph = new PanelHighlighter(); ps.AddVisual("Comp", ph); } ps.Visible = true; } catch (System.Exception ex) { if (ex.Message.ToUpper() == "FAIL SILENTLY") { } else { System.Windows.MessageBox.Show(ex.Message); } } }

 

 

0 Likes
Message 4 of 11

_gile
Consultant
Consultant

Hi,

 

Here's a way.

 

In the Commands class

 

using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Runtime;
using AcAp = Autodesk.AutoCAD.ApplicationServices.Application;

namespace AutoCadWpfPaletteSample
{
    public class Commands
    {
        static CustomPaletteSet palette;

        [CommandMethod("SHOWPALETTE")]
        public void ShowPalette()
        {
            if (palette == null)
                palette = new CustomPaletteSet();
            palette.Visible = true;
        }

        [CommandMethod("ZoomToEntity", CommandFlags.Redraw)]
        public void ZoomToEntity()
        {
            var id = palette.Tab.SelectedId;
            if (!id.IsNull)
            {
                using (var tr = new OpenCloseTransaction())
                {
                    var entity = (Entity)tr.GetObject(id, OpenMode.ForRead);
                    var extents = entity.GeometricExtents;
                    dynamic acadApp = Application.AcadApplication;
                    acadApp.ZoomWindow(extents.MinPoint.ToArray(), extents.MaxPoint.ToArray());
                    acadApp.ZoomScaled(0.8, 1);
                    var ed = AcAp.DocumentManager.MdiActiveDocument.Editor;
                    ed.SetImpliedSelection(new[] { id });
                }
            }
        }
    }
}

The CustomPaletteSet class

 

using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.Windows;
using System;

namespace AutoCadWpfPaletteSample
{
    public class CustomPaletteSet : PaletteSet
    {
        public PaletteTab Tab { get; }

        public CustomPaletteSet()
            : base("Palette", "SHOWPALETTE", new Guid("{034E96B4-20D7-4BA7-9CF6-E2E6923E84A3}"))
        {
            Tab = new PaletteTab();
            Style = PaletteSetStyles.ShowAutoHideButton |
                    PaletteSetStyles.ShowCloseButton |
                    PaletteSetStyles.ShowPropertiesMenu;
            MinimumSize = new System.Drawing.Size(250, 150);
            AddVisual("Tab", Tab);
        }
    }
}

The PaletteTab XAML (only Bindings)

 

<UserControl x:Class="AutoCadWpfPaletteSample.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:AutoCadWpfPaletteSample"
             mc:Ignorable="d" 
             d:DesignHeight="150" d:DesignWidth="250">
    <Grid Background="WhiteSmoke">
        <Grid.RowDefinitions>
            <RowDefinition Height="*"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <ListBox Width="200" ItemsSource="{Binding Ids}" SelectedItem="{Binding SelectedId}" />
        <Button Grid.Row="1" Margin="10" Width="100" Click="CmdButton_Click">Zoom To Entity</Button>
    </Grid>
</UserControl>

The code behind

 

using Autodesk.AutoCAD.DatabaseServices;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using AcAp = Autodesk.AutoCAD.ApplicationServices.Core.Application;

namespace AutoCadWpfPaletteSample
{
    public partial class PaletteTab : UserControl, INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        public void RaisePropertyChanged(string propertyName)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }

        ObjectId[] ids;
        ObjectId selectedId;

        public ObjectId[] Ids
        {
            get { return ids; }
            set { ids = value; RaisePropertyChanged(nameof(Ids)); }
        }

        public ObjectId SelectedId
        {
            get { return selectedId; }
            set { selectedId = value; RaisePropertyChanged(nameof(SelectedId)); }
        }

        public PaletteTab()
        {
            InitializeComponent();
            DataContext = this;
        }

        private void CmdButton_Click(object sender, RoutedEventArgs e)
        {
            var doc = AcAp.DocumentManager.MdiActiveDocument;
            doc.SendStringToExecute("ZoomToEntity ", false, false, false);
        }
    }
}


Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Message 5 of 11

_gile
Consultant
Consultant

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; }
        }
    }
}

 



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

0 Likes
Message 6 of 11

_gile
Consultant
Consultant

Oops...

 

In the upper message, the Commands class shoud have been this:

 

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()
        {
            ObjectId id = ObjectId.Null;
            var ed = AcAp.DocumentManager.MdiActiveDocument.Editor;
            if (ed.SelectImplied().Status == PromptStatus.OK && ed.SelectImplied().Value.Count == 1)
            {
                id = ed.SelectImplied().Value[0].ObjectId;
            }
            else
            {
                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)
                {
                    id = sel.Value[0].ObjectId;
                }
            }
            if (!id.IsNull)
            {
                using (var tr = new OpenCloseTransaction())
                {
                    var entity = (Entity)tr.GetObject(id, 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(new[] { id });
            }
        }
    }
}


Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Message 7 of 11

ActivistInvestor
Mentor
Mentor
Accepted solution

First, to clarify what you wrote below, all command methods do not have to be in a single class with a CommandClass attribute.

 

You can place command methods in any number of classes, but if you use the CommandClass attribute anywhere in the assembly, then there must be one CommandClass attribute for every class that contains command methods.

 

What you need to be careful with is the scope of your CommandMethods. Unless there is a good reason for it, you should declare CommandMethods as static methods, rather than instance methods. If a command method is not static, AutoCAD is going to create an instance of the containing class for each open document in which the command is used. So in fact, you can declare a static command method on your UserControl class, but that isn't going to solve the problem, because the command method is static and it doesn't have access to the instance of the UserControl in which the data is obtained from.

 

A simple and direct way to access the ObjectId from the ZoomToEntity() command method, is to declare a static class, with a single static property of the type ObjectId, and before you call SendStringToExecute() to invoke the ZoomToEntity() command method, you assign the ObjectId to the static property of the static class, and then from the ZoomToEntity() command method, you can read that same property. The static class where you store the ObjectId could be nothing more than this:

 


public static class ZoomToEntityData { public static ObjectId EntityId {get; set;} }

 


@BKSpurgeonwrote:

Thank you for your answer Activist.

 

I have a clarification to make:

 

Given the new command method ZoomToEntity below, would you know how I can pass an objectId to this method?

 

As I understand it, all command methods must be in a single class with a commandclass attribute. so i cannot register such a method from within my user control.

 

Would you know how I can pass an objectId to the ZoomEntity method from within my button event handler (which is located in the PanelHighlighter class (of type UserControl) as you've suggested above?

Any advice much appreciated.

 

 

 

 

        [CommandMethod("ZoomToEntity", CommandFlags.Redraw)]
        public void ZoomToEntity() 
        {
                 // I can put the code here, but any ideas how to pass in an objectId to here?
        }
private static PaletteSet ps = null;
public static PanelHighlighter ph = null; // UI - i.e. UserControl
[CommandMethod("CPWin", CommandFlags.Redraw)] public void CPWin() { try { if (ps == null) { ps = new PaletteSet("Comp"); ph = new PanelHighlighter(); ps.AddVisual("Comp", ph); } ps.Visible = true; } catch (System.Exception ex) { if (ex.Message.ToUpper() == "FAIL SILENTLY") { } else { System.Windows.MessageBox.Show(ex.Message); } } }

 

 


 

Message 8 of 11

_gile
Consultant
Consultant
Accepted solution

A better MVVM implementation.

 

Commands class

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.Core.Application;

namespace ZoomToEntityPalette
{
    public class Commands
    {
        static PaletteSet palette;

        [CommandMethod("ZOOMPALETTE")]
        public static void ZoomPalette()
        {
            if (palette == null)
                palette = new CustomPaletteSet();
            palette.Visible = true;
        }


        [CommandMethod("ZOOMTOENTITY", CommandFlags.UsePickSet | CommandFlags.Redraw)]
        public static void ZoomToEntity()
        {
            SelectionSet selection = null;
            var ed = AcAp.DocumentManager.MdiActiveDocument.Editor;
            if (ed.SelectImplied().Status == PromptStatus.OK && ed.SelectImplied().Value.Count == 1)
            {
                selection = ed.SelectImplied().Value;
            }
            else
            {
                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)
                {
                    selection = sel.Value;
                }
            }
            if (selection != null)
            {
                using (var tr = new OpenCloseTransaction())
                {
                    var entity = (Entity)tr.GetObject(selection[0].ObjectId, OpenMode.ForRead);
                    var extents = entity.GeometricExtents;
                    dynamic acadApp = Application.AcadApplication;
                    acadApp.ZoomWindow(extents.MinPoint.ToArray(), extents.MaxPoint.ToArray());
                    acadApp.ZoomScaled(0.9, 1);
                }
                ed.SetImpliedSelection(selection);
            }
        }
    }
}

CustomPaletteSet class

using Autodesk.AutoCAD.ApplicationServices.Core;
using Autodesk.AutoCAD.Windows;
using System;

namespace ZoomToEntityPalette
{
    public class CustomPaletteSet : PaletteSet
    {
        bool wasVisible, hiddenInZeroDocState;

        public CustomPaletteSet()
            : base("Palette", "ZOOMPALETTE", new Guid("{F7082EBA-AE90-4EE7-98A6-EA04ADEFFEC5}"))
        {
            Style = PaletteSetStyles.ShowAutoHideButton |
                    PaletteSetStyles.ShowCloseButton |
                    PaletteSetStyles.ShowPropertiesMenu;
            MinimumSize = new System.Drawing.Size(230, 150);
            AddVisual("ZoomTab", new PaletteTab());
            
            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;
                }
            };
        }
    }
}

PaletteTab XAML

<UserControl x:Class="ZoomToEntityPalette.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:ZoomToEntityPalette"
             mc:Ignorable="d" 
             d:DesignHeight="150" d:DesignWidth="220">
    <Grid Background="WhiteSmoke">
        <Grid.RowDefinitions>
            <RowDefinition Height="*"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <ListBox Margin="10" Width="200" ItemsSource="{Binding ObjectIds}" DisplayMemberPath="ObjectClass.DxfName" SelectedItem="{Binding SelectedId}"/>
        <Button Grid.Row="1" Margin="10" Width="100" Command="{Binding ZoomCommand}">Zoom to Entity</Button>
    </Grid>
</UserControl>

PaletteTab code behind

using System.Windows.Controls;

namespace ZoomToEntityPalette
{
    public partial class PaletteTab : UserControl
    {
        public PaletteTab()
        {
            InitializeComponent();
            DataContext = new PaletteTabViewModel();
        }
    }
}

PaletteTabViewModel class

using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Runtime;
using System.Collections.ObjectModel;
using System.Linq;
using AcAp = Autodesk.AutoCAD.ApplicationServices.Core.Application;

namespace ZoomToEntityPalette
{
    public class PaletteTabViewModel : ObservableObject
    {
        ObservableCollection<ObjectId> ids;
        ObjectId? selectedId;

        public PaletteTabViewModel()
        {
            var docs = AcAp.DocumentManager;
            GetIds(docs.MdiActiveDocument);
            docs.DocumentActivated += (s, e) => GetIds(e.Document);
            foreach (Document doc in docs) AddHandlers(doc);
            AcAp.DocumentManager.DocumentCreated += (s, e) => AddHandlers(e.Document);
        }

        public ObservableCollection<ObjectId> ObjectIds
        {
            get { return ids; }
            set { ids = value; RaisePropertyChanged(nameof(ObjectIds)); }
        }

        public ObjectId? SelectedId
        {
            get { return selectedId; }
            set { selectedId = value; RaisePropertyChanged(nameof(SelectedId)); }
        }

        public RelayCommand ZoomCommand =>
            new RelayCommand((_) => ExecuteZoomCommand(), (_) => selectedId.HasValue);

        private void ExecuteZoomCommand()
        {
            var doc = AcAp.DocumentManager.MdiActiveDocument;
            if (doc != null)
            {
                doc.Editor.SetImpliedSelection(new[] { selectedId.Value });
                SelectedId = null;
                doc.SendStringToExecute("ZoomToEntity ", false, false, false);
            }
        }

        private void AddHandlers(Document doc)
        {
            var db = doc.Database;
            db.ObjectAppended += (s, e) =>
            {
                if (e.DBObject.OwnerId == db.CurrentSpaceId)
                    ObjectIds.Add(e.DBObject.ObjectId);
            };
            db.ObjectErased += (s, e) =>
            {
                if (e.DBObject.OwnerId == db.CurrentSpaceId)
                {
                    if (ids.Contains(e.DBObject.ObjectId))
                        ObjectIds.Remove(e.DBObject.ObjectId);
                    else
                        ObjectIds.Add(e.DBObject.ObjectId);
                }
            };
            doc.LayoutSwitched += (s, e) => GetIds(doc);
            doc.CommandEnded += (s, e) =>
            {
                if(e.GlobalCommandName == "MSPACE" || e.GlobalCommandName == "PSPACE")
                    GetIds(doc);

            };
        }

        private void GetIds(Document doc)
        {
            using (var tr = new OpenCloseTransaction())
            {
                try
                {
                    var space = (BlockTableRecord)tr.GetObject(doc.Database.CurrentSpaceId, OpenMode.ForRead);
                    ObjectIds = new ObservableCollection<ObjectId>(space.Cast<ObjectId>());
                }
                catch (Exception e) when (e.ErrorStatus == ErrorStatus.NullObjectId) { }
                catch { throw; }
            }

        }
    }
}

View Model helper classes

using System.ComponentModel;

namespace ZoomToEntityPalette
{
    public class ObservableObject : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        protected void RaisePropertyChanged(string propertyName)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}
using System;
using System.Windows.Input;

namespace ZoomToEntityPalette
{
    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; }
        }
    }
}


Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

0 Likes
Message 9 of 11

ActivistInvestor
Mentor
Mentor

 

 Hi @_gile

 

You really don't want to call SelectImplied() 3 times redundantly, because it has to do a lot of work.

 

 

selectImplied.png

 

 


@_gilewrote:

A better MVVM implementation.

 

Commands class

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.Core.Application;

namespace ZoomToEntityPalette
{
    public class Commands
    {
        static PaletteSet palette;

        [CommandMethod("ZOOMPALETTE")]
        public static void ZoomPalette()
        {
            if (palette == null)
                palette = new CustomPaletteSet();
            palette.Visible = true;
        }


        [CommandMethod("ZOOMTOENTITY", CommandFlags.UsePickSet | CommandFlags.Redraw)]
        public static void ZoomToEntity()
        {
            SelectionSet selection = null;
            var ed = AcAp.DocumentManager.MdiActiveDocument.Editor;
            if (ed.SelectImplied().Status == PromptStatus.OK && ed.SelectImplied().Value.Count == 1)
            {
                selection = ed.SelectImplied().Value;
            }
            else
            {
                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)
                {
                    selection = sel.Value;
                }
            }
            if (selection != null)
            {
                using (var tr = new OpenCloseTransaction())
                {
                    var entity = (Entity)tr.GetObject(selection[0].ObjectId, OpenMode.ForRead);
                    var extents = entity.GeometricExtents;
                    dynamic acadApp = Application.AcadApplication;
                    acadApp.ZoomWindow(extents.MinPoint.ToArray(), extents.MaxPoint.ToArray());
                    acadApp.ZoomScaled(0.9, 1);
                }
                ed.SetImpliedSelection(selection);
            }
        }
    }
}

}

 

 

 

Message 10 of 11

_gile
Consultant
Consultant

@ActivistInvestor wrote:

 Hi @_gile

You really don't want to call SelectImplied() 3 times redundantly, because it has to do a lot of work.


Thank you for the remark, it must have escaped me when I refactored this code.

 

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.Core.Application;

namespace ZoomToEntityPalette
{
    public class Commands
    {
        static PaletteSet palette;

        [CommandMethod("ZOOMPALETTE")]
        public static void ZoomPalette()
        {
            if (palette == null)
                palette = new CustomPaletteSet();
            palette.Visible = true;
        }


        [CommandMethod("ZOOMTOENTITY", CommandFlags.UsePickSet | CommandFlags.Redraw)]
        public static void ZoomToEntity()
        {
            SelectionSet selection = null;
            var ed = AcAp.DocumentManager.MdiActiveDocument.Editor;
            var selectImplied = ed.SelectImplied();
            if (selectImplied.Status == PromptStatus.OK && selectImplied.Value.Count == 1)
            {
                selection = selectImplied.Value;
            }
            else
            {
                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)
                {
                    selection = sel.Value;
                }
            }
            if (selection != null)
            {
                using (var tr = new OpenCloseTransaction())
                {
                    var entity = (Entity)tr.GetObject(selection[0].ObjectId, OpenMode.ForRead);
                    var extents = entity.GeometricExtents;
                    dynamic acadApp = Application.AcadApplication;
                    acadApp.ZoomWindow(extents.MinPoint.ToArray(), extents.MaxPoint.ToArray());
                    acadApp.ZoomScaled(0.9, 1);
                }
                ed.SetImpliedSelection(selection);
            }
        }
    }
}


Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

0 Likes
Message 11 of 11

ActivistInvestor
Mentor
Mentor

@_gilewrote:

@ActivistInvestorwrote:

 Hi @_gile

You really don't want to call SelectImplied() 3 times redundantly, because it has to do a lot of work.


Thank you for the remark, it must have escaped me when I refactored this code.

 

 

YW, I just wish I had posted the right image, which was supposed to be this one:

 

 

DebugSelectImplied.gif