script

Symbol per API erstellen

In einem aktuellen Kundenprojekt werden Bediensymbole (Piktogramme) per DXF-Dateien eingelesen und in einer eigenen Symbolbibliothek abgespeichert.
Generell empfehlen wir keine eigene Symbolbibliothek zu machen. Für diesen Anwendungsfall ist es aber völlig in Ordnung.

Leider ist es per API nicht ganz so einfach.

Als erstes erstellen wir mal eine neue SymbolLibrary. Achtet darauf dass der komplette Pfad übergeben werden muss:

var symbolLibrary = MDSymbolLibrary.Create(symbolLibraryPath);

Danach können wir neue Symbole hinzufügen. Sucht euch die gewünschte Funktionsdefinition und die Typen des Symbols aus der Oberfläche. Nur ein Teil ist in der Hilfe beschrieben:

MDSymbol symbol = symbolLibrary.AddSymbol(id, symbolName);
symbol.Type = MDSymbol.Enums.SymbolType.Function;
symbol.FunctionDefinitionCategory = Function.Enums.Category.Undefined;
symbol.FunctionDefinitionGroup = 98;
symbol.FunctionDefinitionId = 1;
symbol.PlacementType = DocumentTypeManager.DocumentType.Circuit;
symbol.Properties.SYMB_DESC = description;
symbol.Properties.SYMB_SYBMOLFUNCTIONTYPE = 1;

Nun gehts an die Varianten. Da wird es knifflig. Variante A (Index 0) wird automatisch beim Erstellen des Symbols mit erstellt. Weitere Varianten müssen wir dann separat hinzufügen. Achja, der VariantIndex wird als sbyte übergeben :)

sbyte variantIndex = Convert.ToSByte(variantCount); // A = 0
MDSymbolVariant variant;
if (variantCount == 0) // First variant is created at Symbol.Create()
{
  variant = symbol.Variants.First();
}
else
{
  variant = symbol.AddSymbolVariant(variantIndex);
}

Nun können wir der SymbolVariant Placements hinzufügen. Kleiner Handstand um die Group von der Variant zu bekommen. Danach können wir die Platzierungen hinzufügen. Jedes Placements muss einzeln hinzugefügt werden.

Group group = variant.AsGroup;
foreach (var placement in page.AllFirstLevelPlacements)
{
  placement.CopyTo(group);
}

Mir ist aufgefallen dass hier EPLAN bzw. die API sehr empfindlich reagiert was das Locking angeht. Darum am besten das Quellprojekt exklusiv öffnen.

Von |2018-09-24T12:50:00+02:002018-09-24|EPLAN, EPLAN-API|

Anzeigesprache per Script ermitteln

Wie so oft ist es in der API ganz einfach… Im Scripting muss man aber einmal einen Roundtrip machen…
Hier eine Action um die Anzeigesprache des Projektes per Script zu ermitteln.

Aufruf:

public void Function()
{
  var languages = GetDisplayLanguages();
  foreach (var language in languages)
  {
    MessageBox.Show(language);
  }
  return;
}

private static List<string> GetDisplayLanguages()
{
  string value = null;
  ActionCallingContext actionCallingContext = new ActionCallingContext();
  new CommandLineInterpreter().Execute("GetDisplayLanguages", actionCallingContext);
  actionCallingContext.GetParameter("value", ref value);
  var split = value.Split(';');
  var languages = split.Where(language => !string.IsNullOrEmpty(language)).ToList();
  return languages;
}

 

Script:

using System.IO;
using System.Xml;
using Eplan.EplApi.ApplicationFramework;
using Eplan.EplApi.Base;
using Eplan.EplApi.Scripting;

namespace EplanScriptingProjectBySuplanus.GetDisplayLanguages
{
    public class GetDisplayLanguages
  {
        [DeclareAction("GetDisplayLanguages")]
        public void Action(out string value)
        {
            // Get language from settings
            string tempFile = Path.Combine(PathMap.SubstitutePath("$(TMP)"), "GetDisplayLanguages.xml");

            ActionCallingContext actionCallingContext = new ActionCallingContext();
            actionCallingContext.AddParameter("prj", FullProjectPath());
            actionCallingContext.AddParameter("node", "TRANSLATEGUI");
            actionCallingContext.AddParameter("XMLFile", tempFile);
            new CommandLineInterpreter().Execute("XSettingsExport", actionCallingContext);

            // Needed because there is no direct access to setting
            string language = GetValueSettingsXml(tempFile, "/Settings/CAT/MOD/Setting[@name='DISPLAYED_LANGUAGES']/Val");
            value = language;
        }

        private static string GetValueSettingsXml(string filename, string url)
        {
            XmlDocument xmlDocument = new XmlDocument();
            xmlDocument.Load(filename);
            XmlNodeList rankListSchemaName = xmlDocument.SelectNodes(url);
            if (rankListSchemaName != null && rankListSchemaName.Count > 0)
            {
                string value = rankListSchemaName[0].InnerText;
                return value;
            }
            return null;
        }

