Kean Walmsley


  • About the Author
    Kean on Google+

August 2014

Sun Mon Tue Wed Thu Fri Sat
          1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
31            








« DevLabs in Beijing, Bangalore & Las Vegas(?) | Main | First Portuguese DevTV session: Introdução à Programação AutoCAD.NET »

August 12, 2009

Hosting WPF content inside an AutoCAD palette

OK, OK: I know I said I’d talk more about overrules, last week, but – as is often the way, I’m afraid to say – I got distracted. The good news, though, is that I got distracted by something genuinely interesting, and well worth sharing.

I’ve been working on upgrading the WinForms user interface of an existing .NET application to use WPF, the Windows Presentation Foundation. For those wanting a thorough grounding in WPF, I recommend watching Fenton Webb’s highly-rated webcast series on WPF, just one of the interesting webcasts that can be downloaded and viewed from our API training schedule:

AutoCAD: Using WPF in your Applications - Part 1 (28.9 Mb)

AutoCAD: Using WPF in your Applications - Part 2 (16.3 Mb)

In this post I’m going to walk through creating a simple WPF User Control which we can then host inside an AutoCAD PaletteSet.

Firstly we need to add a WPF User Control to our Visual Studio 2008 (or higher) project:

Adding a WPF User Control to our project

We’ll accept the default name for the purposes of this project.

Now we should see our blank user-control hosted in both a designer window and a XAML editing pane:

Our empty WPF User Control

For the content of our user-control, I decided to take a static 2D image and apply some effects to it, inspired by this page, which also has a thorough explanation of the various effects applied (which saves me from doing the same :-).

You can copy & paste this XAML into the editing pane:

<UserControl x:Class="WPF_Palette.UserControl1"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Height="380" Width="300">

  <StackPanel Background="Gray">

    <Border BorderBrush="OldLace" BorderThickness="10" CornerRadius="10"

            HorizontalAlignment="Center" VerticalAlignment="Center">

      <Image Source="TTIF.png" Width="200" Height="200"

             Stretch="Fill" x:Name="blogImage" />

      <Border.RenderTransform>

        <SkewTransform CenterX="250" CenterY="0"

                       AngleX="0" AngleY="350" />

      </Border.RenderTransform>

    </Border>

    <Border Width="220" Height="300" BorderThickness="10"

            CornerRadius="10" BorderBrush="OldLace">

      <Border.Background>

        <VisualBrush Visual="{Binding ElementName=blogImage}">

          <VisualBrush.Transform>

            <ScaleTransform ScaleX="1" ScaleY="-1"

                            CenterX="200" CenterY="150" />

          </VisualBrush.Transform>

        </VisualBrush>

      </Border.Background>

      <Border.OpacityMask>

        <LinearGradientBrush StartPoint="0,0" EndPoint="0,1">

          <GradientStop Offset="0" Color="Black" />

          <GradientStop Offset="0.3" Color="Transparent" />

        </LinearGradientBrush>

      </Border.OpacityMask>

      <Border.RenderTransform>

        <SkewTransform CenterX="260" CenterY="0"

                       AngleX="40" AngleY="350" />

      </Border.RenderTransform>

    </Border>

  </StackPanel>

</UserControl>

For this to work, I added a simple screenshot of this blog as an item in the project, calling it “TTIF.png”. I simply added it to the project via the Solution Explorer, using Add –> Existing Item… no need to create a resource.

Now we should see our User Control has taken shape:

Our edited WPF User Control

Now it’s simply a matter of defining a command to create a PaletteSet to host our WPF content:

using Autodesk.AutoCAD.Runtime;

using Autodesk.AutoCAD.Windows;

using System.Drawing;

using System.Windows.Forms;

using System.Windows.Forms.Integration;

 

namespace WPF_Palette

{

  public class Commands

  {

    static PaletteSet _ps = null;

 

    [CommandMethod("WPFP")]

    public void ShowWPFPalette()

    {

      if (_ps == null)

      {

        // Create the palette set

 

        _ps = new PaletteSet("WPF Palette");

        _ps.Size = new Size(400, 600);

        _ps.DockEnabled =

          (DockSides)((int)DockSides.Left + (int)DockSides.Right);

 

        // Create our first user control instance and

        // host it on a palette using AddVisual()

 

        UserControl1 uc = new UserControl1();

        _ps.AddVisual("AddVisual", uc);

 

        // Create our second user control instance and

        // host it in an ElementHost, which allows

        // interop between WinForms and WPF

 

        UserControl1 uc2 = new UserControl1();

        ElementHost host = new ElementHost();

        host.AutoSize = true;

        host.Dock = DockStyle.Fill;

        host.Child = uc2;

        _ps.Add("Add ElementHost", host);

      }

 

      // Display our palette set

 

      _ps.KeepFocus = true;

      _ps.Visible = true;

    }

  }

}

For the application to build you’ll need to add project references to the .NET assemblies System.Drawing and WindowsFormsIntegration (in addition to the usual AcMgd.dll and AcDbMgd.dll, of course).

The above code deliberately adds two instances of our control into the PaletteSet, to show the different techniques for doing so:

  1. The first uses the new (to AutoCAD 2010) AddVisual() method to add in our WPF User Control into a Palette
    • This works, but doesn’t dock the control inside the palette (something I hope to see addressed in the future – as it stands this isn’t particularly useful)
  2. The second uses an ElementHost to host our WPF User Control – essentially hosting our WPF control in one that works with a WinForms UI. We then use the standard Add() method to add it, as we have done in the past

Now the application should build. When we NETLOAD it into AutoCAD and run the WPFP command, we should see our docked palette set with the first tab visible:

Our first WPF Palette inside AutoCAD

We can see that this tab hosts our control, but it doesn’t fill the palette.

If we select the second tab, we see things are better, there:

Our second WPF Palette inside AutoCAD

If you undock the palette set you can see more easily the way the control is hosted by each palette.

I’m still on the steep part of the learning curve with respect to WPF (and expect I’ll be there for some time), but so far I’m really impressed with its capabilities, especially around binding a user-interface’s properties to the data it hosts. I’ll be sharing more of my findings related to WPF in due course.

TrackBack

TrackBack URL for this entry:
http://www.typepad.com/services/trackback/6a00d83452464869e20120a4eab7a5970b

Listed below are links to weblogs that reference Hosting WPF content inside an AutoCAD palette:

blog comments powered by Disqus

10 Random Posts