Przejdź do treści

Połączenie okien Neos z VCL

Wywoływanie funkcji i okien Neosa ze wstążki aplikacji

Aby w aplikacji VCL uruchomić jakąś formę Neosa, najwygodniej dodać do niej skrót we wstążce aplikacji. Skrót taki definiujemy poprzez dodanie akcji w dowolnym obiekcie biznesowym, która ma zaznaczone pole "stanowi element wstążki / menu głównego". W akcji takiej dodatkowo określamy nazwę zakładki i grupy w jakiej ma się ta akcja pojawić. Metoda wykonawcza takiej akcji jest statyczna, a więc nie można w niej odwoływać się do danych bieżącego rekordu danych, itp. Jedyne czego można użyć w praktyce to metody statycznej klasy GUI.

Przykład

Metoda wykonawcza akcji, która z poziomu wstążki uruchamia okno ról i uprawnień Neos Experta

public static void ShowNeosExpertGrants()
{
  GUI.ShowForm("SYSTEM.ROLE","BROWSEROLESANDGRANTS");  
}

Wywoływanie okien Neosa z akcji VCL

Aby z aplikacji wywołać jakieś okno NEOSa należy zdefiniować odpowiednią akcje, w której definiuje się nazwę obiektu i okno do pokazania. Np tak:

Function=SYSMESSAGE_CSHOW
ObjectName=SYSTEM.STRUCTURE
FormName=BROWSE

Dodatkowo akcja może przyjmować parametry (ParamX:Name i ParamX:Value), które przekazywane są do okna jako kontekst. Kontekst może ustawiać parametry obiektu, lub nakładać filtr na pola obiektu. Dostępne są następujące funkcje:

SYSMESSAGE_CSHOW - wyświetla zadaną formę. Przyjmuje parametry:

  • ObjectName - pełna nazwa obiektu
  • FormName - symbol formy (opcjonalny, jeśli nie podano pokazywana jest domyślna forma przeglądania danych)
  • Mode - tryb: B=przeglądanie, E=edycja, D=słownik (opcjonalny)
  • FormStyle - styl: M=okno MDI, D=okno modalne, F=wolne okno (opcjonalny)
  • ParamX:Name/Value - kontekst zawężający dziedzinę danych (opcjonalnie)
  • Postpone - parametr niewymagany, komunikat zwrotny z neosa ma być obsługiwany: 0-synchronicznie, 1-asynchronicznie, domyślnie 0 (od 5.4.17)

SYSMESSAGE_CSHOWRECORD - wyświetla zadane okno w kontekście danych wskazanego rekordu. Przyjmuje parametry:

  • ObjectName - pełna nazwa obiektu
  • FormName - symbol formy (opcjonalny, jeśli nie podano pokazywana jest domyślna forma edycji danych)
  • Mode - tryb: B=przeglądanie, E=edycja, D=słownik (opcjonalny)
  • FormStyle - styl: M=okno MDI, D=okno modalne, F=wolne okno (opcjonalny)
  • ParamX:Name/Value - kontekst zawężający dziedzinę danych do wskazanego rekordu
  • Postpone - parametr niewymagany, komunikat zwrotny z neosa ma być obsługiwany: 0-synchronicznie, 1-asynchronicznie, domyślnie 0 (od 5.4.17)

SYSMESSAGE_CSHOWNEWRECORD - wyświetla zadane okno w kontekście dodawania nowego rekordu. Przyjmuje parametry:

  • ObjectName - pełna nazwa obiektu
  • FormName - symbol formy (opcjonalny, jeśli nie podano pokazywana jest domyślna forma edycji danych)
  • Mode - tryb: B=przeglądanie, E=edycja, D=słownik (opcjonalny)
  • FormStyle - styl: M=okno MDI, D=okno modalne, F=wolne okno (opcjonalny)
  • ParamX:Name/Value - kontekst zawężający dziedzinę danych (opcjonalnie)
  • Postpone - parametr niewymagany, komunikat zwrotny z neosa ma być obsługiwany: 0-synchronicznie, 1-asynchronicznie, domyślnie 0 (od 5.4.17)

