Archiv für den Monat: November 2017

GetVarLanguage

Im Kundenauftrag habe ich mich mal auf die Suche gemacht nach der Variablen Sprache. Diese bekommt man leider nicht so einfach, da es eine Projekteinstellung ist.

Anbei die Lösung. Einfach das Script laden und dann mit dieser Methode aufrufen. Somit kann man die Sprache in unterschiedlichen Scripten verwenden.
Vielen Dank an unseren tollen Kunden, für die Freigabe die Lösung hier zu veröffentlichen!

Aufruf:

private static string GetVarLanguage()
{
    string value = null;
    ActionCallingContext actionCallingContext = new ActionCallingContext();
    new CommandLineInterpreter().Execute("GetVarLanguage", actionCallingContext);
    actionCallingContext.GetParameter("value", ref value);
    return value;
}

 

Script:

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

namespace EplanScriptingProjectBySuplanus.GetVarLanguage
{
    public class GetVarLanguage
    {
        [DeclareAction("GetVarLanguage")]
        public void Action(out string value)
        {
            // Get language from settings
            string tempFile = Path.Combine(PathMap.SubstitutePath("$(TMP)"), "GetVarLanguage.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='VAR_LANGUAGE']/Val");

            // If setting is GUI language, return the GUI language
            if (language == "##_##")
            {
                language = new Languages().GuiLanguage.GetString();
            }

            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;
        }
    }
}

 

Wie immer auf GitHub zu finden :^)

Von |2019-03-14T08:36:45+01:002017-11-30|EPLAN|

Artikel mit Funktionsschablone erzeugen

Schnell mal per API Artikel mit Funktionsschablone erzeugen war meine Aufgabe…
Naja nicht so einfach:

public static MDPart CreateOrUpdateWithFunctionTemplate(Function function)
{
    // Need to lock project
    var project = function.Project;
    project.SmartLock();
    function.SmartLock();

    // Init
    var partsDatabase = new MDPartsManagement().OpenDatabase();
    var articleReference = function.ArticleReferences.First();
    articleReference.SmartLock();
    var partNr = articleReference.PartNr;
    var partVariant = articleReference.VariantNr;
    MDPart part = partsDatabase.GetPart(partNr, partVariant);

    // Create new part
    if (part == null)
    {
        // LockingVector is needed because of locking exception from EPLAN action (no catch possible)
        LockingVector lockingVector = new LockingVector();
        int stateId = lockingVector.PauseManualLock();
        new CommandLineInterpreter().Execute("XPameCreateType");
        lockingVector.ResumeManualLock(stateId);

        partsDatabase = new MDPartsManagement().OpenDatabase(); // Second Call needed to get new part
        part = partsDatabase.GetPart(partNr, partVariant);                
    }
    else
    {
        // Rename part
        string suffix = "_temp";
        string partNrTemp = part.PartNr + suffix;
        try
        {
            articleReference.PartNr = partNrTemp;
            articleReference.StoreToObject();

            // Quiet create temp part
            var application = new EplApplication();
            var quiteMode = application.QuietMode;
            application.QuietMode = EplApplication.QuietModes.ShowNoDialogs;
            new CommandLineInterpreter().Execute("XPameCreateType");
            application.QuietMode = quiteMode;
        }
        finally
        {
            // Rename back
            articleReference.PartNr = partNr;
            articleReference.StoreToObject();
        }

        // Copy FunctionTemplate
        partsDatabase = new MDPartsManagement().OpenDatabase(); // Second Call needed to get new part
        MDPart partDuplicate = partsDatabase.GetPart(partNrTemp, partVariant);
        foreach (var partFunctionTemplatePosition in part.FunctionTemplatePositions)
        {
            part.RemoveFunctionTemplatePosition(partFunctionTemplatePosition);
        }
        foreach (var partDuplicateFunctionTemplatePosition in partDuplicate.FunctionTemplatePositions)
        {
            part.AddFunctionTemplatePosition(partDuplicateFunctionTemplatePosition);
        }

        partsDatabase.RemovePart(partDuplicate);


        // Check if article is in project
        var existingArticle = project.Articles
            .FirstOrDefault(obj =>
            obj.PartNr.Equals(partNrTemp) && obj.VariantNr.Equals(partVariant)
            );
        if (existingArticle != null)
        {
            existingArticle.SmartLock();
            existingArticle.Remove();
        }
    }

    // Load data
    var article = project.Articles
        .FirstOrDefault(obj =>
            obj.PartNr.Equals(partNr) && obj.VariantNr.Equals(partVariant)
        );
    if (article != null)
    {
        article.SmartLock();
        article.LoadFromMasterdata();
    }

    return part;
}

