Report Viewer: externe Bilder darstellen

Will man externe Bilder darstellen, könnte es sein, dass man über die Syntax der Pfadangabe stolpert. Ich hatte direkt den Pfad zum Bild eingetragen und war etwas verwundert, dass MS anhand der Backslashes in der Pfadangaben nicht von selbst auf den Dateizugriff kam. Man muss es also klar voranstellen, was man will. Report Viewer unterstützt Bilder über Http- und File-Zugriff:

  • Http:
    http://www.Beispiel.de/MeinBild.png
  • File:
    file:\\\D:\Ordner\MeinBild.png

Aus Sicherheitsgründen muss man zusätzlich den externen Zugriff bei Bildern auch erlauben:

reportViewer1.EnableExternalImages = true;

Cheers,
Ralf

Windows Forms: Grid-Container mit Hintergrundfarbe

Jeder der schon mit WPF (oder Silverlight) gearbeitet hat, empfindet es sicher wie ich als Qual wenn mit der älteren Technologie „Windows Forms“ arbeitet. In WPF gibt es eine Vielzahl von Containern, die einem eine Menge Arbeit abnehmen. Jeder der in WPF Stunden zubringt um einzelne Elemente neu zu verschieben, nur weil sich die Seitenbreite geändert hat, sollte sein Tun dringend überdenken.

Immer wenn ich also „Back to the roots“ gehe und ein Windows Forms-Projekt bearbeite, dann vermisse ich bespielsweise das Grid-Element, das sehr viele Elemente prozentual über den kompletten Bereich verteilen kann. Es gibt unter Windows Forms allerdings ein Element namens TableLayoutPanel, das ein bisschen Ähnlichkeit hat … allerdings mit der Eleganz einer Bahnschranke :-)

Hier ein paar Einschränkungen:
– Das Ausrichten übereinander ist nicht möglich.
– Es kann nur ein Element pro Zelle eingefügt werden
– Copy & Paste: Das neue Element wird in die letzten Zeile erstes Feld eingefügt
– Die Performance bei vielen UI-Elementen ist leider nicht besonders
– Bei einem Resize der Komponente könnte es flackern
– Zeilen und Spalten lassen sich nicht in der Design-Ansicht einfärben

Will man z.B. eine unterschiedliche Hintergrundfarbe für die erste und dritte Spalte haben, dann muss man das CellPaint-Ereignis abfangen und folgenden Handler programmieren:

void tableLayoutPanel1_CellPaint(object sender, 
        TableLayoutCellPaintEventArgs e)
{
    if (e.Row == 0 || e.Row == 2) {
        Graphics g = e.Graphics;
        Rectangle r = e.CellBounds;
        g.FillRectangle(Brushes.Blue, r);
    }
}

Besser als nichts. Ich setzte es gerne ein, wenn man schnell einen Prototypen basteln will.

Cheers,
Ralf

 

Report Viewer: Berichte mit Master-Detail-Ansicht

Grundsätzlich ist ja der Aufbau der Reports so, dass alles von oben nach unten abgearbeitet wird. Wenn wir beispielsweise zwei Tabellen (Tablix-Elemente) mit Schülern und Noten untereinander setzen, dann bekommen wir zuerst alle Schüler und danach die Notenliste.

In einem Bericht möchte man aber häufig eine kombinierte Ansicht. Man möchte nacheinander alle Noten pro Schüler … und das am besten seitenweise getrennt.

Wenn man das mit RDLC-Files machen möchte dann bereitet man die Daten am besten in einer flachen Tabelle vor. Jede Zeile hat also neben der Schülerinformation (z.B. Name, Geburtsdatum, …) auch die Informationen zu der einzelnen Note (z.B. Fach, Note).

In der Design-Ansicht des Berichts, muss man dann die Notentabelle in ein List-Elemente packen. Bei diesem List-Element stellt man unter „Row Properties“ eine Gruppierung über die Schüler ein und den Seitewechsel nach jedem Schüler.

Die Tabelle innerhalb bekommt dann automatisch alle Zeilen dieses Schülers. Wenn man in der Tabelle eine „Column Group“ mit Gruppierung über das Fach definiert, dann sieht man für jede Note des jeweiligen Fachs eine Spalte. Bilder dazu folgen, wenn ich mehr Zeit habe …

Streng genommen ist ein List-Element (mittlerweile) ein spezielles Tablix-Element. Beispiel zu beiden Varianten findet man hier:

http://www.gotreportviewer.com/masterdetail/index.html

Cheers,
Ralf

Report Viewer: Es muss nicht immer teuer sein

