DevTrain

Autor: Tobi Ulm

ASP .NET Master - Detail Grid like WinForms

Hallo, sicherlich hat der eine oder andere Coder festgestellt, das Microsoft im Objektmodell des Frameworks einen guten Job getan hat. Dennoch gibt es einige Controls die sich unterscheiden, so z.B. das DataGrid. In Windows Forms ist das Grid sehr zuvorkommend und visualisiert, falls vorhanden, Master Detail Datensätze. Dies geht leider nicht mit dem ASP .NET DataGrid. Aus diesem Grund will ich Ihnen heute zeigen wie Sie a) ein ASP.NET Custom Control und b) eine Master Detail Darstellung erstellen können. Der Quellcode ist ziemlich einfach, es gibt eine Menge an HTML Tags zu implementieren auf den ich nicht eingehen werde, denn die können Sie nach ihren Tabellenwünschen ändern.

 

Ein Custom Control ist eine Klasse welche normalerweise von der Klasse System.Web.UI.WebControls.WebControl abgeleitet wird. In unserem Fall wollen wir aber die Grundfunktionalität des originalen DataGrids nutzen und leiten unsere Klasse nun von DataGrid ab:

[ToolboxData("<{0}:MDGrid runat=server></{0}:MDGrid>")]public class MDGrid : DataGrid{...}

Beachten Sie bitte das Attribut welches vor der Klasse steht. Hierbei handelt es sich um Metainformationen für Visuelle Entwicklungsumgebungen, wie in der ASP Seite das Control registriert und verwendet werden soll, vergleichen Sie z.B. den Button Tag <asp:Button /> in der HTML Ansicht einer *.aspx Seite.

 

Für alle WebForm Controls gilt es nun eine sehr wichtige Methode zu implementieren, die Methode Render(). Diese Methode ist dafür zuständig das Control zu visualisieren. Normalerweise wird an den Client (Browser) ein HTML Stream (Zeichenkette) zurückgeschickt. Diese Zeichenkette wird durch den HTMLTextWriter erzeugt der in der Render() Funktion als Argument deklariert ist. Wollen Sie also eine Überschrift erster Ordnung in den Client Content schreiben, sollten Sie die Methode HTMLTextWriter.Write() verwenden.

output.Write("<h1>Hallo</h1>");

In unserem Fall werden innerhalb der Render Methode Tabellen erzeugt, aber: Es ist ja möglich zum Beispiel eine ArrayList als DataSource an das Grid zu binden und dort gibt es keine Relationen zwischen Master Record und Detail Records. Aus diesem Grund füge ich nach der Deklaration der Methode Render() folgende if Bedingung ein:

