Visual Studio 2017 C# .net WPF within Autocad

Visual Studio 2017 C# .net WPF within Autocad

Anonymous
Not applicable
10,892 Views
15 Replies
Message 1 of 16

Visual Studio 2017 C# .net WPF within Autocad

Anonymous
Not applicable

Hello,

 

I am using AutoCAD Mechanical 2016, and Visual Studio 2017 (.net C#).

I have some code that I would like to use a WPF within AutoCAD to control. 

I tried looking for some AutoCAD WPF tutorials with .net but all of them seem to be missing the basic introduction to it.

The link below is a good example of how to accomplish this task..but when I try to utilize this example I get a few issues with it.

http://through-the-interface.typepad.com/through_the_interface/2014/05/adding-a-wpf-document-tab-in-...

 

The main issue is, when the palette shows, it is just a blank box and doesn't show a button I added or any of the stuff the example showed.

 

My main question is:

Is there a really good recent example that shows the most basic uses utilizing a WPF within AutoCAD?

0 Likes
Accepted solutions (2)
10,893 Views
15 Replies
Replies (15)
Message 2 of 16

_gile
Consultant
Consultant
Accepted solution

Hi,

 

To add a WPF modal dialog to your AutoCAD plugin project, you have to add a "User Control (WPF)" to the project and replace Usercontrol with Window in both the xaml and xaml.cs files.

Here's a minimalist example:

XAML:

<Window x:Class="SimpleWpfModalDialog.ModalDialog"
             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:SimpleWpfModalDialog"
             mc:Ignorable="d" Height="160" Width="300">
    <Grid Background="WhiteSmoke">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <Label Grid.Row="0" Margin="5">Enter your name:</Label>
        <TextBox x:Name="nameBox" Grid.Row="1" Margin="5"/>
        <Button x:Name="okButton" Grid.Row="2" Margin="10" HorizontalAlignment="Center" Content="OK" Height="24" Width="80" Click="okButton_Click"/>
    </Grid>
</Window>

Code behind (xaml.cs)

using System.Windows;

namespace SimpleWpfModalDialog
{
    public partial class ModalDialog : Window
    {
        public ModalDialog()
        {
            InitializeComponent();
        }

        public string UserName => nameBox.Text;

        private void okButton_Click(object sender, RoutedEventArgs e)
        {
            DialogResult = true;
        }
    }
}

To display the dialog box from an AutoCAD command, you have to use the Application.ShowModalWindow() method.

using Autodesk.AutoCAD.ApplicationServices.Core;
using Autodesk.AutoCAD.Runtime;

namespace SimpleWpfModalDialog
{
    public class Commands
    {
        [CommandMethod("TEST")]
        public static void Test()
        {
            var doc = Application.DocumentManager.MdiActiveDocument;
            var db = doc.Database;
            var ed = doc.Editor;
            var dialog = new ModalDialog();
            var result = Application.ShowModalWindow(dialog);
            if (result.Value)
                Application.ShowAlertDialog("Hello " + dialog.UserName);
        }
    }
}


Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Message 3 of 16

_gile
Consultant
Consultant
Accepted solution

To add a WPF modeless dialog (typically a PaletteSet) to your AutoCAD plugin project, you have to add a "User Control (WPF)" to the project.

XAML:

<UserControl x:Class="SimpleWpfPalette.PaletteUserControl"
             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:SimpleWpfPalette"
             mc:Ignorable="d" 
             d:DesignHeight="450" d:DesignWidth="800">
    <Grid Background="WhiteSmoke">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <Label Grid.Row="0" Margin="5">Enter your name:</Label>
        <TextBox x:Name="nameBox" Grid.Row="1" Margin="5"/>
        <Button x:Name="okButton" Grid.Row="2" Margin="10" HorizontalAlignment="Center" Content="OK" Height="24" Width="80" Click="okButton_Click"/>
    </Grid>
</UserControl>

in the code behind, you can call a custom AutoCAD command with sendStringToExecute to avoid ahaving to lock the current document and set the focus to AutoCAD application:

using System.Windows;
using System.Windows.Controls;

using AcAp = Autodesk.AutoCAD.ApplicationServices.Application;

namespace SimpleWpfPalette
{
    public partial class PaletteUserControl : UserControl
    {
        public PaletteUserControl()
        {
            InitializeComponent();
        }

        private void okButton_Click(object sender, RoutedEventArgs e)
        {
            var doc = AcAp.DocumentManager.MdiActiveDocument;
            if (doc != null)
                doc.SendStringToExecute("HELLO " + nameBox.Text + "\n", false, false, false);
        }
    }
}

You add to your project a class for your custom palette set which derives from PaletteSet in which you add the Usercontrol using the AddVisual() method.

using System;

using Autodesk.AutoCAD.Windows;

namespace SimpleWpfPalette
{
    public class CustomPalette : PaletteSet
    {
        public CustomPalette()
            : base("WPF Palette", "SHOW_PALETTE", new Guid("{1E20F389-33C1-421F-81CB-B3D413E5B05C}"))
        {
            Style = PaletteSetStyles.ShowAutoHideButton |
                    PaletteSetStyles.ShowCloseButton |
                    PaletteSetStyles.ShowPropertiesMenu;
            MinimumSize = new System.Drawing.Size(250, 150);
            AddVisual("Hello", new PaletteUserControl());
        }
    }
}

From an AutoCAD command you show the palette (and create it if it not already exists). this class also contains the command called from the button in the palette.

using Autodesk.AutoCAD.ApplicationServices.Core;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Runtime;

namespace SimpleWpfPalette
{
    public class Commands
    {
        static CustomPalette palette;

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

        [CommandMethod("Hello")]
        public static void Hello()
        {
            var ed = Application.DocumentManager.MdiActiveDocument.Editor;
            var pr = ed.GetString("\nEnter your name: ");
            if (pr.Status == PromptStatus.OK)
                Application.ShowAlertDialog("Hello " + pr.StringResult);
        }
    }
}

 



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Message 4 of 16

Anonymous
Not applicable

Exactly what I was looking for!  Thank you very much.

0 Likes
Message 5 of 16

essam-salah
Collaborator
Collaborator

HI @_gile

 

 mc:Ignorable="d" Height="100" Width="50">

the window has a fixed height and width, even with the new value (100,50)

any help

 

0 Likes
Message 6 of 16

_gile
Consultant
Consultant

@essam-salah  a écrit :

HI @_gile

 

 mc:Ignorable="d" Height="100" Width="50">

the window has a fixed height and width, even with the new value (100,50)

any help

 


Sorry, I do not understand your question.



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Message 7 of 16

essam-salah
Collaborator
Collaborator
I want the window to be smaller
0 Likes
Message 8 of 16

_gile
Consultant
Consultant

Still not sure to understand, but try:

Height="100" Width="50" ResizeMode="NoResize">


Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Message 9 of 16

essam-salah
Collaborator
Collaborator

sir @_gile

i have a problem but its related to c# more than .NET if u can help.

i wanna link a wpf control  event(combobox1_selectionchanged) to main code in the transaction

 

 public partial class ModalDialog : Window
    {
        public ModalDialog()
        {
            InitializeComponent();
        }

        private void Combobox1_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            //textblock1.Text  = somthingFromTransAction; // ????
        }

 

 

0 Likes
Message 10 of 16

_gile
Consultant
Consultant

@essam-salah, Please start a new thread to ask your question because it is different from the OP.

And try to be more clear and detailed in your request if you want someone to be able to reply you.



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

0 Likes
Message 11 of 16

BKSpurgeon
Collaborator
Collaborator

Hi Gilles

 

Thank you for your answer. Not just this answer, but all the answers on the forum.

 

Re: the above code, when the ok button is clicked, the Dialog Result is set to true. Was wondering if you knew a MVVM way to handle this?

 

  • When the button is clicked a command should fire; and when this command runs, it should somehow close the window. In this case, the ViewModel should not know anything about the view. Is there a way to handle this?

 

 

 public class OverWritePanelsViewModel 
    {
       
        public OverWritePanelsViewModel()
        {
        }

        private ICommand _endCommand;

        public ICommand EndCommand
        {
            get
            {
                if (_endCommand == null)
                {
                    _endCommand = new RelayCommand(
                        p => { // what should go here to close the window? },
                        p => { return true; }
                        );
                }
                return _endCommand;
            }
        }
    }

/// And here is my XAML:

<Window x:Class="BKTools.GrabCopy.OverWrite"
             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:BKTools.Tools.GrabCopy"               
             mc:Ignorable="d"
             d:DesignHeight="450" d:DesignWidth="800">
    <Grid>
        <StackPanel >
            <Button Command="{Binding EndCommand}"> Ok</Button>
        </StackPanel>        
    </Grid>
</Window>


 

 

Message 12 of 16

_gile
Consultant
Consultant

@BKSpurgeon 

Even implementing MVVM, you can use the code behind for a modal dialog box OK button which only set the DialogResult to true.

 



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

0 Likes
Message 13 of 16

norman.yuan
Mentor
Mentor

You can bind the Window itself to the command as CommandParameter in the XAML, like this

<Window x:Name="MyDialog" x:Class=... ...>

  <Grid>

    ...

      <Button Content="OK" Width=100 Height=20 

                     Command="{Binding EndCommand}

                     CommandParameter="{Binding ElementName=MyDialog}" />

    ....

  </Grid>

</Window>

 

Then in the ViewModel, you have the command like this:

 

_endCommand=new relayCommand(

     p => {

                 var win=(System.Windows.Window)p;

 

                 // You can either set the window's DialogResult value

                 win.DialogResult=true/false;

 

                 // Or you can expose a ViewModel's public property to desired value

                 // if the ViewModel remains for next step to get data manipulated by the UI after the view is closed,

                 // this property would indicate if the view is cancelled or not.

                 // then you can close/hide the view, regardless the DialogResult value

                 this.DataOked =  true;

                 win.Close()/Hide(); 

              }

     p => { return true; });

 

The point is that the command parameter is bound to the view Window object, so it can close it.

 

Norman Yuan

Drive CAD With Code

EESignature

Message 14 of 16

_gile
Consultant
Consultant

If you absolutely want to handle the DialogResult from the ViewModel, you can set the CommandParameter of the button to the Window and use this paramater in the EndCommand

 

XAML

<Button Command="{Binding EndCommand}"
        CommandParameter="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Window}}}">Ok</Button>

ViewModel

public RelayCommand EndCommand =>
    new RelayCommand((dlg) => { ((OverWrite)dlg).DialogResult = true; }, (_) => true);

 

One more time @norman.yuan was faster 😉



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Message 15 of 16

_gile
Consultant
Consultant

Another way could be implementing a Button.IsAccept DependencyProperty (similar to Button.IsCancel) as shown in the first reply of this topic.



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

0 Likes
Message 16 of 16

BKSpurgeon
Collaborator
Collaborator

Thank you very much @norman.yuan and @_gile 

0 Likes