Author Topic: WPF and AutoCAD  (Read 9007 times)

0 Members and 1 Guest are viewing this topic.

Coder

  • Swamp Rat
  • Posts: 827
WPF and AutoCAD
« on: January 21, 2016, 07:57:10 AM »
Hello guys.

I created a WPF project and everything has been working well until I changed the OutPut Type: from Windows Application to Class Library from ( Project -> Properties-> Application tab -> OutPut Type: ) and lots of errors took a place. see the pic.

I changed the OutPut Type to be able to have a dll file to load it in AutoCAD, how can I solve this error?

What is the best way of creating  WPF dialog in AutoCAD ? is it to start with WPF Project then add a class to the project or start with class then add WPF ( I noticed that it is called user Control (WPF) and NOT straight forward naming WPF Application )

I totally confused with these issues, could anyone help please?

The name of comboBox is pop in my example.

Many thanks .


« Last Edit: January 21, 2016, 08:02:35 AM by Coder »

Coder

  • Swamp Rat
  • Posts: 827
Re: WPF and AutoCAD
« Reply #1 on: January 21, 2016, 01:03:21 PM »
Hello.

After trying and checking for many times I found that I can not start with a WPF application and add a class then after that convert it to Class Library to be able to create a .dll file.

But the one that it did work for me is that I should start with Class library first then adding a WPF application by adding it to the my project via Add -> User Control (WPF).

Good luck for all.

gile

  • Gator
  • Posts: 2507
  • Marseille, France
Re: WPF and AutoCAD
« Reply #2 on: January 21, 2016, 01:58:43 PM »
Hi,

By my side I'd start with a Class Library (or some AutoCAD command template) and add a WPF Window to the project.

Another thing, even if the MVVM design pattern should be quite too much for this kind of small dialog, I think it's a good habit to use the WPF powerful bindings rather than handling events in the code behind (.xaml.cs file).

Here's the way I'd write this kind of small dialog, using only two classes: one where both the AutoCAD command method and the bound wpf properties are defined and another small one to define a wrapper for ICommand interface (both in the same file here).
Nothing more in the code behind than the code generated by Visual Studio.

The xaml (defines the data context and the bindings)
Code - XML: [Select]
  1. <Window x:Class="WpfDialogSample.Dialog"
  2.        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  3.        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  4.        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
  5.        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
  6.        xmlns:local="clr-namespace:WpfDialogSample"
  7.        Title="Insert Text"
  8.        WindowStartupLocation="CenterOwner" Height="120" Width="280" ResizeMode="NoResize">
  9.     <Window.DataContext>
  10.         <local:AcadCommand/>
  11.     </Window.DataContext>
  12.     <Grid>
  13.         <Grid.RowDefinitions>
  14.             <RowDefinition Height="*"/>
  15.             <RowDefinition Height="*"/>
  16.         </Grid.RowDefinitions>
  17.         <ComboBox Grid.Row="0" Height="23" Margin="10,0,10,0" ItemsSource="{Binding Strings}" SelectedIndex="{Binding Index}"/>
  18.         <Grid Grid.Row="1">
  19.             <Grid.ColumnDefinitions>
  20.                 <ColumnDefinition Width="*"/>
  21.                 <ColumnDefinition Width="*"/>
  22.             </Grid.ColumnDefinitions>
  23.             <Button Grid.Column="0" Content="Insert" Height="23" Width="80" Command="{Binding InsertCommand}"/>
  24.             <Button Grid.Column="1" Content="Exit" Height="23" Width="80" IsCancel="True"/>
  25.         </Grid>
  26.     </Grid>
  27. </Window>
  28.  

