Reklama: Jesteś webmasterem ? Zacznij zarabiać KLIKNIJ

Stwórz profil

Musisz wpisać swoje imię
Musisz wpisać swoje nazwisko
Musisz wpisać poprawny e-mail
Musisz wpisać hasło (min. 8 znaków)
Musisz zaakceptować regulamin

Adrian Olszewski Projektant iMed24
SA, Biostatystyk

Temat: Barkody i wydruki w ap. desktopowych

Cześć wszystkim :)

Temat bardziej dla programistów (widzę, że są tutaj obecni), niż analityków, ale ponieważ dotyczy RepSrv, a raczej jego klienckiej wersji, to umieszczam tutaj.

Od pewnego czasu stosuję RDLC jako narzędzie do wydruków w aplikacjach desktopowych (kontrolka ReportViewer). Jest to bardzo przyjemne rozwiązanie: nie trzeba niczego instalować (wystarczy przegrać DLLki ReportViewer), dostaje się wygodny edytor wydruku, sam raport ma postać pliku XML, zatem da się go modyfikować chociażby w Notatniku (a także programistycznie, o czym dalej), a sama kontrolka ma dość szerokie możliwości (może służyć jako podgląd wydruku, a także "renderer" raportu do pliku).

W związku z tym, że rozwiązanie wielokrotnie mi się opłaciło czasowo i finansowo, a natknąłem się na kilka problemów, zwracam uwagę na kilka ciekawych kwestii, które może się komuś przydadzą.

Nie chodzi tu o "wypasione raporty" z pięknymi wykresami i ślicznymi tabelkami, ale o wykorzystanie tego mechanizmu do zrzucenia z siebie problemu oprogramowania wydruków w aplikacjach desktopowych. Przykładowo drukowałem w ten sposób recepty lekarskie (z pełną parametryzacją), kupony RUM, wypisy ze szpitala i karty wizyty pacjenta i inne, złożone dokumenty.

Poniższe rozwiązania gdzieś - kiedyś znalazłem w sieci, dopasowałem do swoich potrzeb, a teraz zbieram tutaj "do kupy". Może się przyda, pozwoli zaoszczędzić czas.