Wywoływanie kodu C# Neosa z akcji VCL

Z akcji VCL można wywołać dowolną metodę statyczną obiektu biznesowego. Realizuje to następująca funkcja:

SYSMESSAGE_CMETHOD - Przyjmuje ona parametry:

  • ObjectName - pełna nazwa obiektu
  • MethodName - nazwa metody
  • ParamX:Name/Value - parametry metody (opcjonalne). Ważna jest kolejność parametrów, a nie ich nazwa, czyli Param0 - to pierwszy parametr, Param1 - drugi, itp. Po stronie serwera wszystkie parametry muszą być typu string. !!! Warning "Uwaga!" wartości w parametrach nie mogą być podzielone po średniku!!! Użyj innego znaku np. ",".
  • Postpone - parametr niewymagany, komunikat zwrotny z neosa ma być obsługiwany: 0-synchronicznie, 1-asynchronicznie, domyślnie 1 (od 5.4.17)

Przykład

Jeśli w Neosie w obiekcie SENTE.NAGZAM zdefiniowano następującą metodę:

static public void BrowseNagzam(string GrZam, string ListTypow, string Rejestr)
{ 
  ...
}

to można ją wywołać w następujący sposób:

  Function=SYSMESSAGE_CMETHOD
  ObjectName=SENTE.NAGZAM
  MethodName=BrowseNagzam
  Param0:Name=GrZam
  Param0:Value=SPR
  Param1:Name=ListTypow
  Param1:Value=ZAM
  Param2:Name=Rejestr
  Param2:Value=ZNO

Podmiana / przykrycie okien klienta VCL na okna Neosa

Jeśli jakieś okno zbudowane w kliencie VCL zastępujesz oknem Neosowym, należy wszelkie wywołania tego okna przekierować do Neosa. Jeśli okno wywoływane jest tylko z poziomu wstążki nawigatora, to nie ma problemu. Ale często okna są wywoływane z różnych akcji a także bezpośrednio z kodu C++.

Aby na stałe zastąpić konkretne okno zarejestrowane w kliencie VCL oknem Neosa, można w Neos Expercie zdefiniować specjalną metodę wywoływaną zamiast pokazania okna (hook). W oknie edytora C# uruchom funkcję Dodaj metodę zastępującą pokazanie formy w VCL. Jako nazwy metody użyj symbolu formy, którą chcesz zastąpić, np BrowseNAGFAK. W parametrach podaj nazwy zmiennych globalnych, których chcesz użyć, np parametr string globalparam1 pobierze wartość ze zmiennej globalnej GLOBALPARAM1. Jeśli użyjesz podkreślenia w nazwie parametru to otrzymasz pole danych, np parametr string nagfak_ref odczyta zawartość pola NAGFAK.REF. Od wersji 4.6 obsługiwany jest także parametr state, który przekazuje do funkcji informację z klienta VCL, czy forma ma zotać pokazana w wyniku uruchomienia w kliencie funkcji ShowForm - parametr przyjmuje wartość B (przeglądanie), NewRecord - I (dodawanie rekordu), czy EditRecord - E (edycja rekordu).

Wynik tej metody nie jest obecnie w żaden sposób interpretowany, zalecane jest zwrócenie true. W przyszłości planowane jest, aby jako wynik zwrócić true - jeśli pokażesz jakąś formę neosową, lub false - jeśli chcesz aby klient VCL pokazał formę oryginalną. Poniżej przykładowa metoda zastępująca okno BrowseDOKPLIK.

Przykład

public static bool BrowseDOKPLIK(string state, string browsedokplikdokzlacztable, string browsedokplikdokzlaczref, string browsedokplikcaption)
{
  //ignorujemy parametr state, bo zawsze chcemy pokazać oknoe przeglądania
  ShowAttachments(browsedokplikdokzlacztable, browsedokplikdokzlaczref, browsedokplikcaption);
  return true;
}

Przykład