        private static string FullProjectPath()
        {
            ActionCallingContext acc = new ActionCallingContext();
            acc.AddParameter("TYPE", "PROJECT");

            string projectPath = string.Empty;
            new CommandLineInterpreter().Execute("selectionset", acc);
            acc.GetParameter("PROJECT", ref projectPath);

            return projectPath;
        }
    }
}

 

Ihr findet das wie gewohnt auf GitHub.

Von |2019-03-14T08:30:01+01:002018-09-07|EPLAN, EPLAN-Scripts|

EPLAN Version ermitteln

Vielen Dank an nairolf für die Bereitstellung der schönen Methode um die EPLAN Version zu ermitteln. Funktioniert in API & Scripting. Man kann das dann z.B. so verwenden:

if (EplanApplicationInfo.GetActiveEplanVersion() >= 270)
{
  FlyToTheRainbowIn27();
}

Die Methode:

using System;
using System.Diagnostics;
using System.IO;
using Eplan.EplApi.Base;

namespace Suplanus.Sepla.Application
{
  public class EplanApplicationInfo
  {
    public static int GetActiveEplanVersion()
    {
      string eplanVersion = "0"; //default value = 0 to ensure, that EPLAN-version is correctly recognized 

      //try new variable $(EPLAN_VERSION) first, if not valid, no possibility to get active get active EPLAN-version
      if (PathMap.SubstitutePath("$(EPLAN_VERSION)") != "$(EPLAN_VERSION)")
      {
        eplanVersion = PathMap.SubstitutePath("$(EPLAN_VERSION)");
      }
      else
      {
        //try different method to get version of executing eplan, in case the actual version doesn't support $(EPLAN_VERSION)
        string dllFilename = Path.Combine(PathMap.SubstitutePath("$(BIN)"), "Eplan.EplApi.Baseu.dll");
        FileInfo fileInfo = new FileInfo(dllFilename);
        if (fileInfo.Exists)
        {
          var versionInfo = FileVersionInfo.GetVersionInfo(dllFilename);
          //return main-version-infos (without build number)
          if (versionInfo.ProductVersion.Length >= 5)
          {
            eplanVersion = versionInfo.ProductVersion.Substring(0, 5);
          }
        }
      }

      if (eplanVersion == "0" || eplanVersion == "$(EPLAN_VERSION)")
      {
        MultiLangString multiLangErrorText = new MultiLangString();
        multiLangErrorText.AddString(ISOCode.Language.L_de_DE, "Die aktuelle EPLAN-Version konnte nicht ermittelt werden.");
        multiLangErrorText.AddString(ISOCode.Language.L_en_US, "Unable to get actual EPLAN-version.");
        ISOCode.Language guiLanguage = new Languages().GuiLanguage.GetNumber();
        string errorText = multiLangErrorText.GetStringToDisplay(guiLanguage);
        if (String.IsNullOrEmpty(errorText))
        {
          //if actual GUI-language is not defined in multi-language-string, use en_US-text-version
          errorText = multiLangErrorText.GetStringToDisplay(ISOCode.Language.L_en_US);
        }
        new BaseException(errorText, MessageLevel.Warning).FixMessage(); 
        eplanVersion = "0";
      }
      return Convert.ToInt32(eplanVersion.Replace(".", string.Empty));
    }
  }
}

Findet Ihr auch hier auf GitHub.

Von |2022-03-28T08:08:11+02:002018-09-04|EPLAN, EPLAN-API, EPLAN-Scripts|

Dokumentation erstellen mit MkDocs

Ich liebe Markdown. Es ist einfach zu schreiben und man bekommt ein schönes Resultat.
Darum habe ich mich entschlossen viele der Dokumentation welche ich schreiben muss darf, auch in Markdown zu schreiben.

Hab mich bei der zweiten Auflage meines Buches dazu entschieden auch eine kleine Website zu machen. WordPress oder ein anderes CMS war für den Anwendungsfall einfach zu groß.

Zufällig bin ich dann mal über MkDocs gestolpert. Dies generiert aus Markdown files schöne Websites die sich super für Dokumentationen eignen. Bekannter dürfte Jekyll sein, aber das ist wieder zu groß für so kleine Dokus.

Da ich auf der Seite die ganzen Beispiel vom Buch darstellen wollte und natürlich zu faul bin das alles zu kopieren… Hab ich mir einfach ein kleines C# Programm erstellt, welches mir die Arbeit abnimmt.
Es generiert Pro Kapitel-Ordner und Script-Datei eine Markdown-Datei mit Überschriften usw.
Zusätzlich wird auch noch die Übersicht generiert.
In der Debug-Konsole lass ich mir auch noch gleich die Menüpunkte ausgeben, welche dann in der YML-Datei von MkDocs landen.

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;