1. Barkody.
Na CodeProject znajduje się biblioteka (.NET, C#) wielu popularnych barkodów:

Code 128,
Code11,
Code 39 (Extended / Full ASCII),
Code 93,
EAN-8,
EAN-13,
UPC-A,
UPC-E,
JAN-13,
MSI,
ISBN,
Standard 2 of 5,
Interleaved 2 of 5,
PostNet,
UPC Supplemental 2,
UPC Supplemental 5,
Codabar,
ITF-14

W dodatku, ponieważ jest dostępny kod źródłowy, ma się dobrą bazę do dodawania kolejnych implementacji algorytmów generujących kod.

Biblioteka ksportuje kilka metod statycznych, więc można je od razu wykorzystać w raporcie:

Image -> MimeType = (np.) image/png, Source = Database, Value = metoda generująca barkod (rodzaj kodu, dane, kolory, rozmiary).

Można wykorzystać całą bibliotekę "jak leci" - wtedy nie trzeba nic programować. Dodaje się bibliotekę do raportu, podstawia nazwę metody i parametry pod właściwość Value obrazka i informuje RepSrv, że biblioteka jest zaufana.

Ale można sobie przykroić ją do potrzeb (np. usunąć zbędne kody, zmodyfikować listę i rodzaj argumentów metody generującej). U mnie np. wygląda to tak:
=I25.I25.GenerateI25Barcode(Parameters!PrescriptionNumber.Value, false, 320, 30, Parameters!PrintPrescriptionNumber.Value)

Przy okazji - ukrywanie barkodu przez Visible.Hidden może spowodować, że raport się rozjedzie (zmiana wysokości kolejnych elementów). Można to łatwo obejść przez ustawienie koloru barkodu na kolor kolor tła. Generuje się "pusty" obrazek o ustalonych wymiarach, co zachowuje layout raportu.

W kontrolce raportu barkod wygląda na rozmazany, ale drukuje się bardzo ostro (i skaner bez problemu go odczytuje w różnych warunkach). Można dla pewności, w kodzie biblioteki, w metodzie Generate_Image dodać kod (pamiętając o odpowiednich using'ach)

g.TextRenderingHint = TextRenderingHint.SystemDefault;
g.SmoothingMode = SmoothingMode.None;
g.InterpolationMode = InterpolationMode.Low;
g.CompositingQuality = CompositingQuality.Default;


Oczywiście trzeba dodać "uspokoić" RepSrv, że biblioteki są bezpieczne:

this.reportViewer1.LocalReport.AddTrustedCodeModuleInCurrentAppDomain("System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a");
this.reportViewer1.LocalReport.AddTrustedCodeModuleInCurrentAppDomain("I25, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null");


Uspokoję jeszcze, że całość jest na licencji CodeProject Open License. Najważniejsza z tego informacja to: can be used in commercial applications.


2. Własne funkcje rysujące


Przykład jednej z moich funkcji (Value obrazka):
=ScriptRenderer.ScriptRenderer.GetBitmap(Parameters!ReakcjaChem.Value, 100,25, "Verdana", 8)

gdzie ReakcjaChem = "AgCl + 2S_2@O_3#2^-@ -> Ag(S_2@O_3@)_2#3^-@ + Cl^-"


Obrazek
Niestety, napisy są "rozmazane" i nie umiem tego wyostrzyć. Lepiej generować w ten sposób obrazki (zdjęcia, krzywe, wykresy, grafy), a nie tekst w formie obrazka.


3. Zmiana marginesów raportu runtime
Marginesy i rozmiar raportu można podać jedynie liczbowo (nie może to być wyrażenie). A podczas generowania wydruków czasem okazuje się, że klient ma drukarkę wymagającą innego ustawienia marginesów.

Można to załatwić programistycznie, wczytując raport do strumienia XML, podmieniając odpowiednie wartości przy żądanym obiekcie i podając zmodyfikowany strumień do kontrolki raportu.

Można w ten sposób sterować położeniem i rozmiarem dowolnego obiektu raportu, jeśli znamy jego nazwę. Niemniej jest to paskudna robota. Możliwa, ale paskudna.

Stream ChangeMargins(Stream xmlStream, double PrescriptionWidth, double PrescriptionHeight, double LeftMargin, double TopMargin)
{
System.Xml.XmlDocument doc = new System.Xml.XmlDocument();
doc.Load(xmlStream);
xmlStream.Close();
XmlNode report = doc.SelectSingleNode("./*");
foreach (XmlNode node in report.ChildNodes)
{
if (node.Name == "LeftMargin")
{
node.InnerText = LeftMargin.ToString().Replace(",", ".") + "cm";
}

if (node.Name == "TopMargin")
{
node.InnerText = TopMargin.ToString().Replace(",", ".") + "cm";
}

if (node.Name == "PageWidth")
{
node.InnerText = (PrescriptionWidth + LeftMargin).ToString().Replace(",", ".") + "cm";
}

if (node.Name == "PageHeight")
{
node.InnerText = (PrescriptionHeight + TopMargin).ToString().Replace(",", ".") + "cm";
}
}
MemoryStream stream = new
MemoryStream(); doc.Save(stream);
stream.Seek(0, SeekOrigin.Begin);

return stream;
}


a dalej w kodzie:

this.reportViewer1.Reset();
Stream s = new FileStream(@"E:\temp\WebSite1\Rp.rdlc", FileMode.Open);
this.reportViewer1.LocalReport.LoadReportDefinition(ChangeMargins(s, 10, 21.5, 0, 0));

// ustawienie źródeł danych, parametrów

this.reportViewer1.RefreshReport();



4. Drukowanie raportu
Standardowy mechanizm drukowania raportu wymaga kliknięcia w ikonkę "drukuj". Wywołanie metody Print wyświetla okno wyboru drukarki, co jest nieciekawym rozwiązaniem w przypadku wydruku wielu kopii. Można jednak raport wydrukować programistycznie.

Nie będę wklejał ton kodu, ale wskażę użyteczny link:
http://msdn.microsoft.com/en-us/library/ms252091(VS.80...

Przypominam tylko wymiary arkusza A4
"<PageWidth>21cm</PageWidth>" +
" <PageHeight>29.7cm</PageHeight>" +



Na razie tyle. Jak mi się coś jeszcze przypomni, to wkleję. Chyba, że okaże się, że te informacje nie są nikomu przydatne. Wtedy dajcie znać - nie będę spamował :)
8.09.2009, 12:18



Wyślij zaproszenie do