public static bool EditKLIENCI(string state, string klienci_ref)
{
  if(state=="I") 
  {
    //tutaj kod na odpalenie okna dodawania nowego klienta w oknie neosowym
  } 
  else 
  {
    //tutaj kod na pokazanie okna edycji klienta o refie klienci_ref
  }
  return true;
}

Dla poprawnego działania przeciążenia okno, należy oprogramować stany I, E, B, żeby w każdym przypadku okno poprawnie się odpaliło. Nieobsłużenie danego stanu skutkować będzie brakiem jakiegokolwiek okna po wywołaniu akcji!

Metoda zacznie działać dopiero po przelogowaniu aplikacji lub odświeżeniu nawigatora.

Podmiana słownika na neosowy na oknie klienta VCL

W przypadku gdy chcemy wywołać słownik neosowy z okna natywnego VCL należy postąpić jak w przypadku Podmiana okien klienta VCL na okna Neosa. Nazwa słownika powinna być ustawiona w pliku DBI po stronie klienta VCL. Będzie to albo parametr DictForm na tabeli słownikowanej albo parametr DefaultDictForm na tabeli słownika. Ponadto możemy (nie musimy) korzystać z dwóch dodatkowych parametrów:

  • dictFindValue - zawiera wartość tekstową pola słownikowanego na formie VCL przydatną np. do wstępnego wyfiltrowania słownika
  • dictKeyValue - zawiera bieżącą wartość pola klucza głównego elementu wybranego ze słownika - najczęściej będzie to ref wybranego elementu lub null, gdy jeszcze nic nie było wybrane. Nie możemy odwołać się do pola konkretnej tabeli, gdyż ten sam słownik może być uruchamiany na wielu różnych formach i tabelach (np. klienci na nagzam i nagfak)

Przykład

Przykład wywołania

public static bool DictKLIENCI(string state, string dictFindValue)
{
  var obj=GUI.ShowForm("COMMON.KLIENCI","DICT",null,"","D");

  if (!String.IsNullOrEmpty(dictFindValue.Trim()))
  {
    obj.FindRecord("FSKROT",dictFindValue);
    obj.SearchFieldName = "FSKROT";
    obj.SearchValue = dictFindValue;
  }

  return true;
}

Przypisanie wybranego elementu słownika do bieżącego rekordu natywnego okna VCL jest obsługiwane tylko w przypadku, gdy na formie natywnej słownik jest uruchomiony przy pomocy metody SimpleDictionary. Gdy do przycisku kontrolki edycyjnej formy natywnej nie będzie przypisana żadna akcja, to metoda SimpleDictionary wywoła się domyślnie.

Wywoływanie akcji klienta VCL z okien Neosa

Aby z Neosa wywołać jakąś akcję albo okno klienta VCL, należy w metodach C# używać funkcji CallAction(...) lub CallFunction(...). Nie można jednak odebrać, żadnego wyniku z tych akcji, gdyż akcję nie są wywoływane dokładnie w momencie wywołania metody CallAction/CallFunction, ale umieszczane w kolejce komunikatów do klienta i wywoływane faktycznie dopiero wtedy, gdy kod C# w serwerze zakończy działanie.

Jeśli wywołujesz akcję przez CallAction i akcja ta otwiera jakieś okno do przeglądania lub edycji danych, powinieneś określić, czy okno to ma powołać swoje własne źródło danych, czy ma działać na tym samym źródle, co okno neosowe, z którego wywołano CallAction.

Aby wyświetlić np okno VCL pozycji faktury z poziomu neosowego okna przeglądania listy pozycji faktury, możesz napisać:

GUI.CallAction("EditPozfak","");

Musisz jednak pamiętać aby w akcji dodać wpis określający na jakiej tabeli ma działać okno:

Klucz Wartość
Table POZFAK

Najlepiej zdefiniuj osobną akcję, w której będzie ten klucz.

Jeśli chcesz wyświetlić okienko z własnym źródłem danych, użyj takiej akcji, która powołuje własne źródło, oraz znajduje w nim rekord na podstawie zmiennej globalnej. Przykładowo akcja EditPozfakFromId może wyglądać tak:

Klucz Wartość
Function EditRecord
FormName EditPOZFAK
Source0:Name table;POZFAK;_
Table POZFAK
If %qfind(POZFAK,REF,&POZFAK_ID&)%

Akcję tą wywołaj w taki sposób, aby ustawić zmienną globalną POZFAK_ID.

GUI.CallAction("EditPozfakFromId","POZFAK_ID="+this.REF);

Zwykle po wykonaniu akcji VCL zachodzi potrzeba odświeżenia danych w oknie neosowym wywołującym tą akcję. Najprościej jest zrobić to poprzez zdefiniowanie kolejnej akcji, np o nazwie RefreshPOZFAK:

Klucz Wartość
Function Refresh
Table POZFAK

i związanie jej jako kolejnej akcji po akcji EditPozfakFromId poprzez dodanie w niej wpisu:

Klucz Wartość
After RefreshPOZFAK

Działanie będzie takie, że najpierw zostanie wykonana akcja EditPozfakFromId i ponieważ pokazuje ona okno modalne, to akcja nie zakończy się, póki okno nie zostanie zamknięte. Po zamknięciu okna akcja zakończy się i zostanie wywołana kolejna akcja: RefreshPOZFAK. Akcja ta wywoła odświeżenie danych ale na bieżącym oknie. A bieżącym oknem będzie w tym momencie okno Neosowe, bo okno VCL-owe już zostało zamknięte.

Praca na oknach edycyjnych VCL z okien przeglądania w Neosie

Jeśli mamy okna BROWSE w Neosie, ale potrzebujemy obsłużyć akcje Dołącz i Popraw działające na oknie VCL, to musimy zwrócić uwagę na następujące aspekty:

  • Takie dobranie akcji VCL aby zakładały wszystkie potrzebne źródła danych do powoływanego okna. Potrzebne są te źródła danych, do których odwołuje się kod C++ okna edycyjnego, a nie są to lokalne źródła danych tego okna
  • Zapewnienie tego, aby po dodaniu rekordu, okno neosowe BROWSE się odświeżyło i ustawiło na dodanym rekordzie
  • Zapewnienie tego, aby po edycji rekordu, okno neosowe BEOWSE się odświeżyło

Realizację tych wymagań pokażemy na przykładzie zamówień (NAGZAM). Dodawanie nowego zamówienia realizujemy następującą akcją NewNagzamFromNeos:

Klucz Wartość
Function ZamAutomatyczne
AUTOREPEAT no
KLIENCIBASE no
OPERACJAAFTER &OPERACJAAFTER&
OPERACJATYP 1
REJZAM &REJZAM&
REJZAMFILTER &REJZAMFILTER&
TYPZAM &TYPZAM&
TYPZAMFILTER &TYPZAMFILTER&

Wywołujemy ją następująco:

CallAction("NewNagzamFromNeos","REJZAM="+_rejzam+";TYPZAM="+_typzam);

Akcja ta jest w pełni dostosowana do zakładania zamówień w różnych trybach i umożliwia podpowiadanie wartości szerokiego zakresu pól. Jeśli wyjdziemy z okna edycji zamówienia przyciskiem Zatwierdź, a neosowe okno BROWSE, które leży pod spodem jest oparte o tabelę NAGZAM, to zostanie ono automatycznie odświeżone, a nowo dodane zamówienie stanie się bieżące. Jeśli okno pod spodem jest oparte o inne źródło danych, to należy je odświeżyć korzystając z akcji After zawierającej odpowiednią funkcję Refresh.

Analogicznie można obsłużyć faktury i dokumenty magazynowe wywołując odpowiednio akcje FakAutomatyczne i DokmagAutoRejestruj.

Innym, bardziej ogólnym sposobem dodania rekordu jest użycie funkcji NewRecord. Akcja dodawania zamówienia z wykorzystaniem NewRecord powinna wyglądać następująco:

Klucz Wartość
FormName EditNAGZAM
Function NewRecord
Source0:Name table;POZZAM;_
Source1:Name table;DEFREJZAM;_
Source2:Name table;TYPZAM;_
If %qfind(TYPZAM,SYMBOL,&TYPZAM&)%
Param0:Name DISABLE_NAGZAM_CONTROLS
Param1:Name NAGZAMNEW
Param2:Name TOWARYBASE
Param3:Name AUTONEWPOZ

Warto zwrócić uwagę, że powołujemy niezbędne źródła danych z wyjątkiem źródła table;NAGZAM'_, gdyż ono zostanie utworzone automatycznie. Dzięki temu, że źródło NAGZAM nie jest tu podane jawnie, po założeniu zamówienia, neosowe okno BROWSE poprawnie się odświeży i ustawi na nowo dodanym zamówieniu. Ponadto w takiej akcji mogą się pojawić specyficzne parametry, z których korzysta okno, a także różne sposoby inicjacji wartości poszczególnych pól. Np rejestr nowego zamówienia inicjujemy zmienną globalną NAGZAMRejestrID (wiemy to, zaglądając do akcji blankującej pole rejestr, czyli BL_NAGZAM_REJ, natomiast typ zamówienia inicjujemy ustawiając odpowiedni rekord w lokalnym źródle danych TYPZAM (stąd wiersz z If w akcji).

Wywołanie powyższej akcji z kodu neosa wygląda więc tak:

CallAction("NewNagzamFromNeos","NAGZAMRejestrID="+_rejzam+";TYPZAM="+_typzam);

Jedyna różnica w wywołaniu to inna nazwa zmiennej globalnej inicjująca rejestr nowego zamówienia.

Powyższy sposób zakładania zamówień można uogólnić na inne tabele / okna w następujący sposób. Tworzymy akcję NewXXXFromNeos (gdzie XXX to jakaś tabela) wg następującego wzorca:

Klucz Wartość
FormName EditXXX
Function NewRecord
Source0:Name table;YYY;_
Table table;YYY;_

