in

DevWare GmbH

Blog- und Forum-Seite der Firma DevWare GmbH

Tibor Csizmadia

Dezember 2006 - Posts

  • Online-Hilfe aus Word-Dokument

    Heute ist so ein Tag (man nennt es ja auch so schon Zwischen den Jahren) an dem ich so richtig viel Zeit habe und mal Dinge aufarbeite zu den ich sonst nicht komme. Und was macht man dann als Softwareentwickler:

    Genau das was "wir" ja sonst so ungern machen: Dokumentation schreiben und Online Hilfe Files. Dabei habe ich nach einer schnellen und einfachen Lösung gesucht aus einem Word-Dokument ein richtiges chm-Helpfile zu generieren. Nachdem ich mir das "Html Help Workshop" Tool angeschaut hatte und schnell festgestellt habe, dass es nicht so einfach war aus meinem Word-Handbuch in ein chm-Helpfile zu generieren. So bin ich auf ein Smartes Tool Doc2Chm von der Firma Dawningsoft (http://www.dawningsoft.com/products/doc2chm.htm ). Damit lässt sich ganz schnell aus einem Word-Dokument ein Chm-File erzeugen wobei man auch noch einige Parameter konfigurieren kann.

    Dieses File habe ich dann in meine Solution mit aufgenommen und die Build-Action auf Content und das Property "Copy to Output Directory" auf "Copy allways". Somit kann man das Help-File aus seinem Programmcode wie folgt benutzen:

    private void onlineHilfeToolStripMenuItem_Click(object sender, EventArgs e)
    {
     
    Help.ShowHelp(this, "BusinessNewsDB.chm" );
    }

    Das war jetzt so einfach, das ich mich Frage warum wir nie Online-Hilfen mit unseren Applikation erstellen?

  • Databound Header/Footer Fields in Reporting-Service

    Heute bin ich auf ein echt gravierendes Problem beim erstellen von Reports mit den Microsoft Reporting Service gestoßen. Ich wollte in meinen Header einige Datenfelder Benutzer mit First() so das z.B. die Adresse eines Lieferscheins im Header Bereich benutzt werden kann. Leider kommt dann beim kompilieren des Reports die Fehlermeldung: "Felder können in Seitenkopfzeilen oder –fußzeilen verwendet werden". Da ich allerdings den Content-Bereich im Report dreispaltig aufbauen wollte und die Anschrift natürlich nicht in das dreispaltige Layout platzieren wollte, musste ich eine andere Lösung finden. Da bin ich auf folgenden Artikel aufmerksam geworden (http://msdn2.microsoft.com/en-us/library/ms159677.aspx) Dort wird ein kleiner Trick beschrieben, womit man im Header Bereich über die Referenz einer Textbox im Content Bereich auf den ersten Wert zugreifen kann.

    Leider ist das wirklich ein Workaround und von einem Reporting–Tool hätte ich eigentlich eine saubere Lösung erwartet…

  • Kalenderwoche aus DateTime ermitteln

    Heute bin ich auf einen echt sehr guten Tipp gestoßen, nachdem ich seltsame Implementierung gefunden habe. Ich war auf der Suche nach einer einfachen Möglichkeit unter .Net die Kalenderwoche aus einer DateTime Struktur zu ermitteln. Ich war sehr erstaunt darüber das diese Funktion nicht in der Klasse DateTime implementiert ist.

    Dann machte ich mich bei Google & Co auf der Suche nach einem einfachen Algorithmus....dabei sind mir echt abstruse Kandidaten untergekommen, aber auf diese Lösung wär ich nicht gekommen:

    using System;
    using System.Globalization ;

    namespace ConsoleApplication1
    {
        class Class1
        {
            [STAThread]
            static void Main(string[] args)
            {
                DateTime dt = DateTime.Now;
                System.Globalization.Calendar objCal = CultureInfo.CurrentCulture.Calendar;    
                int weekofyear = objCal.GetWeekOfYear(dt, CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday);
                
                Console.WriteLine(weekofyear.ToString() ) ;
            }
        }
    }

     Somit ist mein Erstaunen über das Fehlen der Funktion in der DateTime-Klasse wieder beruhgt worden: .Net ist eben cool!

     

  • Visual Studio 2005 Web-Projekte + IIS7 unter Vista

    Ich habe mich gewundert warum meine ASP.NET Projekte unter VS2005 und Vista nicht mehr richtig funktionieren und nach langem Suchen bin ich dann auf das Blog von Sarang Datye (http://sarangdatye.blogspot.com/2006/11/windows-vista-iis7-vs2005-confusion.html) gestossen und endlich eine Lösung gefunden.

    Da wird nur mal wieder bewußt wie Abhängig einige Applikation von der Administrator- Rolle sind!

     

  • SQL-Server Installation auf Vista

    Heute habe ich mal feststellen müssen, dass die Installation des SQL-Servers 2005 auf einem Vista Betriebsystem nicht so einfach ist! Nachdem ich über Google auf Steffen Krause´s Blog Eintrag zum Installieren von SQL auf Vista (http://blogs.technet.com/steffenk/archive/2006/11/07/reporting-services-unter-vista.aspx ) gestoßen bin, hat die Installation auch geklappt. Allerdings habe ich anscheint etwas noch falsch gemacht, da ich mit dem SQL Managment Studio keine Verbindung zu der SQL-Instanz aufbauen konnte. Es erscheint immer wieder die Meldung:

    Attachment: SQLError18456.jpg (16641 bytes)

    Wenn man dann nach dieser Fehlermeldung einmal im Internet sucht, stößt man auf eine KB-Eintrag http://support.microsoft.com/kb/925744/en-us der darauf hindeutet, das es wohl ein Problem ist und erst im nächsten SP des SQL Servers (Also SP2) gefixt ist. Da ich mir den Rechner nicht mit einem CTP des SP2 vollmüllen wollte habe ich frustriert aufgegeben und mir hier mal einen Server beschafft, um dort SQL-Server 2005 zu installieren. (Zum Glück haben wir einen grooossseeennn Server auf dem Virtuell Server läuft, somit war das eben so einfach wie SQL-Server dann auch dort zu installieren.)

    Posted Dez 05 2006, 05:47 by Tibor Csizmadia with no comments
    Filed under:
  • Royalty@Night -Veranstaltung und das ISV- Royalty -Programm

    Ich vergaß ganz letzte Woche meine Eindrücke zu der Veranstaltung „Die Vermarktung von SQL Server 2005 im ISV Royalty-Lizenzprogramm (Royalty@Night)  “bei Microsoft in Neuss zu schreiben. Aufgrund geringer Teilnehmerzahl war es dann auch eine recht gemütliche Veranstaltung, nicht mehr als 5-6 Unternehmen schienen sich für das Thema zu interessieren. Ich frage mich ob es ein gutes Zeichen ist oder ehr ein schlechtes. Bedeutet es nun das es in Deutschland so wenige ISV (Independent Software Vendor, sprich Softwarehersteller) gibt, oder hierzulande einfach keine Software produziert wird? Natürlich ist das Thema Lizenzierung von Microsoft Software nicht gerade eins der spannendsten, wobei ein Einkäufer oder ein Geschäftsführer sollte sich schon einmal die Frage stellen, ob man seinen Einkauf von Lizenzen nicht optimieren kann.

    Auch aus diesem Grund wollte ich mir die Veranstaltung anschauen, um ggf. nach neuen Beschaffunsgwegen zu forschen. Mein Ansatz ist dabei immer schon gewesen, das wir als ISV eine Menge für Microsoft tun, da ohne die Lösungen hätte sich ein Betriebsystem Windows nicht so verbreitet. Um so ärgerlicher war es in der Vergangenheit, das man keine Möglichkeit bekommen hatte entsprechend seines Status von Microsoft direkt zu kaufen.

    Diesen Umstand soll das ISV- Royalty Programm beheben (es gab in der Vergangenheit schon dieses Programm nur mit etwas anderen Bedingungen), so dass man sich zu einem Mindestumsatz und einer Laufzeit verpflichtet und erhält dann entsprechende Lizenzen zu einem durchaus viel günstigeren Preis als im Laden oder über entsprechend OPEN oder SELECT Verträge.

    Das klingt erstmal ganz gut, allerdings sehe ich auch einige Probleme.

    Einmal sind nicht alle Produkte in diesem Royalty Programm, so stehen z.B. Betriebsystem nicht auf der Liste, was ich als Lösungsanbieter aus einer Hand nicht ganz nachvollziehen kann. Da ich dem Kunden ein komplett Angebot unterbreite ggf. noch mit Hardware.

    Auf der anderen Seite benutzen wir für unsere Lösung den Microsoft SQL Server der mittlerweile ja schon (fast) Betriebsystem – Status erfahren hat, weil sehr viele Produkte von Microsoft den Server auch nutzen. Somit ist die Runtime-Lizenz aus dem Roality Programm nicht ganz so interessant, da diese dann lizenztechnisch auf eine Lösung beschränkt ist. D.h. Sollte ich einmal einen Kunden die Runtime-Lizenz des SQL Servers als Vollversion angeboten haben und der Kunde möchte dann noch zusätzlich eine andere Applikation mit dieser SQL-Instanz laufen lassen, ist es lizenztechnisch (und ob es auch technisch nicht geht weiß ich nicht) nicht erlaubt. Somit würde der Kunde verärgert sein und ich mit meinem Angebot schon wieder gar nicht so gut dastehen. Somit bleibt nur die Vollversion des SQL-Servers zu nehmen und da schwindet schon wieder meine neu gewonnen Marge, die ich aus dem Royalty Programm erhofft hatte.

    Somit ist die Aussage eines Referenten schon ganz hilfreich gewesen; wenn man sich nur auf die SQL-Lizenz aus dem Royalty Programm stützt, wird man den Mindestumsatz kaum erreichen.

    Ein Trostpflaster gibt es allerdings noch, in Zukunft soll auch der Microsoft Small Business-Server 2003 in das Programm aufgenommen werden.

     Attachment: ISV.jpg (15599 bytes)

     

    Posted Dez 04 2006, 08:13 by Tibor Csizmadia with no comments
    Filed under:
  • Tipps und Tricks mit dem ReportViewer-Control für Local-Reports

    Die Reporting Features vom neuen SQL-Server 2005 finde ich als AdHoc Lösung ein schneller und eleganter Weg, um Daten anspruchsvoll zu präsentieren UND auch noch einfach druckbar oder nach PDF konvertierbar zu machen.  Wir setzten in vielen Projekten schon die Reporing Service ein, wobei ich festgestellt habe, das die der Einsatz von lokal gerenderten Reports ebenso einfach wie elegant eingsetzt werden kann. Lokale-Reports können mit dem Visual Studio 2005 auch ohne SQL-Reporting Service erzeugt und gerendert werden. Der einzige Nachteil dabei ist, dass man sich selber um die Datenquellen und Daten kümmern muß. Da ich diese Möglichkeit in einem aktuellen Projekt eingesetzt habe und einige Fallstricke bei der Benutzung des ReportViewer-Control festgestellt habe, wird ich mal einige Punkte hier beleuchten:

    SampleReport.rdl = SampleReport.rdlc

    Auch wenn in einem VS-Projekt die beiden Reportarten mit unterschiedlichen File-Extensions aufgelistet werden, sind die Dateiformat kompatibel. D.h. Wenn man ein Server-Report *.rdl in ein lokalen – Report umwandeln möchte, muss man nur das File von *.rdl in *.rdlc umbenennen. Dadurch gewinnt man auch noch den XML-Konten für das SQL-Sequenz, um die Daten für diesen Report zu ermitteln. Das habe ich mir zum nutzen gemacht, um die Reports einfach mit dem Server-Report Designer zu erstellen (was im übrigen dann sehr elegant ist, da man den Report inkl. SQL-Statement konfigurieren kann) und dann in das entsprechende Projekt als *.rdlc rein kopieren. Mit dem folgenden Code kann man dann so einen Report einfach lokal laden und render inkl. Datenermittlung:

    private void LoadReportData(Dictionary<string, object> myParamValues)

    {

               

    // Daten laden    

           string mySQL = "";

           XmlDocument myReportXML = new XmlDocument();

           myReportXML.Load(this.reportViewer1.LocalReport.ReportPath);

           XmlNodeList myList = myReportXML.GetElementsByTagName("DataSet");

     

           this.reportViewer1.LocalReport.DataSources.Clear();

           foreach (XmlNode myDSNode in myList)

           {

                        DataTable myDataTable = new DataTable(myDSNode.Attributes["Name"].Value);

                   XmlNode myQuery = FindXmlNode(myDSNode, "Query");

                   if (myQuery != null)

                   {

                        XmlNode myCmd = FindXmlNode(myQuery, "CommandText");

                        XmlNode myDSName = FindXmlNode(myQuery, "DataSourceName");

     

    SqlDatabase myDB = new SqlDatabase(ConfigurationManager.ConnectionStrings["mySQLConnectionString"].ConnectionString);

            SqlCommand myCmd = new SqlCommand(sSql);

     

     

           if (myParams != null)

                  {

                        foreach (string myParam in myParams.Keys)

                                myCmd.Parameters.Add(new SqlParameter(myParam, myParams[myParam]));

                        }

     

           DataSet myDS = myDB.ExecuteDataSet(myCmd);

     

                        if (myDS.Tables.Count > 0)

                                      myDataTable =myDS.Tables[0]);

                        else

                               myDataTable = new DataTable();

               

         

                        ReportDataSource myData = new ReportDataSource(myDSName.InnerText, myDataTable);

     

                        this.reportViewer1.LocalReport.DataSources.Add(myData);

                }

           }

     

           this.reportViewer1.RefreshReport();

           this.reportViewer1.Update();

    }

    Diese Funktion holt nun aus der *.rdlc XML-Datei das SQL-Statement und führt es, wobei dieser Funktion auch noch ein Array mit Eingabeparametern übergeben werden kann.

    Parameter-Eingabe bei lokalen Reports im ReportViewer-Control

    Die Parameter-Definition von Reports ist leider bei den lokal gerenderten reports nicht so vollständig implementiert wie bei den serverseitigen Reports. Somit stellt sich das ReportViewer-Control auch im Bereich der Parametr anders dar. Zum Leid der Entwickler muss man sich für die Paramtereingabe eine eingene Lösung bauen, da das Parameter-Panel mit der dynamisch generierten Eingabecontrols für lokale Reports nicht zur Verfügung steht.

    Ich habe mir dazu einfach ein Usercontrol gebaut, dem ich einfach per Methode ein Array der ReportParameter übergebe und dieses dann die Eingabecontrols dynmisch generiert:

    public void SetParamWindow( ReportParameterInfoCollection myParams )

    Dieses Control habe ich dann in meinem eigenen Report-Viewer Control, welches aus einem Split-Container mit zwei Panels besteht und dort einmal mein Parameter-Control und auf der anderen Seite das ReportViewer-Control befinden. Die Parameter werden dann wie folgt an das Parameter-Control übergeben:

    // prüfe ob Report mit Parameter?

    ReportParameterInfoCollection myParams = reportViewer1.LocalReport.GetParameters();

    if (myParams != null && myParams.Count > 0)

    {

    splitContainer2.Panel1Collapsed = false;

    ucReportParameters1.SetParamWindow(myParams);

    }

    else

    {

    splitContainer2.Panel1Collapsed = true;

    LoadReportData(null);

    }

     

    Reports dynamisch dem ReportViewer-Control zuweisen

    Nach den o.b. Hürden war ich nun überglücklich lokal gerenderte Reports einfach wie serverseitige Reports zu designen und im ReportViewer-Control auch genau so darzustellen. Nun lässt die Methode this.reportViewer1.RefreshReport()darauf schlissen, dass mit der Kombination des Properties this.reportViewer1.LocalReport.ReportPath (welches als  ein Getter und ein Setter besitzt) dem ReportVIewer-Control auch zur Laufzeit einmal einen neuen Report zur Darstellung mitgeben kann. Leider hat sich nach einigen frustrierten Test ergeben, das dieses nicht so funktioniert. Entweder ist es ein Feature oder ein Bug! Da ich diese Funktionalität allerdings unbedingt benötigte habe ich mir ein Workaround (mal wieder) gebaut. Der einfachste Trick der mir dazu eingefallen war ist, das anscheint dieses Property nur beim Erzeugen des Controls ausgewertet wird. Somit habe ich in mein Panel vom Split-Container, welches das ReportViewer-Control beinhalttet, einfach zum Zeitpunkt des Neuladen eine neue Instanz des ReportViewer-Control erzeugt habe.

    Somit ergibt sich eine Lade-Methoide für neue Reports wie folgt:

    private void LoadReportByClient(string sPath)

    {

    this.splitContainer2.Panel2.Controls.Clear();

    this.reportViewer1 = new Microsoft.Reporting.WinForms.ReportViewer();

    this.reportViewer1.Dock = System.Windows.Forms.DockStyle.Fill;

    this.reportViewer1.Location = new System.Drawing.Point(0, 0);

    this.reportViewer1.Name = "reportViewer1";

    this.reportViewer1.Size = new System.Drawing.Size(454, 366);

    this.reportViewer1.TabIndex = 0;           

    this.splitContainer2.Panel2.Controls.Add(this.reportViewer1);

     

    this.reportViewer1.LocalReport.ReportPath = sPath;

                                      

    // prüfe ob Report mit Parameter?

    ReportParameterInfoCollection myParams = reportViewer1.LocalReport.GetParameters();

    if (myParams != null && myParams.Count > 0)

    {

    splitContainer2.Panel1Collapsed = false;

    ucReportParameters1.SetParamWindow(myParams);

    }

    else

    {

    splitContainer2.Panel1Collapsed = true;

    LoadReportData(null);

    }

    this.reportViewer1.LocalReport.ReportPath                      

    }

     

Copyright (c) 2008 DevWare GmbH. All rights reserved.
Powered by Community Server (Non-Commercial Edition), by Telligent Systems