Bisher dachte ich, man bräuchte zwingend ein „Third-Party“-Produkt, um praktikabel Berichte unter .NET (Windows Forms) zu erzeugen. Viele Stimmen sagten immer, dass es zu kompliziert wäre mit den Boardmitteln von MS einen Ausdruck zu erzeugen oder PDF-Dokumente zu generieren.

Mit der Report Viewer Engine ist dies aber meiner Meinung nach durchaus möglich. Sie ist in Visual Studio integriert und bedarf beim Deployment lediglich einer zusätzlichen Setup-Anwendung (man kann bestimmt das auch über ein MSM-File in das eigene Setup einbauen, aber Setups sind bei unseren Projektentwicklungen nicht das Thema).

Als Einstieg hatte ich mir einfach den ersten Treffer bei Google angesehen und dabei auch gleich ein paar nette Beispiele entdeckt:
http://www.gotreportviewer.com/

Natürlich ist das ganze nicht so komfortable wie gekaufte Produkte und hat leider auch ein paar Macken, die man relative schnell entdeckt und sich deshalb auch etwas über Microsoft wundert :-)

  1. Ärgerlich ist, dass bei der Undo- bzw. Redo-Programmierung gespart wurde. Ich hatte ein paar Mal erlebt, dass bei Redo sich Visual Studio verabschiedete und Undo nicht den letzten Schritt wiederherstellte, sondern einen der ersten Schritte … Auf Redo verichte ich ganz, speichere deshalb vor Undo lieber regelmäßig ab.
  2. Im Internet sind häufig ältere Samples zu finden, die dann in VS 2010 zuerst hochkonvertiert werden. Führt man mit der neue VS-Version die beschriebenen Schritte in der IDE durch kommt es leider hin und wieder  vor, dass das Verhalten beider Varianten  nicht identisch ist. Da hilft ein Blick in die XML-Struktur der RDLC-Datei.
  3. Hin und wieder bleibt das „Report Data“-Fenster auch in der Codeansicht offen und wird dann nicht neugezeichnet. Sieht hässlich aus, stört aber eigentlich nicht wirklich.

Es lohnt sich mal einen Versuch zu wagen. Setzt man rdlc-Files gepaart mit xsd-Files bekommt man auch mit MS-Mitteln einen ansprechenden Bericht unter Windows-Forms hin ohne eine Zeile zu coden.

Cheers,
Ralf

Windows Forms: Elemente zentrieren

Die Ausrichtung der Elemente beeinflusst man bekannterweise mit der „Align„-Eigenschaft, die jedes visuelle Elemente anbietet. Dort gibt es allerdings nur left, right, top und bottom, sowie Kombinationen aus diesen.

Bisher hatte ich es nicht gebraucht und dachte aber man müsse bereits zur Tastatur greifen (sprich coden), wenn man eine zentrierte Ausrichtung haben möchte und dafür das Resize-Ereignis abfischen. Das ist natürlich Blödsinn … wenn man das Element in der Design-Ansicht manuell zentriert, kann man einfach die entsprechenden Align-Optionen ausschalten und man zentriert es für diese Achse. Soll also das Element horizontal zentriert werden, dann schaltet man left und right aus, soll vertikal zentriert werden, dann einfach top und bottom abwählen.

Hier die Referenz, die mich auf diese Idee brachte:
http://wannabedeveloper.wordpress.com/2007/03/23/center-align-on-windows-forms/

Cheers,
Ralf

JQuery: Änderungen an HTML Elementen bewirken nichts

Jetzt bin ich schon zum zweiten Mal auf das gleiche Problem gestoßen und muss es jetzt endlich mal dokumentieren … vielleicht komme ich beim nächsten Mal  ja schneller auf die richtige Spur.

Wenn man mittels JQuery eine Checkbox als „checked“ markieren will, dann würde man das normalerweise so versuchen:

$("#myCheckbox").attr("checked", true);

Leider schlägt das nicht durch, weil die Checkbox sich scheinbar nicht neu zeichnet. Man muss das leider manuell anstoßen:

$("#myCheckbox").attr("checked", true).trigger("change");

Selbiges kann man beim Anzeigen/Verstecken von <legend> Elementen beobachten:

$('.tx-powermail-pi1_fieldset').children('legend')
  .css('visibility','visible').trigger("change");
Cheers,
Ralf

Typo3: Backend HTML Editor „aufbohren“

Standardmäßig erlaubt der Texteditor im TYPO3-Backend keine Textfarbe zu ändern. Es gibt sehr viele Möglichkeiten die Konfiguration des Editors zu ändern, aber „wenn’s mal wieder schnell gehen soll“, dann kann man auch einfach die „typische“ Einstellung ändern. Dafür muss man in der Datei:

/typo3/sysext/rtehtmlarea/res/typical/pageTSConfig.txt

