TheSwamp

Code Red => .NET => Topic started by: Coder on January 21, 2016, 07:57:10 AM

Title: WPF and AutoCAD
Post by: Coder 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 .


Title: Re: WPF and AutoCAD
Post by: Coder 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.
Title: Re: WPF and AutoCAD
Post by: gile 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.  
Title: Re: WPF and AutoCAD
Post by: cvcolomb 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;
            }
Title: Re: WPF and AutoCAD
Post by: Coder 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
Title: Re: WPF and AutoCAD
Post by: gile 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.
Title: Re: WPF and AutoCAD
Post by: MexicanCustard 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.
Title: Re: WPF and AutoCAD
Post by: gile 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 ?
Title: Re: WPF and AutoCAD
Post by: gile 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.
Title: Re: WPF and AutoCAD
Post by: Coder 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 !

Title: Re: WPF and AutoCAD
Post by: gile 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.
Title: Re: WPF and AutoCAD
Post by: Coder 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.
Title: Re: WPF and AutoCAD
Post by: gile 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.
Title: Re: WPF and AutoCAD
Post by: Coder on January 25, 2016, 12:42:43 AM
Great job gile.

I have working now , many thanks.
Title: Re: WPF and AutoCAD
Post by: Coder 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
Title: Re: WPF and AutoCAD
Post by: kdub_nz 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.




Title: Re: WPF and AutoCAD
Post by: Coder 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:
Title: Re: WPF and AutoCAD
Post by: CADbloke on January 28, 2016, 04:32:53 AM
(http://d22zlbw5ff7yk5.cloudfront.net/images/cm-50190-9511cbdf4410a9.jpeg)


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 (https://github.com/Reactive-Extensions) , http://www.introtorx.com/ is probably the best place to start.
Title: Re: WPF and AutoCAD
Post by: kdub_nz 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 (https://github.com/Reactive-Extensions) , http://www.introtorx.com/ is probably the best place to start.

:-)
Quote from: http://docs.reactiveui.net/en/fundamentals/functional-reactive-programming.html
Functional reactive programming is the peanut butter and chocolate of programming paradigms.