Es darf nur ein Artikel hinterlegt sein, sonst schlägt die Action XPameCreateType  fehl. Ist nicht schön, aber die Funktionsschablone von Hand zu erstellen ist mir zu heikel. Denn da kommt ja oftmals was neues dazu :^)

Von |2017-11-23T12:42:26+01:002017-11-22|EPLAN, EPLAN-API|

UndoStep & SafetyPoint

Man ist es gewohnt über Bearbeiten Rückgängig  zu arbeiten…
Aber das geht nicht von alleine, mann muss schon was dafür tun.

EPLAN stellt hier zwei Klassen bereit, welche das sehr gut implementieren. Muss sagen ich nutze für Schreiboperationen (ab sofort) immer Beide.
UndoStep lässt den User die Möglichkeit die Bearbeitung per API rückgängig zu machen. SafetyPoint stellt den Ursprung wieder her, falls eine Exception auftritt.

Toller Nebeneffekt, man muss sich nicht ums Locking der erzeugten Elemente kümmern :)

public void DoStuff()
{
    using (var undoStep = new UndoManager().CreateUndoStep())
    {
        undoStep.SetUndoDescription("DoStuff");
        using (SafetyPoint safetyPoint = SafetyPoint.Create())
        {
            try
            {
                // Do wild stuff
                safetyPoint.Commit();
            }
            catch (Exception exception)
            {
                MessageBox.Show(exception.Message, "Error", MessageBoxButton.OK, MessageBoxImage.Error);
                safetyPoint.Rollback();
            }
        }
    }
}
Von |2017-11-16T09:41:37+01:002017-11-16|EPLAN, EPLAN-API|

EPLAN-API: Signierung automatisieren (Update 2)

Und täglich grüßt die EPLAN Signierung…

Meine Beschreibung hier, klappt leider nur wenn man eine DLL bzw. EXE hat. Es wird zwar alles richtig signiert, aber die Verweise werden nicht aktualisiert, da ist .NET schuld…

Tja, für die Meisten wird das kein Problem sein, aber ich arbeite immer mit verteilten Libraries.

Ich habe einen Weg gefunden der für mich OK ist. Bisl manuelle Arbeit hat man wenn man mehrere Keys signieren muss.
In der AssemblyInfo.cs  lege ich fest dass in der Release Konfiguration die Kompiler-Attribute für EPLAN gesetzt werden.

// EPLAN signing
#if TRACE && !DEBUG
using Eplan.EplApi.Starter;
[assembly: EplanSignedAssembly(true)]
[assembly: AssemblyKeyFile("2161_Public.snk")]
[assembly: AssemblyDelaySign(true)]
#endif

Das tolle ist, ich kann nach wie vor den Release Build testen, wenn ich das Trace Flag wegnehme.

Zusätzlich wird die Signierung wirklich erst von EPLAN gemacht… denn die Attribute reservieren nur den Speicher in den Assemblies. Somit kann man auch Extensions verwenden welche den Build beeinflussen wie Fody.PropertyChanged, welches bei mir immer mit WPF im Einsatz ist.

Mir ist beim Bauen einer Offline-Application auch noch was aufgefallen:
Werden externe Assemblies verwendet, achtet darauf das diese strong namend signiert sind. Sonst könnt Ihr Sie nicht verwenden. Ich nutze zum Glück ausschließlich OpenSource Lösungen… denn eine davon war nicht signiert und ich musste es dann mit dem EPLAN KeyFile selbst machen, was ich ja konnte da Code vorhanden ist :^)

Vielen Dank an der Stelle, mal wieder, an den tollen EPLAN API Support, der mir hier wieder freundlich zur Seite stand!

Von |2019-03-14T08:39:03+01:002017-11-09|EPLAN, EPLAN-API|
Nach oben