C# 6
Code - C#: [Select]
  1. using Autodesk.AutoCAD.DatabaseServices;
  2. using Autodesk.AutoCAD.EditorInput;
  3. using Autodesk.AutoCAD.Runtime;
  4. using System;
  5. using System.Windows.Input;
  6. using AcAp = Autodesk.AutoCAD.ApplicationServices.Application;
  7.  
  8. namespace WpfDialogSample
  9. {
  10.     public class AcadCommand
  11.     {
  12.         // bound properties
  13.         public string[] Strings => new[] { "aa", "bb", "cc", "dd" };
  14.  
  15.         public int Index { get; set; }
  16.  
  17.         public ICommand InsertCommand => new SimpleCommand { ExecuteDelegate = (_) => Insert() };
  18.  
  19.         // AutoCAD command
  20.         [CommandMethod("TEST")]
  21.         public void Test()
  22.         {
  23.             var dlg = new Dialog();
  24.             AcAp.ShowModalWindow(dlg);
  25.         }
  26.  
  27.         // action executed by InsertCommand
  28.         private void Insert()
  29.         {
  30.             var doc = AcAp.DocumentManager.MdiActiveDocument;
  31.             var db = doc.Database;
  32.             var ed = doc.Editor;
  33.  
  34.             var result = ed.GetPoint("\nInsertion point: ");
  35.             if (result.Status != PromptStatus.OK)
  36.                 return;
  37.             var pt = result.Value.TransformBy(ed.CurrentUserCoordinateSystem);
  38.  
  39.             using (var tr = db.TransactionManager.StartTransaction())
  40.             {
  41.                 var curSpace = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
  42.                 var text = new DBText();
  43.                 text.TextString = Strings[Index];
  44.                 text.Position = pt;
  45.                 curSpace.AppendEntity(text);
  46.                 tr.AddNewlyCreatedDBObject(text, true);
  47.                 tr.Commit();
  48.             }
  49.         }
  50.     }
  51.  
  52.     // Simplified ICommand implementation
  53.     // https://marlongrech.wordpress.com/2008/11/26/avoiding-commandbinding-in-the-xaml-code-behind-files/
  54.     public class SimpleCommand : ICommand
  55.     {
  56.         public Predicate<object> CanExecuteDelegate { get; set; }
  57.         public Action<object> ExecuteDelegate { get; set; }
  58.  
  59.         public event EventHandler CanExecuteChanged
  60.         {
  61.             add { CommandManager.RequerySuggested += value; }
  62.             remove { CommandManager.RequerySuggested -= value; }
  63.         }
  64.  
  65.         public bool CanExecute(object parameter) => CanExecuteDelegate?.Invoke(parameter) ?? true;
  66.  
  67.         public void Execute(object parameter) => ExecuteDelegate?.Invoke(parameter);
  68.     }
  69.  
« Last Edit: January 21, 2016, 05:10:49 PM by gile »
Speaking English as a French Frog

cvcolomb

  • Guest
Re: WPF and AutoCAD
« Reply #3 on: January 21, 2016, 03:10:20 PM »

I'm with gile on this, simply add a new Project to your solution of type WPF. You can activate the window in your code, and call methods on it or read Properties from it.

Here is a small snippet where I'm showing a WPF dialog then gathering the resulting input data from the DataConext (as this is done in the MVVM pattern). "WallPropertiesEditor" is the WPF Project. I'm also kind of cheating and setting the DataContext myself before showing the dialog. "Bam" is a class which takes data/information from the .dwg and constructs a ViewModel from it, I wanted to show the stored WallProperties (custom framing parameters) when the dialog was fired.

Code: [Select]
WallPropertiesEditor.MainWindow mw = new WallPropertiesEditor.MainWindow();
            WallPropertiesViewModel wpvm = Bam.WallPropsViewModel;
            if (wpvm != null)
            {
                mw.DataContext = wpvm;
                wpvm.InitializeDialog();
                mw.ShowDialog();
            }
            else
            {
                mpOut = null;
                return false;
            }


            if (wpvm.WasCancelled)
            {
                mpOut = null;
                return false;
            }
            else
            {
                mpOut = Bam.GetBam(wpvm);
                return true;
            }

Coder

  • Swamp Rat
  • Posts: 827
Re: WPF and AutoCAD
« Reply #4 on: January 22, 2016, 01:26:23 AM »
Thank you gile ,

I am facing lots of error in the first part of the codes. Maybe I am missing a reference ! sorry.

Plus the dialog couldn't be built due to these codes that prevent the dialog to be built ->  ( <local:AcadCommand/> )

@ cvcolomb I have no idea of what you are trying to show with your codes , I am sorry , I am completely new to your way of coding.

Many thanks

gile

  • Gator
  • Posts: 2507
  • Marseille, France
Re: WPF and AutoCAD
« Reply #5 on: January 22, 2016, 02:43:17 AM »
Coder,

The C# code I posted upper uses C# 6 new syntax. I requires Visual Studio 2015.

For prior versins of C#/Visual Studio, you can try this code:

Code - C#: [Select]
  1. using Autodesk.AutoCAD.ApplicationServices;
  2. using Autodesk.AutoCAD.DatabaseServices;
  3. using Autodesk.AutoCAD.EditorInput;
  4. using Autodesk.AutoCAD.Geometry;
  5. using Autodesk.AutoCAD.Runtime;
  6. using System;
  7. using System.Windows.Input;
  8. using AcAp = Autodesk.AutoCAD.ApplicationServices.Core.Application;
  9.  
  10. namespace WpfDialogSample
  11. {
  12.     public class AcadCommand
  13.     {
  14.         // bound properties
  15.         public string[] Strings
  16.         {
  17.             get { return new[] { "aa", "bb", "cc", "dd" }; }
  18.         }
  19.  
  20.         public int Index { get; set; }
  21.  
  22.         public ICommand InsertCommand
  23.         {
  24.             get
  25.             {
  26.                 SimpleCommand cmd = new SimpleCommand();
  27.                 cmd.ExecuteDelegate = delegate (object x) { Insert(); };
  28.                 return cmd;
  29.             }
  30.         }
  31.  
  32.         // AutoCAD command
  33.         [CommandMethod("TEST")]
  34.         public void Test()
  35.         {
  36.             Dialog dlg = new Dialog();
  37.             AcAp.ShowModalWindow(dlg);
  38.         }
  39.  
  40.         // action executed by InsertCommand
  41.         private void Insert()
  42.         {
  43.             Document doc = AcAp.DocumentManager.MdiActiveDocument;
  44.             Database db = doc.Database;
  45.             Editor ed = doc.Editor;
  46.  
  47.             PromptPointResult result = ed.GetPoint("\nInsertion point: ");
  48.             if (result.Status != PromptStatus.OK)
  49.                 return;
  50.             Point3d pt = result.Value.TransformBy(ed.CurrentUserCoordinateSystem);
  51.  
  52.             using (Transaction tr = db.TransactionManager.StartTransaction())
  53.             {
  54.                 BlockTableRecord curSpace = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
  55.                 DBText text = new DBText();
  56.                 text.TextString = Strings[Index];
  57.                 text.Position = pt;
  58.                 curSpace.AppendEntity(text);
  59.                 tr.AddNewlyCreatedDBObject(text, true);
  60.                 tr.Commit();
  61.             }
  62.         }
  63.     }
  64.  
  65.     // Simplified ICommand implementation
  66.     // https://marlongrech.wordpress.com/2008/11/26/avoiding-commandbinding-in-the-xaml-code-behind-files/
  67.  
  68.     public class SimpleCommand : ICommand
  69.     {
  70.         public Predicate<object> CanExecuteDelegate { get; set; }
  71.         public Action<object> ExecuteDelegate { get; set; }
  72.  
  73.         public event EventHandler CanExecuteChanged
  74.         {
  75.             add { CommandManager.RequerySuggested += value; }
  76.             remove { CommandManager.RequerySuggested -= value; }
  77.         }
  78.  
  79.         public bool CanExecute(object parameter)
  80.         {
  81.             if (CanExecuteDelegate != null)
  82.                 return CanExecuteDelegate(parameter);
  83.             return true;
  84.         }
  85.  
  86.         public void Execute(object parameter)
  87.         {
  88.             if (ExecuteDelegate != null)
  89.                 ExecuteDelegate(parameter);
  90.         }
  91.     }
  92. }
  93.  

The AcadCommand.cs file ant the Dialog.xaml file must belong to the same visual Studio project.
Speaking English as a French Frog

MexicanCustard

  • Swamp Rat
  • Posts: 705
Re: WPF and AutoCAD
« Reply #6 on: January 22, 2016, 11:31:04 AM »
Don't forget to set the owner of your dialog to the AutoCAD mainwindow or you could lose your dialog behind AutoCAD and your users think AutoCAD has frozen.
Revit 2019, AMEP 2019 64bit Win 10

gile

  • Gator
  • Posts: 2507
  • Marseille, France
Re: WPF and AutoCAD
« Reply #7 on: January 22, 2016, 12:26:19 PM »
MexicanCustard,

It seems to me you can't loose a modal dialog behind AutoCAD window.

In case of a modeless window, isn't the AutoCAD window the default owner when not explicitly specified in Application.ShowModelessWindow() method ?
Speaking English as a French Frog

gile

  • Gator
  • Posts: 2507
  • Marseille, France
Re: WPF and AutoCAD
« Reply #8 on: January 23, 2016, 10:14:52 AM »
Hi,

I do not know if this is "the best way of creating a WPF dialog in AutoCAD", but I'll try to give an example.

First, add the attached 'WPF Dialog.zip' file as an Item Template in Visual Studio:
- create a new sub folder named WPF in \Documents\Visual Studio 201X\Templates\ItemTemplates\Visual C#
- save the attached 'WPF Dialog.zip' file as is in this new folder (do not unzip it)

Start an AutoCAD project as you use to (from scratch with a class library project, from a home made project template, from a wizzard, ...)
Right click the project > Add > New Item > WPF and choose 'WPF Dialog'
Rename the XAML file as you want
Click 'Add': the .xaml file and all the required assemblies have been added to your project

You now have a WPF Window in your project you can fill as you want and call from AutoCAD using Application.ShowModalWindow() or Application.ShowModelessWindow().

If you want to use the MVVM pattern or simply avoid using the xaml code behind to handle the dialog as shown upper, you can also add the 'ObservableObject.zip' and the 'SimpleCommand.zip' as Item Templates to Visual Studio. These are two helper classes which implements INotifyPropertyChanged and ICommand.
« Last Edit: January 23, 2016, 11:52:14 AM by gile »
Speaking English as a French Frog

Coder

  • Swamp Rat
  • Posts: 827
Re: WPF and AutoCAD
« Reply #9 on: January 24, 2016, 03:59:53 AM »
Hello gile.

I still can not get it working and just for information I am using VS Community 2015.

I created a new folder (with name: MyWPF ) in the path \Documents\Visual Studio 2015\Templates\ItemTemplates\Visual C#\MyWPF then I create a new Class in C# of course and right click on the project -> Add Item -> WPF but the WPF Dialog is not yet existed !


gile

  • Gator
  • Posts: 2507
  • Marseille, France
Re: WPF and AutoCAD
« Reply #10 on: January 24, 2016, 04:47:39 AM »
Did you save the 'WPF Dialog.zip' file in \Documents\Visual Studio 2015\Templates\ItemTemplates\Visual C#\MyWPF ? If so, you should see it in Visual Studio.
Speaking English as a French Frog

Coder

  • Swamp Rat
  • Posts: 827
Re: WPF and AutoCAD
« Reply #11 on: January 24, 2016, 04:57:26 AM »
Did you save the 'WPF Dialog.zip' file in \Documents\Visual Studio 2015\Templates\ItemTemplates\Visual C#\MyWPF ? If so, you should see it in Visual Studio.

I assume you mean by save is ADDing the folder into the above-said path and you can find out that from the attached images that I posted.

gile

  • Gator
  • Posts: 2507
  • Marseille, France
Re: WPF and AutoCAD
« Reply #12 on: January 24, 2016, 06:06:09 AM »
By 'save' I mean put the .zip file as is (do not extract its contents).

If you created a 'MyWPF' folder in 'Visual C# Items', you should see it.
If you put the 'WPF Dialog.zip' file in 'MyWPF' folder, you should see it.

As you can see in my screen shots, you can simply create a 'WPF' folder, Visual Studio will merge it with its own.
Speaking English as a French Frog

Coder

  • Swamp Rat
  • Posts: 827
Re: WPF and AutoCAD
« Reply #13 on: January 25, 2016, 12:42:43 AM »
Great job gile.

I have working now , many thanks.

Coder

  • Swamp Rat
  • Posts: 827
Re: WPF and AutoCAD
« Reply #14 on: January 28, 2016, 12:53:39 AM »
Hello gile,

Every time I start with a new WPF_Dialog1 I receive the same error as in the image below even if I use User Control (WPF) I would have the same error.
What's made this error to appear and how to solve it please ?

Many thanks

kdub_nz

  • Mesozoic keyThumper
  • SuperMod
  • Water Moccasin
  • Posts: 2132
  • class keyThumper<T>:ILazy<T>
Re: WPF and AutoCAD
« Reply #15 on: January 28, 2016, 01:19:08 AM »
Have you referenced System.Xaml ?

If you want people to look at this issue the least you could do is attach a zip of the FULL project/solution.
... and instructions to reproduce the issue.




Called Kerry in my other life
Retired; but they dragged me back in !

I live at UTC + 13.00

---
some people complain about loading the dishwasher.
Sometimes the question is more important than the answer.

Coder

  • Swamp Rat
  • Posts: 827
Re: WPF and AutoCAD
« Reply #16 on: January 28, 2016, 02:28:25 AM »
Hi kerry,

Yes I already added the System.Xaml  I closed and opened the project again the error disappeared.  :crazy2:

CADbloke

  • Bull Frog
  • Posts: 342
  • Crash Test Dummy
Re: WPF and AutoCAD
« Reply #17 on: January 28, 2016, 04:32:53 AM »



Once you've got your head around MVVM, melt it with http://reactiveui.net/. This is what is keeping me up at nights at the moment.

If you want to know more about Reactive Extensions , http://www.introtorx.com/ is probably the best place to start.

kdub_nz

  • Mesozoic keyThumper
  • SuperMod
  • Water Moccasin
  • Posts: 2132
  • class keyThumper<T>:ILazy<T>
Re: WPF and AutoCAD
« Reply #18 on: January 28, 2016, 09:15:55 PM »


Once you've got your head around MVVM, melt it with http://reactiveui.net/. This is what is keeping me up at nights at the moment.
If you want to know more about Reactive Extensions , http://www.introtorx.com/ is probably the best place to start.

:-)
Functional reactive programming is the peanut butter and chocolate of programming paradigms.
Called Kerry in my other life
Retired; but they dragged me back in !

I live at UTC + 13.00

---
some people complain about loading the dishwasher.
Sometimes the question is more important than the answer.