if ( (this.DataSource.GetType().BaseType.Equals(typeof(DataSet))) || (this.DataSource.GetType().Equals(typeof(DataSet))) ){

else{

base.Render(output);

}

Diese if Bedingung ermittelt ob die gebundene Datenquelle vom Typ eines DataSets ist. Dies geschieht leider in zwei Wegen, da ein durch Visual Studio erzeugtes (klicki bunti) DataSet eine eigene Klasse (welche von DataSet abgeleitet)ist, muss ich hier auch den BaseType abfragen! Wenn die DataSource ein vom Typ eines DataSets ist werden wir eine eigene Visualisierung erzeugen ansonsten gilt: DataGrid du machst das schon: base.Render(...);

Nun folgt erst einmal der Aufbau einer äußeren Tabelle in der wir dann die Master- Detaildaten visualisieren.

Die Visualisierung erfolgt komplett im Client, d.h. wir benötigen JavaScript und Layers (Divs) in denen wir die Detaildaten halten. Wie bereits erwähnt, ist die Tabelle eine reine Geschmackssache. Für die eigentliche Darstellung jedoch ist die Ermittlung der Detaildatensätze wichtig. Dies geschieht folgendermaßen:

Wir iterieren durch die Masterdatensätze mit einer einfachen for () Schleife:

for ( int iCol = 0; iCol < ((DataSet)this.DataSource).Relations[0].ParentTable.Columns.Count; iCol++ ){ ... }

In dieser Schleife können wir dann durch die Relation[0] die zugeörigen Detaildaten ermitteln:

DataRow[] drChildren = null; ...

drChildren = ((DataSet)this.DataSource).Relations[0].ParentTable.Rows[iRow].GetChildRows(((DataSet)this.DataSource).Relations[0]);

Fertig!

Kompilieren Sie den Code in eine Library und setzen Sie einen Verweis in einem ASP.NET Projekt oder fügen Sie diese DLL in die ToolBar von Visual Studio .NET hinzu.

 

Nun der gesamte Code des Controls:

using System;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.ComponentModel;
using System.Data;
namespace tu.Web.UI.Data.MasterDetailGrid
{
 [ToolboxData("<{0}:MDGrid runat=server></{0}:MDGrid>")]
 public class MDGrid : DataGrid
 {
  #region "datamember"
  private const string _scriptMD = "<script language='Javascript'>" +
   "<!-- \n" +
   "function Point(strImage){\n" +
   "//'--- Make the cursor a hand for the item passed in.\n" +
   "var theItem;\n" +
   "theItem = window.document.getElementById(strImage);\n" +
   "if(theItem == null){\n" +
   "theItem = window.document.getElementsByName(strImage);\n " +
   "}\n" +
   "theItem.className='Point' ;\n" +
   "}\n" +
   "function DontPoint(strImage){\n" +
   "// '--- Make the cursor normal for the item passed in.\n" +
   "var theItem ;\n " +
   "theItem = window.document.getElementById(strImage);\n" +
   "if(theItem == null){\n" +
   "theItem = window.document.getElementsByName(strImage);\n " +
   "}\n" +
   "theItem.className = 'DontPoint';\n" +
   "}\n" +
   "function DisplayItem(strImage, strDiv){\n" +
   "var strDisplay = window.document.getElementById(strDiv).style.display;\n" +
   "var theItem;\n" +
   "theItem = window.document.getElementsByName(strImage);\n" +
   "if ( theItem == null){\n" +
   "theItem = window.document.getElementById(strImage)\n" +
   "}\n" +
   "//'--- Check if the DIV is already displayed\n" +
   "if ( strDisplay == 'none') {\n" +
   "//'--- And we need to change the image to the MINUS\n" +
   "theItem.src = 'Minus.GIF';\n" +
   "//'--- We need to display the DIV\n" +
   "strDisplay = '';\n" +
   "}\n" +
   "else{\n" +
   "//'--- And we need to change the image to the PLUS\n" +
   "theItem.src = 'Plus.GIF';\n"+
   "//'--- We need to hide the DIV\n" +
   "strDisplay = 'none';\n" +
   "}\n" +
   "window.document.getElementById(strDiv).style.display = strDisplay;\n" +
   "}\n//-->\n" +
   "</script>\n";
  private const string _styleMD = "<style>\n" +
   "<!--\n" +
   "FONT {\n" +
   "FONT-FAMILY: Arial, Verdana;\n" +
   "}\n" +
   ".Point {\n" +
   "CURSOR: hand;\n" +
   "}\n" +
   ".DontPoint {\n" +
   "CURSOR: default;\n" +
   "}\n" +
   "//--></style>\n";
  private System.Drawing.Color mastertableHeaderBgColor = System.Drawing.ColorTranslator.FromHtml("#000080");
  private System.Drawing.Color mastertableHeaderFontColor = System.Drawing.ColorTranslator.FromHtml("#ffffff");
  private System.Drawing.Color mastertableCellBgColor = System.Drawing.ColorTranslator.FromHtml("#ffffc0");
  private System.Drawing.Color mastertableCellFontColor = System.Drawing.ColorTranslator.FromHtml("#000080");
  private System.Drawing.Color detailtableHeaderBgColor = System.Drawing.ColorTranslator.FromHtml("#000080");
  private System.Drawing.Color detailtableHeaderFontColor = System.Drawing.ColorTranslator.FromHtml("#ffffff");
  private System.Drawing.Color detailtableCellBgColor = System.Drawing.ColorTranslator.FromHtml("#ccccff");
  private System.Drawing.Color detailtableCellFontColor = System.Drawing.ColorTranslator.FromHtml("#000080");
  private bool showBorder = false;
  private int borderWidth = 0;
  #endregion
  #region "properties"
  public int MasterTableBorderWidth{
   get{
    return this.borderWidth;
   }
   set{
    this.borderWidth = value;
   } 
  }
  public bool Border{
   get{
    return this.showBorder;
   }
   set{
    this.showBorder = value;
   }
  }
  
  public System.Drawing.Color MasterTableHeaderBgColor{
   get{
    return this.mastertableHeaderBgColor;
   }
   set{
    this.mastertableHeaderBgColor = value;
   }
  }
  public System.Drawing.Color MasterTableHeaderFontColor{
   get{
    return this.mastertableHeaderFontColor;
   }
   set{
    this.mastertableHeaderFontColor = value;
   }
  }
  public System.Drawing.Color MasterTableCellBgColor{
   get{
    return this.mastertableCellBgColor;
   }
   set{
    this.mastertableCellBgColor = value;
   }
  }
  public System.Drawing.Color MasterTableCellFontColor{
   get{
    return this.mastertableCellFontColor;
   }
   set{
    this.mastertableCellFontColor = value;
   }
  }
  public System.Drawing.Color DetailTableHeaderBgColor{
   get{
    return this.detailtableHeaderBgColor;
   }
   set{
    this.detailtableHeaderBgColor = value;
   }
  }
  public System.Drawing.Color DetailTableHeaderFontColor{
   get{
    return this.detailtableHeaderFontColor;
   }
   set{
    this.detailtableHeaderFontColor = value;
   }
  }

  public System.Drawing.Color DetailTableCellBgColor{
   get{
    return this.detailtableCellBgColor;
   }
   set{
    this.detailtableCellBgColor = value;
   }
  }
  public System.Drawing.Color DetailTableCellFontColor{
   get{
    return this.detailtableCellFontColor;
   }
   set{
    this.detailtableCellFontColor = value;
   }
  }
  #endregion
  /// <summary>
  /// Stellen Sie das Steuerelement für den angegebenen Ausgabeparameter an.
  /// </summary>
  /// <param name="output"> Der HTML-Writer zum Schreiben in </param>
  protected override void Render(HtmlTextWriter output) {
   if ( (this.DataSource.GetType().BaseType.Equals(typeof(DataSet))) || (this.DataSource.GetType().Equals(typeof(DataSet))) ){
    //putting in the DIV Style and the JavaScript
    output.WriteLine(_styleMD);
    output.WriteLine(_scriptMD);
   
    output.WriteBeginTag("table");
    output.WriteAttribute("width", "100%", true);
    output.WriteAttribute("border", "1", true);
    output.WriteAttribute("cellpadding", "0", true);
    output.WriteAttribute("cellspacing", "0", true);
    output.Write(">");
    output.RenderBeginTag("tr");
    output.RenderBeginTag("td");

    output.WriteBeginTag("table");
    output.WriteAttribute("width", "100%", true);
    if ( this.showBorder ){
     output.WriteAttribute("border", this.borderWidth.ToString(), true);
    }
    else{
     output.WriteAttribute("border", "0", true);
    }
    output.WriteAttribute("cellpadding", "0", true);
    output.WriteAttribute("cellspacing", "0", true);
    output.Write(">");
    output.WriteBeginTag("tr");
    output.WriteBeginTag("td");
    //output.WriteAttribute("width", "5", true);
    output.WriteAttribute("bgcolor", "#ffffff", true);
    output.Write(">");
    output.Write("&nbsp;");
    output.WriteEndTag("td");
   
    output.WriteBeginTag("td");
    //output.WriteAttribute("width", "1", true);
    output.WriteAttribute("bgcolor", "#ffffff", true);
    output.Write(">");
    output.Write("&nbsp;");
    output.WriteEndTag("td");

    if ( ((DataSet)this.DataSource).Tables.Count != 0 ){
     if ( ((DataSet)this.DataSource).Relations.Count != 0 ){
      DataRow[] drChildren = null;
      //Print the Header COloumns
      if ( Context.Request.Browser.Browser.Equals("IE")) {
       output.WriteBeginTag("td");
       output.WriteAttribute("align", "right", true);
       output.WriteAttribute("bgcolor", System.Drawing.ColorTranslator.ToHtml(this.mastertableHeaderBgColor) , true);
       output.WriteAttribute("nowrap", null);
       output.Write(">");
       output.WriteEndTag("td"); 
      }
      for ( int i = 0; i < ((DataSet)this.DataSource).Relations[0].ParentTable.Columns.Count; i++ ){
       output.WriteBeginTag("td");
       output.WriteAttribute("align", "right", true);
       output.WriteAttribute("bgcolor", System.Drawing.ColorTranslator.ToHtml(this.mastertableHeaderBgColor) , true);
       output.WriteAttribute("nowrap", null);
       output.Write(">");
       output.WriteBeginTag("font");
       output.WriteAttribute("size", "3");
       output.WriteAttribute("color", System.Drawing.ColorTranslator.ToHtml(this.mastertableHeaderFontColor));
       output.Write(">");
       output.Write(((DataSet)this.DataSource).Relations[0].ParentTable.Columns[i].ColumnName);
       output.WriteEndTag("font");
       output.WriteEndTag("td"); 
      }
      for ( int iRow = 0; iRow < ((DataSet)this.DataSource).Relations[0].ParentTable.Rows.Count; iRow++ ){
       //Display the Master Data Rows
       //the klick Sign
       output.WriteBeginTag("tr");
       output.WriteAttribute("bgcolor", "#ffffff");
       output.Write(">");
       output.WriteBeginTag("td");
       output.WriteAttribute("bgcolor" , "#ffffff");
       output.WriteAttribute("align" , "center");
       output.WriteAttribute("valign" , "center");
       //output.WriteAttribute("width" , "5");
       output.Write(">");
       output.WriteBeginTag("img");

       output.WriteAttribute("name" , "imgMaster" + iRow.ToString());
       output.WriteAttribute("src" , "Plus.GIF");
       output.WriteAttribute("alt" , "Show Details to PK " + ((DataSet)this.DataSource).Relations[0].ParentKeyConstraint.Columns[0].ColumnName  );
       output.WriteAttribute("onclick" , "DisplayItem('imgMaster" + iRow.ToString() + "', 'divDetail" + iRow.ToString() + "');");
       output.WriteAttribute("onmouseover" , "Point('imgMaster"+ iRow.ToString()+"');");
       output.WriteAttribute("onmouseout" , "DontPoint('imgMaster"+iRow.ToString() + "');");
       output.WriteAttribute("width" , "16");
       output.WriteAttribute("height" , "16");
       output.Write(">");
       output.WriteEndTag("img");
       output.WriteEndTag("td");
      
       //The Master Data
       output.WriteBeginTag("td");
       output.WriteAttribute("bgcolor" , System.Drawing.ColorTranslator.ToHtml(this.mastertableHeaderBgColor) );
       //output.WriteAttribute("width" , "1");
       output.Write(">");
       output.Write("&nbsp;");
       output.WriteEndTag("td");
       for ( int iCol = 0; iCol < ((DataSet)this.DataSource).Relations[0].ParentTable.Columns.Count; iCol++ ){
        output.WriteBeginTag("td");
        output.WriteAttribute("bgcolor" , System.Drawing.ColorTranslator.ToHtml(this.mastertableCellBgColor) );
        output.WriteAttribute("align" , "right");
        output.WriteAttribute("nowrap" , null);
        output.Write(">");
        output.WriteBeginTag("font");
        output.WriteAttribute("size", "3");
        output.WriteAttribute("color", System.Drawing.ColorTranslator.ToHtml(this.mastertableCellFontColor) );
        output.Write(">");
        output.Write(((DataSet)this.DataSource).Relations[0].ParentTable.Rows[iRow][iCol].ToString());
        output.WriteEndTag("font");
        output.WriteEndTag("td");
       }

       output.WriteEndTag("tr");
       //Now we Should show the Detail Data
       output.WriteBeginTag("tr");
       output.Write(">");
      
       output.WriteBeginTag("td");
       output.WriteAttribute("bgcolor", "#ffffff", true);
       output.Write(">");
       output.WriteEndTag("td");

       output.WriteBeginTag("td");
       output.WriteAttribute("align" , "center");
       output.WriteAttribute("colspan" , (((DataSet)this.DataSource).Relations[0].ParentTable.Columns.Count +1).ToString() );
       output.Write(">");
       output.WriteBeginTag("div");
       output.WriteAttribute("id" , "divDetail" + iRow.ToString());
       output.WriteAttribute("style" , "display:none");
       output.Write(">");
       drChildren = ((DataSet)this.DataSource).Relations[0].ParentTable.Rows[iRow].GetChildRows(((DataSet)this.DataSource).Relations[0]);
      
       if ( drChildren.Length == 0 ){
        output.WriteBeginTag("font");
        output.WriteAttribute("size", "2");
        output.WriteAttribute("color", System.Drawing.ColorTranslator.ToHtml(System.Drawing.Color.Red));
        output.Write(">");
        output.Write("No Detail Rows");
        output.WriteEndTag("font");
       }
       else{
        //the children table Header
        output.WriteBeginTag("table");
        output.WriteAttribute("width", "100%", true);
        output.WriteAttribute("border", "0", true);
        output.WriteAttribute("cellpadding", "0", true);
        output.WriteAttribute("cellspacing", "0", true);
        output.Write(">");
        output.WriteBeginTag("tr");
        output.Write(">");
        output.WriteBeginTag("td");
       
        output.WriteAttribute("bgcolor" , "#ffffff");
        output.WriteAttribute("width" , "5");
        output.Write(">");
        output.Write("&nbsp;");
        output.WriteEndTag("td");
        output.WriteBeginTag("td");
        output.WriteAttribute("bgcolor" , System.Drawing.ColorTranslator.ToHtml(this.mastertableHeaderFontColor) );
        output.WriteAttribute("width" , "5");
        output.Write(">");
        output.Write("&nbsp;");
        output.WriteEndTag("td");
        output.WriteBeginTag("td");
        output.WriteAttribute("bgcolor" , System.Drawing.ColorTranslator.ToHtml(this.detailtableHeaderBgColor));
        output.WriteAttribute("width" , "1");
        output.Write(">");
        output.WriteEndTag("td");
        for ( int iCCol = 0; iCCol < ((DataSet)this.DataSource).Relations[0].ChildTable.Columns.Count; iCCol++ ){
         output.WriteBeginTag("td");
         output.WriteAttribute("bgcolor" , System.Drawing.ColorTranslator.ToHtml(this.detailtableHeaderBgColor));
         output.WriteAttribute("align" , "right");
         output.WriteAttribute("nowrap" , null);
         output.Write(">");
         output.WriteBeginTag("font");
         output.WriteAttribute("size", "2");
         output.WriteAttribute("color", System.Drawing.ColorTranslator.ToHtml(this.detailtableHeaderFontColor));
         output.Write(">");
         output.WriteBeginTag("b");
         output.Write(">");
         output.Write(((DataSet)this.DataSource).Relations[0].ChildTable.Columns[iCCol].ColumnName);
         output.WriteEndTag("b");
         output.WriteEndTag("font");
         output.WriteEndTag("td");
        }
        output.WriteEndTag("tr");
        //the child rows data
        for ( int iCRow = 0; iCRow < drChildren.Length; iCRow++ ){
         output.WriteBeginTag("tr");
         output.Write(">");
         //<td>
         output.WriteBeginTag("td");
         output.WriteAttribute("bgcolor" , "#ffffff");
         output.WriteAttribute("align" , "center");
         output.Write(">");
         output.WriteEndTag("&nbsp;");
         output.WriteEndTag("td");
         //</td>
         //<td>
         output.WriteBeginTag("td");
         output.WriteAttribute("bgcolor" , "#ffffff");
         output.WriteAttribute("align" , "center");
         output.WriteAttribute("valign" , "center");
         output.WriteAttribute("width" , "5");
         output.Write(">");
         output.WriteEndTag("&nbsp;");
         output.WriteEndTag("td");
         //</td>
         //<td>
         output.WriteBeginTag("td");
         output.WriteAttribute("bgcolor" , System.Drawing.ColorTranslator.ToHtml(this.detailtableHeaderBgColor) );
         output.WriteAttribute("width" , "1");
         output.Write(">");
         output.WriteEndTag("&nbsp;");
         output.WriteEndTag("td");
         //</td>
         for ( int yColCount = 0 ; yColCount < ((DataSet)this.DataSource).Relations[0].ChildTable.Columns.Count; yColCount++ ){
          //<td>
          output.WriteBeginTag("td");
          output.WriteAttribute("bgcolor" , System.Drawing.ColorTranslator.ToHtml(this.detailtableCellBgColor));
          output.WriteAttribute("align" , "right");
          output.Write(">");
          output.WriteBeginTag("font");
          output.WriteAttribute("size", "2");
          output.WriteAttribute("color", System.Drawing.ColorTranslator.ToHtml(this.detailtableCellFontColor));
          output.Write(">");
          output.Write( drChildren[iCRow][yColCount].ToString());
          output.WriteEndTag("font");
          output.WriteEndTag("td");
          //</td>
         }
         output.WriteEndTag("tr");
        }
        output.WriteEndTag("table");
       }
       output.WriteEndTag("div");
       output.WriteEndTag("td");
       output.WriteEndTag("tr");
      }
     }
    }
    output.WriteEndTag("tr");
    output.WriteEndTag("table");
    output.WriteEndTag("td");
    output.WriteEndTag("tr");
    output.WriteEndTag("table");
   }
   else{
    base.Render(output);
   }
  }
 }
}

Das Grid in "Action":

Das Grid in Action


Erfasst am: 16.04.2004 - Artikel-URL: http://www.devtrain.de/news.aspx?artnr=917
© Copyright 2003 ppedv AG - http://www.ppedv.de