namespace DocuCreator
{
  class Program
  {
    static void Main(string[] args)
    {
      // Output
      string outputDirectory = @"\\Mac\Home\Documents\GitHub\EplanElectricP8Automatisieren.V2.Writing\Documentation\Website\docs\scripts";
      if (Directory.Exists(outputDirectory))
      {
        Directory.Delete(outputDirectory, true);
      }
      Directory.CreateDirectory(outputDirectory);

      // Overview
      Console.WriteLine("- 'Übersicht': 'scripts/Overview.md'");
      string fileNameOVerview = Path.Combine(outputDirectory, "Overview.md");
      StringBuilder sbOverview = new StringBuilder();
      sbOverview.AppendLine(); // Needed for Encoding problem
      sbOverview.AppendLine("**Übersicht**");
      sbOverview.AppendLine();
      sbOverview.AppendLine("---"); // Devider line
      sbOverview.AppendLine();

      // Folder
      string path = @"\\Mac\Home\Documents\GitHub\EplanElectricP8Automatisieren.V2.Writing\Data\Code\EPLAN Scripting Project";
      var directories = Directory.GetDirectories(path, "*_*").OrderBy(obj => obj).ToList();
      foreach (var directory in directories)
      {
        string directoryName = new DirectoryInfo(directory).Name;
        string directoryNameWithSpaces = directoryName.Replace("_", " ");
        var directoryNameWithoutUmlauts = directoryName
             .Replace("ä", "ae")
             .Replace("ö", "oe")
             .Replace("ü", "ue")
          ;

        // Overview
        sbOverview.AppendLine($"### [{directoryNameWithSpaces}]({directoryNameWithoutUmlauts}.md)");

        // Files
        StringBuilder sb = new StringBuilder();
        sb.AppendLine(); // Needed for Encoding problem        
        string header1 = $"**{directoryNameWithSpaces}**"; // Main header
        sb.AppendLine(header1);
        sb.AppendLine();
        sb.AppendLine("---"); // Devider line
        sb.AppendLine();

        var files = Directory.GetFiles(directory, "*.cs", SearchOption.TopDirectoryOnly).OrderBy(obj => obj).ToList();
        foreach (var file in files)
        {
          AddFile(file, sbOverview, directoryNameWithoutUmlauts, sb, files);
        }

        // Write file
        string outputFile = Path.Combine(outputDirectory, directoryNameWithoutUmlauts + ".md");
        File.WriteAllText(outputFile, sb.ToString(), Encoding.UTF8);
        Console.WriteLine($"- '{directoryNameWithSpaces}': 'scripts/{directoryNameWithoutUmlauts}.md'");

      }

      // RemoteClient
      Console.WriteLine("- 'RemoteClient': 'scripts/RemoteClient.md'");
      AddFileRemoteClient(sbOverview, outputDirectory);

      // Write Overview
      File.WriteAllText(fileNameOVerview, sbOverview.ToString(), Encoding.UTF8);
    }

    private static void AddFileRemoteClient(StringBuilder sbOverview, string outputDirectory)
    {
      var fileRemoteClient = @"\\Mac\Home\Documents\GitHub\EplanElectricP8Automatisieren.V2.Writing\Data\Code\EPLAN Remote Client\Program.cs";
      string outputFile = Path.Combine(outputDirectory, "RemoteClient.md");

      sbOverview.AppendLine($"### [RemoteClient](RemoteClient.md)");

      StringBuilder sb = new StringBuilder();
      string header1 = "##### RemoteClient"; // Main header
      sb.AppendLine(header1);
      string lines = File.ReadAllText(fileRemoteClient);
      sb.AppendLine("```csharp"); // Code start
      sb.AppendLine(lines); // Code
      sb.AppendLine("```"); // Code end
      sb.AppendLine();
      File.WriteAllText(outputFile, sb.ToString(), Encoding.UTF8);
    }

    private static void AddFile(string file, StringBuilder sbOverview, string directoryNameWithoutUmlauts, StringBuilder sb,
      List<string> files)
    {
      string fileName = Path.GetFileNameWithoutExtension(file);
      string fileNameWithSpaces = fileName.Replace("_", " ");

      // ReSharper disable once PossibleNullReferenceException
      var anker = fileNameWithSpaces
          .ToLower()
          .Replace(" ", "-")
          .Replace('ä', 'a')
          .Replace('ö', 'o')
          .Replace('ü', 'u')
        ;
      sbOverview.AppendLine($"- [{fileNameWithSpaces}]({directoryNameWithoutUmlauts}.md#{anker})");

      string header2 = $"##### {fileNameWithSpaces}"; // Sub header
      sb.AppendLine(header2);
      string lines = File.ReadAllText(file);
      sb.AppendLine("```csharp"); // Code start
      sb.AppendLine(lines); // Code
      sb.AppendLine("```"); // Code end
      sb.AppendLine();

      // Devider line if not last
      if (!files.Last().Equals(file))
      {
        sb.AppendLine();
        sb.AppendLine("<br>");
      }
    }
  }
}

Alles bisl Quick-And-Dirty, aber läuft super.

Vorteil: Bei jeder Änderung am Script muss ich nur das kurz laufen lassen und die Website ist wieder aktuell. Für künftige Auflagen eine große Erleichterung.

Von |2018-08-21T08:32:53+02:002018-08-21|C#|
Nach oben