einfach die Zeile 118 (könnte sich bei einer späteren Installation verschieben) etwas hinzufügen.
Original Block:

showButtons (
 class, blockstylelabel, blockstyle, textstylelabel, textstyle,
 formatblock, bold, italic, subscript, superscript,
 ...

Nach der Änderung:

showButtons (
 class, blockstylelabel, blockstyle, textstylelabel, textstyle,
 formatblock, bold, italic, subscript, superscript,
 textcolor, bgcolor, fontsize,
 ...

Die deutlich elegantere Variante ist natürlich die Anpassung im TSConfig der Page. Meine Methode hat den Charme, dass man sich eine Standardinstallation mit seinen „typical“ Einstellungen machen kann.

Cheers,
Ralf

MySQL: Fehlende Einträge finden

Hin und wieder sucht man in zwei ähnlichen Tabellen nach fehlenden Einträgen. Das kommt beispielsweise vor, wenn wir zwei unterschiedliche Versionsstände einer Tabelle haben und diese vergleichen wollen. Nehmen wir an wir haben zwei Tabellen.

Tabelle „A“:

ID DESCRIPTION
1 Name1
2 Name2
4 Name4

Tabelle „B“:

ID DESCRIPTION
1 Name1
3 Name3
4 Name4

Bei einem Microsoft SQL Server würde man jetzt mit full outer join arbeiten:

SELECT A.ID as A1, B.ID as B1 
FROM A FULL OUTER JOIN B ON A.ID = B.ID
WHERE A.ID is null OR B.ID is null;

Als Ergebnis bekämen wir  hier zwei Zeilen und wüssten dann, dass in B die ID 2 fehlt und in A die ID 3.

A1 B1
2 null
null 3

Leider gibt es das bei MySQL nicht direkt, weil bei diesem Datenbankserver  „full outer join“ nicht unterstützt wird. Man muss also statt „full outer join“ den Ausdruck in zwei Teile mit zwei „joins“ aufteilen:

SELECT A.ID as A1, B.ID as B1 
FROM A LEFT OUTER JOIN B 
ON A.ID = B.ID
WHERE B.ID is null
UNION 
SELECT A.ID as A1, B.ID as B1
FROM A RIGHT OUTER JOIN B 
ON A.ID = B.ID
WHERE A.ID is null;

Hier ist eine nette Seite, die das Thema auch beschreibt:
http://www.peterkropff.de/site/mysql/full_outer_join.htm

Cheers,
Ralf

MySQL: Inner joins vs. sub queries

Heute wollte ich Kunden aus der Tabelle „Customers“ heraussuchen für die es in der Tabelle „Orders“ mindestens einen Auftrag gibt.

Mein erster Wurf dauerte 714 Sekunden:

SELECT * FROM customers WHERE ID in 
(SELECT customerID FROM orders group by customerID);

Der Verdacht liegt nahe, dass die Subquery hier nicht die richtige „Waffe“ ist:

select * from customers,
(SELECT customerID FROM orders group by customerID) as b 
where id = b.customerID;

Gleiches Ergebnis, aber schon nach 1,5 Sekunden. Eine gute Erklärung liefert folgender Thread:
http://stackoverflow.com/questions/141278/subqueries-vs-joins

Zusammenfassend kann man sagen, dass Subqueries zeilenweise immer wieder neu berechnet werden … leider auch, wenn keine Infos aus der Zeile benötigt werden.

Cheers,
Ralf

Webentwicklung: WordPress als Blogger-Plattform

Mein erster Blog-Eintrag ist eine Hommage an WordPress als Blogger-Plattform. Normalerweise  mag man als Coder flexible und damit auch meist komplizierte Systeme. Wordpress ist diesmal das genaue Gegenteil: es ist sehr einfach und ich mag es :-)

Die berühmte „Fünf-Minuten-Installation“ hält was sie verspricht:
http://dokupress.de/wordpress-benutzerhandbuch/installation/neue-installation/datenbank-verbindung/5-minuten-installation/

Durch das Theme-basierte Design der Plattform kann man einfach das gewünschte Layout anflanschen:
http://wordpress.org/extend/themes/

Wenn ein Theme noch nicht 100% passt, kann man seine Anpassungen einfach in CSS und PHP vornehmen. Mein Basis-Theme ist „Martin“ von Themestown:

http://wordpress.org/extend/themes/martin

Plugins lassen die Funktionalität einfach erweitern. Ich werde demnächst mal auf die Suche gehen, ein Plugin für Code-Highlighting und eins für Thumbshots zu suchen. Sonst bietet bereits die Grundinstallation schon fast alles was das Herz begehrt.

Cheers,
Ralf