Oczywiście musimy zwrócić uwagę czy okno EditXXX istnieje i jak się nazywa. Wiersze SourceX:Name służą do zakładania wszystkich potrzebnych źródeł danych do powoływanego okna. Potrzebne są te źródła danych, do których odwołuje się kod C++ okna edycyjnego EditXXX, a nie są to lokalne źródła danych tego okna. Ważne jest aby nie powoływać w ten sposób samego źródła XXX (czyli nie możemy napisać SourceX:Name=table;XXX;_. Dzięki temu zadziała poprawnie mechanizm zaszyty w VCL, który po dodaniu rekordu odświeży dane na oknie BROWSE neosowym i znajdzie w nim nowo dodany rekord.

Pokazanie istniejącego zamówienia realizujemy następującą akcją DisplayNagzamFromNeos:

Klucz Wartość
FormName EditNAGZAM
Function DisplayRecord
If %qfind(NAGZAM,REF,&NAGZAMREF&)%
Param0:Name DISABLE_NAGZAM_CONTROLS
Param1:Name NAGZAMNEW
Param2:Name TOWARYBASE
Param3:Name AUTONEWPOZ
Source0:Name table;POZZAM;_
Source1:Name table;DEFREJZAM;_
Source2:Name table;TYPZAM;_
Source3:Name table;NAGZAM;_
Table NAGZAM
After RefreshNagZam

Wywołujemy ją następująco:

CallAction("DisplayNagzamFromNeos","NAGZAMREF=0"+this.REF);

Akcja ta jest w pełni dostosowana do edycji zamówienia w różnych trybach. Możemy skopiować w/w akcję i ustawić w niej inne wartości parametrów np TOWARYBASE (dodawanie pozycji przez słownik towarów) i AUTONEWPOZ (automatyczna inicjacja dodania nowej pozycji), aby wpłynąć na zachowanie okna edycji. Za odświeżenie neosowego okna przeglądania odpowiada akcja RefreshNagZam wywołana jako After.

Warto zwrócić uwagę na to, że jeśli z okna neosowego wywołamy dowolną akcję VCL, to jeśli w tej akcji odwołamy się w wyrażeniach parsera do źródła danych o nazwie NAGZAM albo do dowolnego pola tego źródła (np. %NAGZAM.REF%) to tak naprawdę odwołujemy się do źródła danych na oknie neosowym, z którego wywołaliśmy akcję. Oczywście wtedy, kiedy to okno jest na wierzchu. Jeśli na wierzchu pojawi się inne okno z własnym źródłem danych o nazwie NAGZAM to wtedy ono jest dostępne w wyrażeniach parsera.

Z tego samego powodu odświeżanie okna pod spodem zainicjowane akcją np RefreshNagZam nie działa wtedy, jak okno edycyjne jest jeszcze otwarte, bo wtedy bieżącym źródłem danych NAGZAM jest okno edycyjne, a nie okno przeglądania, które leży pod spodem. I póki okno na wierzchu się nie zamknie, to nie da się dostać do źródła danych na oknie pod spodem. To, że się wywoła akcję odświeżającą na CloseForm nie pomoże, bo okno i tak się jeszcze fizycznie nie zamknęło. Jedyne, co jest skuteczne w 100%, to:

  • jesli okno przeglądania jest VCL-owe, to mozna pogrzebać w oknie VCL-owym i na odpowiednim źródle danych ustawić flagę RefreshOnActivate. Dane będą się same odświeżały, jak okno przeglądania wychodzi na wierzch, z powodu zamknięcia okna edycyjnego.
  • jeśli okno przeglądania jest Neosowe, to ustawiamy na definicji okna znacznik "Odśwież dane przy każdej aktywacji okna". Działanie będzie jak wyżej.

Uruchomienie innej aplikacji po stronie klienta VCL

Aby zlecić uruchomienie dowolnej aplikacji po stronie klienta skorzystaj z funkcji ShellExecute(...).

Przekazywanie parametrów między Neosem a klientem VCL

Zmienne globalne ustawiane w kliencie VCL są przekazywane do NEOSa tylko wtedy, jeśli są to zmienne zrzucane do bazy danych (np. AKTUOPERATOR, AKTUODDZIAL, CURRENTCOMPANY, itd.). W metodach C# można je odczytywać przez:

SessionInfo.GlobalParam[PARAMETR]

Zmienne te są dostępne w bazie danych także z poziomu połączenia serwera, mimo tego, że serwer łączy się do bazy odrębnym połączeniem (connection) niż klient. Serwer nie nawiązuje odrębnego połączenia dla każdego zalogowanego użytkownika, ale korzysta z określonej puli połączeń dostępnych rotacyjnie. Dla każdego połączenia są ustawiane odpowiednie zmienne kontekstowe, które są odczytywane w procedurze GET_GLOBAL_PARAM, aby odnaleźć właściwą wartość zmiennej. Dla bezpieczeństwa zaleca się jednak, aby w procedurach SQL wywoływanych z poziomu serwera, przekazywać jawnie wszystkie zmienne globalne jako parametry procedur.

Z poziomu serwera nie należy jednak korzystać z tabel tymczasowych, w których dane żyją przez cały czas trwania połączenia, gdyż dane te w jednym połączeniu będą widoczne, a w innym nie.

SessionInfo.GlobalParam[PARAMETR] = wartosc;

Przypisanie wartości zmiennej globalnej z poziomu C# powoduje także ustawienie takiej zmiennej w kliencie VCL. W ten sposób można przekazywać zmienne z okien NEOSa do klienta VCL.

Uwaga!

Serwer NEOS używa dostępu do bazy danych w sposób niejawny, w momencie redagowania rekordu podczas zmiany wartości pola podlegającego słownikowaniu. Aby ustawić nowe wartości pól ze słownika, NEOS sam szuka odpowiedniego rekordu z danymi w określonej tabeli. Dzieje się to w osobnym połączeniu do bazy danych niż połączenie klienta, niemniej zmienne globalne odczytywane przez GET_GLOBAL_PARAM są synchronizowane między tymi połączeniami.