Startseite

Über Jürgen A. Becker

Impressum

CAD-Dienstleistungen

Schulungsangebot

Archiv für die Kategorie „DotNet-Programmierung mit C#“

AutoCAD und .Net Framework - Globalisierung oder wie wird sprachunabhängig programmiert -

Freitag, 8. Januar 2010

Ich muss mein erstes Programm für unterschiedlichen Sprachen - englisch, tschechisch, deutsch etc. - zur Verfügung stellen. Das Programm wird u.a. in Toronto, Kanada eingesetzt, was mich schon ein wenig stolz macht.
Ich möchte hier die allgemeine Vorgehensweise für .Net-Programme erläutern, in einem späteren Post werde ich die globalisierung für eigene AutoCAD-Befehle erläutern.
Zunächst wird eine Resource-Datei für jede unterstützte Sprache erstellt. Diese Datei muss einen bestimmten Dateiname erhalten, damit .Net anhand der Windows-Ländereinstellung die zugehörige Sprachdatei erkennt.

Beispiel für deutsch (Deutschland):
[Assemblyname].de-DE.resx

Beispiel für englisch (England)
[Assemblyname.en-GB.resx

Wobei der Assemblyname frei wählbar ist.

Hier ein Beispiel einer Resource-Datei aus Visual C#.

Zunächst werden Variablen für die Instanzen der Klasse System.Resources.ResourceManager und der Klasse CultureInfo deklariert.

private System.Resources.ResourceManager hRM;
private CultureInfo hCI;

Mit Hilfe des Resourcemanager kann auf die Resource-Datei zugegriffen werden um den länderspezifischen Text zu ermitteln.

Im folgenden Beispiel möchte ich zunächst die Instanzierung der Klasse System.Resources.ResourceManager erläutern.

hRM = new
    System.Resources.ResourceManager("[Assemblyname].[Assemblyname]",
    System.Reflection.Assembly.GetExecutingAssembly());

Mit Hilfe der länderspezifischen Einstellung von Windows,

string hCultureName =
      System.Globalization.CultureInfo.CurrentCulture.Name;

wird der Kulturname ermittelt und dem Thread dieses mitgeteilt.

hCI = new CultureInfo("de-DE");
 System.Threading.Thread.CurrentThread.CurrentCulture = hCI;
 System.Threading.Thread.CurrentThread.CurrentUICulture = hCI;

Mit der Methode Getstring des Resourcemanager wird auf die Resourcedatei zugegriffen und der entsprechende Text ermittelt. Es ist darauf zu achten, dass diese Methode innerhalb eines Try-Blockes aufgerufen wird, damit bei einem Fehler das Programm nicht abstürzt.
Das folgende Beispiel ermittelt den Text “Wenden Sie sich bitte an Ihren Administrator!” aus der Resource-Datei.

hRM.Getstring("AdminContact");

Um alle Steuerelemente eines Dialoges zu übersetzen, nutze ich die Methode SetControlText. Diese Methode ruft sich selbst rekursive auf, da Steuerelemente selber Steuerelemente enthalten können.

private void SetControlText(Control Control)
{
Control hControl = Control;
foreach(Control hControlItem in hControl.Controls)
{
if (hControlItem.Text != null)
 {
  if (hControlItem.Text.Length > 0)
  {
   try
   {
     string hControlType = hControlItem.ToString();
     string[] hCTypeSplit = hControlType.Split(',');
                           
     if (hCTypeSplit[0] == "System.Windows.Forms.Label")
     {
       hControlItem.Text = hRM.GetString(hControlItem.Text) + ":";
     }
     else
     {
       hControlItem.Text = hRM.GetString(hControlItem.Text);
     }
   }
   catch(System.Exception e)
   {
                           
   }                       
  }                
 }
 this.SetControlText(hControlItem);
}          
}

Hier der vollständige Code:

hRM = new
  System.Resources.ResourceManager("[Assemblyname].[Assemblyname]",
  System.Reflection.Assembly.GetExecutingAssembly());
string hCultureName =
    System.Globalization.CultureInfo.CurrentCulture.Name;
switch (hCultureName)
{
 case "de-DE":
 case "de-LI":
 case "de-LU":
 case "de-AT":
 case "de-CH":
  hCI = new CultureInfo("de-DE");
  break;
 default:
  hCI = new CultureInfo("en-GB");
  break;
}
if (hCI != null)
{
 System.Threading.Thread.CurrentThread.CurrentCulture = hCI;
 System.Threading.Thread.CurrentThread.CurrentUICulture = hCI;
 this.SetControlText(this);
}

Viel Spaß beim Ausprobieren

Autor: Dipl.-Ing. Jürgen A. Becker
Kontakt: Juergen.Becker@CAD-Becker.de oder Juergen.Becker@AUGI.COM

  • Langjährige Schulungserfahrung
  • Autorisierter AutoCAD Trainer (AutoCAD, Mechanical Desktop etc.)
  • Software- und Datenbankentwicklung

AutoCAD 2010 und .Net-Framework - Verwalten von eigenen Daten innerhalb einer Zeichnung (Teil 6) -

Montag, 14. Dezember 2009

Es ist sinnvoll die einzelnen Methode, die zum Zugriff auf ein Dictionary notwendig sind in eine Klasse zusammenzufassen.

Alle Methoden, die in den vorherigen Artikel beschrieben wurden, wurden in diese Klasse einfügen.

Den vollständigen Code finden Sie im Folgenden:

using Microsoft.VisualBasic;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.GraphicsSystem;
using DatabaseServ = Autodesk.AutoCAD.DatabaseServices;
using TransMan = Autodesk.AutoCAD.DatabaseServices.TransactionManager;
namespace ACADUtility
{
 #region Objectdeclaration
  private SortedList hXRecords = null;
  private DBDictionary hDict = null;
  private DBDictionary hNod = null;
 #endregion

 #region string
  private string hXrecordPrefix = "";
  private string hDictName = "";
 #endregion

 #region Properties
  public SortedList XRecords
  {
   get { return hXRecords; }
  }
  public DBDictionary Dictionary
  {
   get{return hDict;}
  }
  public DBDictionary NamedObjectDictionary
  {
  get{return hNod;}
  }
  public string DictionaryName
  {
   get{return hDictName;}
  }
  public string XRecordPrefix
  {
  get{return hXrecordPrefix;}
  }
 #endregion

 public clsDictionary(string DictName, string XRecordPrefix)
 {
  hXrecordPrefix = XRecordPrefix;
  hDictName = DictName;
 }

 public void AddDictionary(){ }
 public void AddXRecord(ResultBuffer ResBuffer, string XrecordName){}
 public Xrecord ReadXrecord(string XRecordName){}
 public SortedList ReadXRecords(){}
 public void RemoveXRecord (string XRecordName){}

}

Viel Spaß beim Ausprobieren

Autor: Dipl.-Ing. Jürgen A. Becker
Kontakt: Juergen.Becker@CAD-Becker.de oder Juergen.Becker@AUGI.COM

  • Langjährige Schulungserfahrung
  • Autorisierter AutoCAD Trainer (AutoCAD, Mechanical Desktop etc.)
  • Software- und Datenbankentwicklung

AutoCAD 2010 und .Net-Framework - Verwalten von eigenen Daten innerhalb einer Zeichnung (Teil 4) -

Montag, 7. Dezember 2009

Als Fortsetzung zum vorherigen Post möchte ich in diesem Artikel das Lesen aus dem Dictionary erläutern. Hier ein Beispiel, dass die XRecords als SortedList - eine Collections des Namespace System.Collections - als Wert zurückgibt.

Das Problem beim NamedObjectDictionary ist, dass die einzelnen XRecords per Name angesprochen werden müssen. Da in den meisten Fällen ein Name nicht bekannt ist, muss das Dictionary über eine Enumerierung - GetEnumerator eine Methode des Dictionary - durchsucht werden.

Mit einer while-Schleife wird das Dictionary durchlaufen.

DbDictionaryEnumerator hDictEnum = hDict.GetEnumerator();
while(hDictEnum.MoveNext())
{
    ObjectId hObjectID = hDictEnum.Current.Value;
    try
    {
      Xrecord hXr = (Xrecord)hTr.GetObject(hObjectID, OpenMode.ForRead);
      hXRecords.Add(hXr.ObjectId.ToString(), hXr);
    }
    catch (System.Exception e)
    {
      System.Windows.Forms.MessageBox.Show(e.Message);
    }
}

Die Anweisung

ObjectId hObjectID = hDictEnum.Current.Value;

liest die ObjectId des XRecords aus und mit

Xrecord hXr = (Xrecord)hTr.GetObject(hObjectID, OpenMode.ForRead);

wird der XRecord bestimmt. Dieser wird dann als Objekt in die SortedList gespeichert.

hXRecords.Add(hXr.ObjectId.ToString(), hXr);

In der Anwendung kann der Rückgabe-Wert - eine SortedList - einfacher bearbeitet werden. Da die ObjectID des XRecords als Key genutzt wurde.

Hier der vollständige Code.

using AcAp = Autodesk.AutoCAD.ApplicationServices;
.
.
.

public SortedList ReadXRecords()
{
 hXRecords = new SortedList();
 Database db =
    AcAp.Application.DocumentManager.MdiActiveDocument.Database;
 Transaction hTr = db.TransactionManager.StartTransaction();
 hNod = (DBDictionary)hTr.GetObject(
    db.NamedObjectsDictionaryId,
    OpenMode.ForWrite);
 if (hNod.Contains(hDictName) == true)
 {
  try {
   hDict = (DBDictionary)hTr.GetObject(
      hNod.GetAt(hDictName),
      OpenMode.ForRead);
   DbDictionaryEnumerator hDictEnum = hDict.GetEnumerator();
   while(hDictEnum.MoveNext())
   {
    ObjectId hObjectID = hDictEnum.Current.Value;
    try
    {
      Xrecord hXr = (Xrecord)hTr.GetObject(hObjectID, OpenMode.ForRead);
      hXRecords.Add(hXr.ObjectId.ToString(), hXr);
    }
    catch (System.Exception e)
    {
      System.Windows.Forms.MessageBox.Show(e.Message);
    }
  }
 }
 catch (System.Exception e)
 {
  System.Windows.Forms.MessageBox.Show(e.Message);
 }
}
hTr.Commit();
return hXRecords;
}

Viel Spaß beim Ausprobieren

Autor: Dipl.-Ing. Jürgen A. Becker
Kontakt: Juergen.Becker@CAD-Becker.de oder Juergen.Becker@AUGI.COM

  • Langjährige Schulungserfahrung
  • Autorisierter AutoCAD Trainer (AutoCAD, Mechanical Desktop etc.)
  • Software- und Datenbankentwicklung

AutoCAD 2010 und .Net-Framework - Verwalten von eigenen Daten innerhalb einer Zeichnung (Teil 3) -

Freitag, 27. November 2009

Im vorherigen Artikel haben ich über das Anlagen eines NamedObjectDictionary und das Speichern vont User-Einträgen in dieses Dictionary geschrieben. Mit dem heutigen Artikel möchte ich das Löschen von Einträgen eines Dictionaries erläutern.

Die Methode REMOVE des Dictionary mit dem Name des Eintrags als Parameter löscht einen Eintrag aus dem Dictionary.
Eher unspektakulär.

public void RemoveXRecord (string XRecordName)
{
Database db =
    AcAp.Application.DocumentManager.MdiActiveDocument.Database;
Transaction hTr = db.TransactionManager.StartTransaction();
   
hNod =
(DBDictionary)hTr.GetObject(
                               db.NamedObjectsDictionaryId,
                               OpenMode.ForWrite);
           
string hXRecordName = XRecordName;
if (hNod.Contains(hDictName) == true)
{
 hDict = (DBDictionary)hTr.GetObject(
                               hNod.GetAt(hDictName),
                               OpenMode.ForWrite);
 if (hDict.Contains(hXRecordName) == true)
 { 
  hDict.Remove(hXRecordName);
 }
}
hTr.Commit();
}

Viel Spaß beim Ausprobieren

Autor: Dipl.-Ing. Jürgen A. Becker
Kontakt: Juergen.Becker@CAD-Becker.de oder Juergen.Becker@AUGI.COM

  • Langjährige Schulungserfahrung
  • Autorisierter AutoCAD Trainer (AutoCAD, Mechanical Desktop etc.)
  • Software- und Datenbankentwicklung

AutoCAD 2010 und .Net-Framework - Verwalten von eigenen Daten innerhalb einer Zeichnung (Teil 2) -

Donnerstag, 26. November 2009

In einem vorherigen Post habe ich das Verwalten von eigenen Daten innerhalb einer Zeichnung mit Hilfe der Extended Entity Data (EED) erläutert.

In diesem Artikel werde ich eine weitere Möglichkeit nämlich die Nutzung von Dictionaries (NamedObjectDictionary) erläutert.

Ist das Speichern der Daten als EED immer abhängig von einem Objekt, können Daten in ein Dictionary unabhängig von einem Objekt gespeichert werden. Es werden Daten in ein NamedobjectDIctionary gespeichert.

Im Übrigen: Das Speichern von EED’s ist nicht nur an grafischen Objekten möglich, es können auch an nicht-grafische Objekte wie Linientypen, Layer etc. EED’s angehängt werden. Der Layer 0 ist für das Speicher sehr gut geignet, da er in jeder Zeichnung vorhanden sein muss.

Zunächst wird ein Dictionary-Objekt erzeugt, welches die Daten des NamedObjectDictionary enthält. Bitte achten Sie auf den Open-Modus, hier in diesem Beispiel wird das Dictionary zum shcreiben geöffnet.

Database db =
  Application.DocumentManager.MdiActiveDocument.Database;
Transaction hTr = db.TransactionManager.StartTransaction();
   
DBDictionary hNod =
 (DBDictionary)hTr.GetObject
    (db.NamedObjectsDictionaryId, OpenMode.ForWrite);

Ist das NamedObjectDictionary-Objekt erstellt, wird ein Benutzerdefiniertes Dictionary-Objekt erstellt. Wichtig dabei ist, dass vorab mit der Methode CONTAINS des NamedObjectDictionary überprüft wird, ob das neue Dictionary vorhanden ist. Ist es nicht vorhanden wird es erstellt ansonsten das vorhandene über die Methode GETAT des NamedObjectDictionary-Objekt ermittelt.

DBDictionary hDict = null;
if (!hNod.Contains(hDictKey))
{
  hDict = new DBDictionary();
  hNod.SetAt(hDictKey, hDict);
  hTr.AddNewlyCreatedDBObject(hDict, true);
}
else
{
  try
  {
    hDict = (DBDictionary)hTr.GetObject(
    hNod.GetAt(hDictKey), OpenMode.ForWrite);
  }
  catch
  {

  }
}

Die Daten werden vor Aufruf der Methode ADDXRecord als Resultbuffer aufbereitet und dann mit den weiteren Übergabeparameter der Methode übergeben.

ResultBuffer hRb = new ResultBuffer();
hRb.Add(new TypedValue((int)DxfCode.Text, "Erster Text"));
hRb.Add(new TypedValue((int)DxfCode.Text, "Zweiter Text"));

Innerhalb der Routine werden dem ResultBuffer weitere Daten hinzugefügt.

  • Die Objekt-ID des namedObjectDictionary-Objektes
  • Das Handle des benutzerdefinierten Dictionary
hRb.Add(new TypedValue((int)DxfCode.SoftPointerId, hNod.ObjectId));
hRb.Add(new TypedValue((int)DxfCode.Handle, hDict.Handle));

Die Daten werden in Form eines XRecord mit der Methode SETAT des Dictionary in das Dictionary geschrieben.

Xrecord hXr = new Xrecord();
hXr.Data = hRb;          
hDict.SetAt(hXrecPrefix + hXRecordCount.ToString(), hXr);
hTr.AddNewlyCreatedDBObject(hXr, true);

Hier die Methode zum Speichern von Daten in das Dictionary.
Die Übergabeparameter sind:

  • Dictionary-Name
  • Eine Präfix für den Namen des XRecord
  • Die Daten als ResultBuffer
using AcAp = Autodesk.AutoCAD.ApplicationServices;
.
.
.
public void AddXRecord(
    string DictName,
    string XRecordPrefix,
    ResultBuffer ResBuffer)
{
 Database db =
     Application.DocumentManager.MdiActiveDocument.Database;
 Transaction hTr = db.TransactionManager.StartTransaction();
   
 DBDictionary hNod =
  (DBDictionary)hTr.GetObject(
         db.NamedObjectsDictionaryId, OpenMode.ForWrite);
   
 string hDictKey = DictName;
 string hXrecPrefix = XRecordPrefix;
 int hXRecordCount = 0;
 ResultBuffer hRb = ResBuffer;
           
 DBDictionary hDict = null;
 if (!hNod.Contains(hDictKey))
 {
   hDict = new DBDictionary();
   hNod.SetAt(hDictKey, hDict);
   hTr.AddNewlyCreatedDBObject(hDict, true);
 }     
 else
 {
   try
  {
    hDict = (DBDictionary)hTr.GetObject(
          hNod.GetAt(hDictKey), OpenMode.ForWrite);
    hXRecordCount = hDict.Count;
   }
   catch (System.Exception e)
   {
    System.Windows.Forms.MessageBox.Show(e.Message);   
   }
 }
 try
 {
   hRb.Add
    (new TypedValue((int)DxfCode.SoftPointerId, hNod.ObjectId));
   hRb.Add
    (new TypedValue((int)DxfCode.Handle, hDict.Handle));
   
   Xrecord hXr = new Xrecord();
   hXr.Data = hRb;
               
   hDict.SetAt(hXrecPrefix + hXRecordCount.ToString(), hXr);
   hTr.AddNewlyCreatedDBObject(hXr, true);
 }
 catch (System.Exception e)
 {
   System.Windows.Forms.MessageBox.Show(e.Message);
 }
 hTr.Commit();
}

In einen der nächsten Artikel werde ich das Auslesen der Daten aus einem Dictionary beschreiben.

Viel Spaß beim Ausprobieren

Autor: Dipl.-Ing. Jürgen A. Becker
Kontakt: Juergen.Becker@CAD-Becker.de oder Juergen.Becker@AUGI.COM

  • Langjährige Schulungserfahrung
  • Autorisierter AutoCAD Trainer (AutoCAD, Mechanical Desktop etc.)
  • Software- und Datenbankentwicklung

AutoCAD und .Net-Framework - Polar-Koordinate -

Dienstag, 17. November 2009

Das Programmieren einer polaren Koordinate ist in der .Net API nicht ganz so einfach, wie es in Visual Lisp möglich ist.
Visual Lisp-Beispiel:

(setq P2 (polar p2 Angle Distance))

In C# unter der Zuhilfenahme der Klasse Math.

static Point2d PolarPoints(Point2d pPt,
                                   double dAng,
                                   double dDist)
{
  return new Point2d(pPt.X + dDist * Math.Cos(dAng),
                     pPt.Y + dDist * Math.Sin(dAng));
}

Viel Spaß bei Ausprobieren
Ihr Jürgen A. Becker

AutoCAD und .Net-Framework - Berechnung einer Distanz und eines Winkels -

Dienstag, 10. November 2009

Hier möchte ich ein kleines Code-Snippet vorstellen, das den Abstand zweier Punkte und den Winkel zwischen diesen beiden Punkten berechnet.

Zunächst werden zwei Punkte (1: 60,80 und 2: 90,120) definiert.

Autodesk.AutoCAD.Geometry.Point2d hP1 =
     new Autodesk.AutoCAD.Geometry.Point2d(60.0, 80.0);
Autodesk.AutoCAD.Geometry.Point2d hP2 =
     new Autodesk.AutoCAD.Geometry.Point2d(90.0, 120.0);

Laut Pythagoras ist der Abstand 50 und der Winkel liegt bei 53°.

Es existieren zwei Methoden um den Abstand zwischen zwei Punkten zu berechnen.

  • Mit der Methode “GetDistanceTo” eines Point2D-Objektes und dem zweiten Punkt als Parameter
    double hDist = hP1.GetDistanceTo(hP2);
    ed.WriteMessage("\nAbstand : " + hDist.ToString());
  • Es wird ein 2D-Vektor erzeugt und die Länge dieses Vektors berechnet.
    Autodesk.AutoCAD.Geometry.Vector2d vec = hP2 - hP1;
    ed.WriteMessage("\nVektor-Länge : " + vec.Length.ToString());

Der Winkel kann aus der Eigenschaft “Angle” dieses Vektors in Bogenmaß entnommen werden. Der Winkel sollte - wenn er angezeigt wird - in Grad umgerechnet werden (Winkel *180 / PI), für Berechnungen innerhalb einer Funktion MUSS er in Bogenmaß beibehalten werden.

Die Zahl PI steht in der Klasse System.Math als double-Wert zur Verfügung.

double hAngle = vec.Angle * 180 / Math.PI;
ed.WriteMessage("\nVektor-Winkel : " + hAngle.ToString());

Hier der vollständige Code:

using AcAp = Autodesk.AutoCAD.ApplicationServices.Application;
.
.
.
[CommandMethod("GetDist")]
public void GetDist()
{
  Autodesk.AutoCAD.Geometry.Point2d hP1 =
     new Autodesk.AutoCAD.Geometry.Point2d(60.0, 80.0);
  Autodesk.AutoCAD.Geometry.Point2d hP2 =
     new Autodesk.AutoCAD.Geometry.Point2d(90.0, 120.0);
  Editor ed = DocumentManager.MdiActiveDocument.Editor;
  double hDist = hP1.GetDistanceTo(hP2);
 
  ed.WriteMessage("\nAbstand : " + hDist.ToString());

  Autodesk.AutoCAD.Geometry.Vector2d vec = hP2 - hP1;
  ed.WriteMessage("\nVektor-Länge : " + vec.Length.ToString());
  double hAngle = vec.Angle * 180 / Math.PI;
  ed.WriteMessage("\nVektor-Winkel : " + hAngle.ToString());
}

Viel Spaß beim Ausprobieren

Autor: Dipl.-Ing. Jürgen A. Becker
Kontakt: Juergen.Becker@CAD-Becker.de oder Juergen.Becker@AUGI.COM

  • Langjährige Schulungserfahrung
  • Autorisierter AutoCAD Trainer (AutoCAD, Mechanical Desktop etc.)
  • Software- und Datenbankentwicklung

.Net-Framework - XData: Verwalten von eigenen Daten innerhalb einer Zeichnung -

Dienstag, 22. September 2009

Werden eigene technische Daten von Bauteilen innerhalb der Zeichnung gespeichert, werden häufig Attribute genutzt.

Die Nutzung von Attributen ist insofern problematisch, weil die Bauteile Blöcke sein müssen. Außerdem sind die Attribute editierbar, dieses ist in vielen Fällen nicht gewünscht.

Ich möchte hier eine Möglichkeit vorstellen, die diese Probleme löst.

Die Nutzung der Extended Entity Datas ist eine gute Alternative. Jedes Objekt der Zeichnung inkl. Layer, Linientypen, Blockdefinitionen etc. besitzen die Eigenschaft XData. Der Datentyp dieser Eigenschaft ist Autodesk.AutoCAD.DatabaseServices.ResultBuffer.

Leider hat diese Methode einen kleinen Nachteil: Die Menge der Daten ist auf 16kByte begrenzt.

Das folgende Bild zeigt den Inhalt eines ResultBuffers.

ResultBuffer

ResultBuffer

Das folgende Beispiel zeigt eine Klasse, die verschiedene Methoden zum Schreiben und Lesen der Extended Entity Datas bereitstellt.

using System;

#region AutoCAD
 using AcAp = Autodesk.AutoCAD.ApplicationServices;
 using Autodesk.AutoCAD.DatabaseServices;
 using Autodesk.AutoCAD.EditorInput;
 using Autodesk.AutoCAD.Runtime;
#endregion

namespace ACAD_Utility
{
 public class clsXData
 {
  public clsXData()
  {
  }

  public TypedValue GetXData
   (ObjectId ObjectID, string ApplicationName)..

  public ResultBuffer GetXData(ObjectId ObjectID)...

  public int SetXData
    (ObjectId ObjectID, string ApplicationName, string Value)...

  public void AddRegAppTableRecord(string RegAppName)...

 }
}

Nachfolgend die Codebeispiele der obigen Methoden.

Diese Methode registriert den Applikationsnamen in der Zeichnung dann, wenn er nicht registriert ist. Der dafür erforderliche Applikationsname wird als Parameter übergeben.

public void AddRegAppTableRecord(string RegAppName)
{
 Document doc =
   AcAp.Application.DocumentManager.MdiActiveDocument;
 Editor ed = doc.Editor;
 Database db = doc.Database;

 Transaction hTr = doc.TransactionManager.StartTransaction();

 using (hTr)
 {
   RegAppTable hRegTable = (RegAppTable)hTr.GetObject(
      db.RegAppTableId,
      OpenMode.ForRead,
      false
   );
   if (!hRegTable.Has(RegAppName))
   {
     hRegTable.UpgradeOpen();
     RegAppTableRecord hRegTableRecord =
        new RegAppTableRecord();
     hRegTableRecord.Name = RegAppName;

     hRegTable.Add(hRegTableRecord);
     hTr.AddNewlyCreatedDBObject(hRegTableRecord, true);
   }
   hTr.Commit();
 }
}

Um Daten als Extended Entity Data abzuspeichern, wird zunächst der Applikationsname registriert und ein Resultbuffer aus dem Applikationsnamen und der Wert erstellt.
Das Objekt, erstellt aus der ObjektID implementiert die Eigenschaft XData, die dem Resultbuffer gleich gesetzt wird.

Die Übergabeparameter sind:

  • ObjektID, die aus einer Objektwahl gebildet wird
  • der Applikationsname
  • der Wert
public int SetXData(
    ObjectId ObjectID,
    string ApplicationName,
    string Value)
{
 Document doc =
   AcAp.Application.DocumentManager.MdiActiveDocument;
 Editor ed = doc.Editor;

 Transaction hTr = doc.TransactionManager.StartTransaction();
 using (hTr)
 {
  try
  {
   AddRegAppTableRecord(ApplicationName);
   ResultBuffer hResBuffer = new ResultBuffer(
     new TypedValue(1001, ApplicationName),
     new TypedValue(1000, Value)
   );
   DBObject hObject = hTr.GetObject(
     ObjectID,
     OpenMode.ForWrite
   );

   hObject.XData = hResBuffer;
   hResBuffer.Dispose();
   hTr.Commit();
 }
 catch
 {
   return 1;
 }
 return 0;
}

In der Klasse clsXData ist die überladene Methode GetXData implementiert.
Diese Methode gibt einmal ein ResultBuffer als Ergebnis zurück, oder ein TypedValue, der den Wert des Applikationsnamens enthält.
Für das Ergebnis als ResultBuffer ist die ObjektID, die aus der Objektwahl gebildet wird erforderlich.
Für das Ergebnis als TypedValue ist die ObjektID und der Applikationsname erforderlich.

public ResultBuffer GetXData(ObjectId ObjectID)
{
 Document doc =
   AcAp.Application.DocumentManager.MdiActiveDocument;
 Editor ed = doc.Editor;

 Transaction hTr = doc.TransactionManager.StartTransaction();

 using (hTr)
 {
   DBObject hObject = hTr.GetObject(
      ObjectID,
      OpenMode.ForRead
   );

   return hObject.XData;
 }
}

Die Methode, die ein TypedValue zurückgibt ist um einiges komplexer, da der ResultBuffer nach dem Applikationsnamen durchsucht werden muss. Dieses geschieht innerhalb einer foreach-Schleife.

Wird der Applikationsname gefunden, wird ein boolscher Wert auf true gesetzt und die foreach ein weiteres Mal durchlaufen, damit der Wert des Applikationsnamens gefunden wird. Danach wird die foreach-Schleife durch eine break-Anweisung beendet.

Ist innerhalb der foreach-Schleife der Applikationsname gefunden worden, wird ein boolscher Wert auf true gesetzt. Ist dieser Wert true, kann innerhalb einer switch-Anweisung das neue TypedValue erzeugt werden.

public TypedValue GetXData(
  ObjectId ObjectID,
  string ApplicationName)
{
 TypedValue tv2 = new TypedValue();
 Document doc =
   AcAp.Application.DocumentManager.MdiActiveDocument;
 Editor ed = doc.Editor;

 Transaction hTr = doc.TransactionManager.StartTransaction();

 using (hTr)
 {
  DBObject hObject = hTr.GetObject(
    ObjectID,
    OpenMode.ForRead
  );
  ResultBuffer hResBuffer = hObject.XData;
  bool hFound = false;
  if (hResBuffer != null)
  {
   bool hFoundStart = false;
   foreach (TypedValue tv in rb)
   {
    if (tv.TypeCode ==
      (int)DxfCode.ExtendedDataRegAppName &&
      tv.Value.ToString() == ApplicationName)
    {
      hFoundStart = true;
    }
    else
    {
     if (hFoundStart)
     {
      switch (tv.TypeCode)
      {
        case (int)DxfCode.ExtendedDataAsciiString:
         hFound = true;
         tv2 = new TypedValue(
           (int)DxfCode.ExtendedDataAsciiString, tv.Value
         );
         break;
       }
       if (hFound == true)
       {
        break;
       }
      }
     }
    }
    rb.Dispose();
   }
  }
  return tv2;
}

Im nächsten Artikel werde ich die Nutzung dieser Klasse erläutern.

Viel Spaß beim Ausprobieren

Autor: Dipl.-Ing. Jürgen A. Becker
Kontakt: Juergen.Becker@CAD-Becker.de oder Juergen.Becker@AUGI.COM

  • Langjährige Schulungserfahrung
  • Autorisierter AutoCAD Trainer (AutoCAD, Mechanical Desktop etc.)
  • Software- und Datenbankentwicklung

.Net-Framework - Dokumentationen oder bauen wir uns eine Sandburg -

Dienstag, 15. September 2009


Vielen Programmierern ist das Dokumentieren der eigenen Sourcen zuwider, lästig und umständlich. Mir geht es da nicht anders.
Allerdings geht bei den heutigen Programmier-Projekten kein Weg an einer sauberen Dokumentation vorbei.

Aus diesem Grunde habe ich versucht eine Lösung zu finden, die ich hier vorstellen möchte.

Das freie Programm Sandcastle Help File Builder dokumentiert eigene Sourcen anhand der XML-Dokumentation im Sourcescode.

Sandcastle Help File Builder

Sandcastle Help File Builder

Einstellungen im Visual Studio

Im Visual Studio wird in den Projekteigenschaften eines jeden Projektes die xml-Dokumentation eingeschaltet und die Ausgabedatei definiert.

Projekteigenschaft: xml-Dokumentation einschalten

Projekteigenschaft: xml-Dokumentation einschalten

 
Jede public Eigenschaft, Methode oder Event/ Delegate müssen kommentiert bzw. dokumentiert werden. Dieses geschieht mit Hilfe der Dokumentation-Tag “summary”. Die Vorgehensweise ist recht simpel.

Die public Eigenschaft, Methode oder Event/ Delegate implementieren. In der Zeile vor public drei Schrägstriche “///” schreiben, danach wird automatisch der summary-Tag, gegebenenfalls der returns-Tag und die Parameter-Tags eingefügt.

Zwischen den Anfang (<summary>) und Ende-Tag (</summary>) werden die Kommentare oder Dokumentationen implementiert.

Eine Dokumentation-Konvention stellt dynicity.com zur Verfügung.

Hier ein Beispiel für die Dokumentation einer Eigenschaft.
Folgende Zeilen vor unten stehende Eigenschaft einfügen.
/// <summary>
/// Copyright-Attribut der Assembly zurückgeben
/// </summary>
/// <returns>
/// string: Copyright-Vermerk
/// </returns>

public string Copyright {
  get {
    AssemblyCopyrightAttribute[] m_Copyright;
    m_Copyright =
      (AssemblyCopyrightAttribute[])hAsmInfo.GetCustomAttributes
        (typeof (AssemblyCopyrightAttribute), false);
    if (m_Copyright != null)
   {
     return m_Copyright[0].Copyright;
   }
   else
   {
     return "";
   }
  }
}

Einstellungen Im Sandcastle Help File Builder
Im Sandcastle Help File Builder werden die zu dokumentierenden Sourcen hinzugefügt und die Projekteigenschaften eingestellt.

Sourcen zum Dokumentieren hinzufügen

Sourcen zum Dokumentieren hinzufügen

Das Erstellen der Dokumentation geschieht im Menü “Dokumentation”.

Dokumentation starten

Dokumentation starten

Das Ergebnis

Die Dokumentation

Die Dokumentation

Viel Spaß beim Ausprobieren

Autor: Dipl.-Ing. Jürgen A. Becker
Kontakt: Juergen.Becker@CAD-Becker.de oder Juergen.Becker@AUGI.COM

  • Langjährige Schulungserfahrung
  • Autorisierter AutoCAD Trainer (AutoCAD, Mechanical Desktop etc.)
  • Software- und Datenbankentwicklung

.Net-Framework - Maßstabsliste auslesen und ermitteln eines Maßstabes -

Sonntag, 13. September 2009

Seid der AutoCAD 2008 kennen wir die Maßstabsliste. Sie ist Bestandteil der Zeichnung und kann somit von Zeichnung zu Zeichnung variieren.

Diese Maßstabsliste wird in vielen Funktionen im AutoCAD genutzt z.B. Plotten, Ansichtsfenster und für die Definition der Beschriftungsmaßstäbe eines Beschriftungsobjekte.

Hier wird eine kleine Methode vorgestellt, die einen Maßstab aus der Maßstabsliste ausliest.

Die Maßstabsliste ist in der Kontext-Collection mit dem Namen “ACDB_ANNOTATIONSCALES” gespeichert.

Die folgende Methode gibt einen Maßstab anhand eines Namens zurück.

Die Methode des ObjectContextManager “GetContextCollection” gibt anhand des Namens des Kontextes die Collection zurück. Diese Collection bietet mit der Methode “GetContext” die Möglichkeit mit dem Namen ein Object in dieser Collection zurückzugeben.

Hier die Methode:

#region Usings für AutoCAD
    using Autodesk.AutoCAD;
    using Autodesk.AutoCAD.Runtime;
    using AcAp = Autodesk.AutoCAD.ApplicationServices;
    using Autodesk.AutoCAD.DatabaseServices;
    using Autodesk.AutoCAD.EditorInput;
#endregion

                     .
                     .
                     .

public AnnotationScale GetAnnotation(string AnnotationName)
{
  AnnotationScale hAnnotation = null;
  if (AnnotationName.Length > 0)
 {
    AcAp.Document doc =
      AcAp.Application.DocumentManager.MdiActiveDocument;
    Database db = doc.Database;
    Editor ed = doc.Editor;
       
    ObjectContextManager hObjectConMan =
       db.ObjectContextManager;
                   
    if (hObjectConMan != null)
    {
      ObjectContextCollection hObjectConCol =
        hObjectConMan.GetContextCollection
                 ("ACDB_ANNOTATIONSCALES");
      if (hObjectConCol != null)
      {
        hAnnotation =
           (AnnotationScale)hObjectConCol.GetContext
                         (AnnotationName);
      }
   }
 }
 return hAnnotation;
}

Viel Spaß beim Ausprobieren

Autor: Dipl.-Ing. Jürgen A. Becker
Kontakt: Juergen.Becker@CAD-Becker.de oder Juergen.Becker@AUGI.COM

  • Langjährige Schulungserfahrung
  • Autorisierter AutoCAD Trainer (AutoCAD, Mechanical Desktop etc.)
  • Software- und Datenbankentwicklung