Rainer's profileCyrons BlogPhotosBlogListsMore ![]() | Help |
|
|
December 30 Interaktivität mit zur Laufzeit generierten Controls, VorschauDieses Projekt ist damit noch nicht beendet! Interaktivität mit zur Laufzeit generierten Controls, Part 4/5Form1Functionality.csusing System; using System.Collections.Generic; using System.Drawing; using System.Threading; using System.Windows.Forms; namespace SimpleColorFade { class Form1Functionality { #region Global Class members private string basicPictureBoxName; Form1 m_Form; private int numberOfColumns; private int numberOfRows; private List<PictureBox> pictureBoxList; protected delegate void PictureBoxCallBack(int pictureBoxNumber, Color colorState); private static object syncLock = new object(); PictureBox tempPictureBox; #endregion public Form1Functionality(Form1 frm) { this.m_Form = frm; basicPictureBoxName = "pictureBox_"; numberOfColumns = 10; numberOfRows = 10; pictureBoxList = new List<PictureBox>(); } #region Eventhandler private void OnMouseMove(object sender, MouseEventArgs e) { tempPictureBox = (PictureBox)sender; pictureBoxList[m_Form.ThatTableLayoutPanel.Controls.GetChildIndex(tempPictureBox)].BackColor = Color.Orange; } private void OnMouseLeave(object sender, EventArgs e) { tempPictureBox = (PictureBox)sender; ThreadPool.QueueUserWorkItem(new WaitCallback(FadeColor), m_Form.ThatTableLayoutPanel.Controls.GetChildIndex(tempPictureBox)); } #endregion #region Methods private void CalculateSize() { int maxX = 240; int maxY = 240; // Die Zwischenräume müssen berücksichtigt werden. SubSize.x = maxX / numberOfColumns - ((numberOfColumns + 2) * 5) / numberOfColumns; SubSize.y = maxY / numberOfRows - ((numberOfRows + 2) * 5) / numberOfRows; } /// <summary> /// Verändert die Farbe von Orange nach BlueViolet /// in 10 Schritten. /// </summary> /// <param name="pictureBoxNumber">Die Picturebox, deren Farbe geändert werden soll. /// Vom Typ object weil der WaitCallback-Delegat das so erwartet.</param> // BlueViolet=138/43/226 // Orange=225/165/0 private void InitializePanel() { m_Form.ThatTableLayoutPanel.ColumnCount = numberOfColumns; m_Form.ThatTableLayoutPanel.RowCount = numberOfRows; for(int i = 0; i < m_Form.ThatTableLayoutPanel.RowStyles.Count; i++) { m_Form.ThatTableLayoutPanel.RowStyles[i].SizeType = SizeType.AutoSize; } for(int i = 0; i < m_Form.ThatTableLayoutPanel.ColumnStyles.Count; i++) { m_Form.ThatTableLayoutPanel.ColumnStyles[i].SizeType = SizeType.AutoSize; } } private void InvokePictureBox(int pictureBoxNumber, Color colorState) { if(pictureBoxList[pictureBoxNumber].InvokeRequired) { PictureBoxCallBack pbc = new PictureBoxCallBack(InvokePictureBox); pictureBoxList[pictureBoxNumber].Invoke(pbc, new object[] { pictureBoxNumber, colorState }); } else pictureBoxList[pictureBoxNumber].BackColor = colorState; } /// <summary> /// Füllt das Panel mit Pictureboxen. /// </summary> internal void PopulatePanel() { InitializePanel(); CalculateSize(); int counter = 0; for(int rowCount = 0; rowCount < numberOfRows; rowCount++) { for(int columnCount = 0; columnCount < numberOfColumns; columnCount++) { PictureBox myPictureBox = new PictureBox(); myPictureBox.Name = basicPictureBoxName + columnCount.ToString() + rowCount.ToString(); myPictureBox.Size = new Size(SubSize.x, SubSize.y); myPictureBox.BackColor = Color.BlueViolet; myPictureBox.MouseMove += new MouseEventHandler(OnMouseMove); myPictureBox.MouseLeave += new EventHandler(OnMouseLeave); pictureBoxList.Add(myPictureBox); m_Form.ThatTableLayoutPanel.Controls.Add(pictureBoxList[counter], columnCount, rowCount); counter++; } } } #endregion } public struct SubSize { public static int x; public static int y; } } Interaktivität mit zur Laufzeit generierten Controls, Part 3/5Form1.csusing System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; namespace SimpleColorFade { public partial class Form1 : Form { Form1Functionality functionality; public Form1() { InitializeComponent(); functionality = new Form1Functionality(this); } #region Control-Porperties public TableLayoutPanel ThatTableLayoutPanel { get { return this.tableLayoutPanel1; } } #endregion private void Form1_Load(object sender, EventArgs e) { functionality.PopulatePanel(); } } } Interaktivität mit zur Laufzeit generierten Controls, Part 2/5Form1.Designer.csnamespace SimpleColorFade { partial class Form1 { /// <summary> /// Erforderliche Designervariable. /// </summary> private System.ComponentModel.IContainer components = null; /// <summary> /// Verwendete Ressourcen bereinigen. /// </summary> /// <param name="disposing">True, wenn verwaltete Ressourcen gelöscht werden sollen; andernfalls False.</param> protected override void Dispose(bool disposing) { if(disposing && (components != null)) { components.Dispose(); } base.Dispose(disposing); } #region Vom Windows Form-Designer generierter Code /// <summary> /// Erforderliche Methode für die Designerunterstützung. /// Der Inhalt der Methode darf nicht mit dem Code-Editor geändert werden. /// </summary> private void InitializeComponent() { this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel(); this.SuspendLayout(); // // tableLayoutPanel1 // this.tableLayoutPanel1.AutoSize = true; this.tableLayoutPanel1.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; this.tableLayoutPanel1.BackColor = System.Drawing.Color.MidnightBlue; this.tableLayoutPanel1.ColumnCount = 1; this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 20F)); this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 20F)); this.tableLayoutPanel1.Location = new System.Drawing.Point(12, 12); this.tableLayoutPanel1.Name = "tableLayoutPanel1"; this.tableLayoutPanel1.RowCount = 1; this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle()); this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 1F)); this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 1F)); this.tableLayoutPanel1.Size = new System.Drawing.Size(0, 0); this.tableLayoutPanel1.TabIndex = 0; // // Form1 // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.BackColor = System.Drawing.Color.Black; this.ClientSize = new System.Drawing.Size(292, 272); this.Controls.Add(this.tableLayoutPanel1); this.Name = "Form1"; this.Text = "Sandbox"; this.Load += new System.EventHandler(this.Form1_Load); this.ResumeLayout(false); this.PerformLayout(); } #endregion private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1; } } Interaktivität mit zur Laufzeit generierten Controls, Part 1/5Dieser Eintrag steht in Bezug zu "Control-Generierung und handling zur Laufzeit, Part 1 bis 5".
December 17 Referenzierung von WinForm-Controls
Hallo, Form1 formInstance = new Form1(); ergibt zwar keine Fehlermeldung, aber versucht man, etwas aus dieser Instanz heraus zu holen (z.B. formInstance.PictureBox_soundso), merkt man sofort daß das nicht funzt. Nach langen und fruchtlosen Versuchen holte ich mir Rat in einem Forum. Callback-Delegate war das Schlagwort. Das ist eine tolle Sache, aber sehr umständlich. Letztes Wochenende kam nun endlich der Durchbruch mit dem Buch "Visual C# 2005 für Profis"! Ich kann das Buch nur empfehlen. Nach kurzem Studium eines Kapitels sieht die Lösung zu dem Problem wie folgt aus: Man schreibt für jedes zu referenzierenede Control ein Property in die Form1-Klasse (oder ein anderes Form). Das geht ganz einfach (in diesem Beispiel möchte ich ein Label mit dem Namen lbl_Test referenzieren): internal Label lbl { get { return lbl_Test; }}
In einer anderen Klasse kann man nun auf diese Properties zugreifen. Die Instantiierung der Forms-Klasse ist zwar etwas umständlicher, aber immer noch easy, wenn man es einmal weiß:
public class TestClass Stylesheet, EinbindungIm Seitencode unter <title>...</title> Dropdown-Liste in einem GridView mit foreign keys
Eine Tabelle T_PC besitzt einen foreign key "ID_Zustand", der mit dem Primary key der Tabelle "T_Zustand" verbunden ist. Das Update wird über eine Stored Procedure gefahren:
ALTER PROCEDURE dbo.UpdatePC ( @PC_ID uniqueidentifier, @Bezeichnung varchar(50), @Inventarnummer varchar(50), @Kostentraeger varchar(50), @Seriennummer varchar(50), @Zustand varchar(50), @Sonderregelung varchar(255), @LieferantName varchar(50), @Herstellername varchar(50) ) AS SET NOCOUNT OFF DECLARE @ID_Hersteller uniqueidentifier DECLARE @ID_Lieferant uniqueidentifier DECLARE @ID_Zustand uniqueidentifier -- Zugehörige IDs holen SET @ID_Hersteller = (SELECT Hersteller_ID FROM T_Hersteller WHERE (Herstellername = @Herstellername)) SET @ID_Lieferant = (SELECT Lieferant_ID FROM T_Lieferant WHERE (LieferantName = @LieferantName)) SET @ID_Zustand = (SELECT Zustand_ID FROM T_Zustand WHERE (Zustand = @Zustand)) -- Update UPDATE T_PC SET [Bezeichnung] = @Bezeichnung, [Inventarnummer] = @Inventarnummer, [Kostentraeger] = @Kostentraeger, [Seriennummer] = @Seriennummer, [ID_Zustand] = @ID_Zustand, [Sonderregelung] = @Sonderregelung, [ID_Lieferant] = @ID_Lieferant, [ID_Hersteller] = @ID_Hersteller WHERE (PC_ID = @PC_ID) RETURN
Die Gridview wird mit folgender SQL-Anweisung befüllt: SELECT T_PC.PC_ID, T_PC.Bezeichnung, T_PC.Inventarnummer, T_PC.Kostentraeger, T_PC.Seriennummer, T_PC.Sonderregelung, Die ID-Felder werden unsichtbar gemacht, indem man das Column-Property "visible" auf false setzt. Damit der User den Zustand nicht in eine Textbox eingibt, soll er über eine Dropdown-Liste ausgewählt werden. Dazu ändert man das Feld "Zustand" in der GridView in ein Template field. Über Edit templates wählt man aus der Template-Liste "EditItemTemplate" des Zustand-Columns aus. Im Container befindet sich eine Textbox. Diese wird gelöscht und aus der Toolbox wird eine Dropdown-Liste eingesetzt. Als DataSource kann nicht die der GridView gewählt werden, weil diese durch den kombinierten SELECT (INNER JOIN) für den Zustand nur Werte zur Verfügung stellt, die durch diese Funktion auch zu Tage treten. Man wählt also eine eigene DataSource, in diesem Fall eine SqlDataSource von "T_Zustand". Es müßte auch mit einer ObjectDataSource aus dem entsprechenden TableAdapter funktionieren. Das werde ich morgen im Institut ausprobieren. Hier ist der komplette aspx-Code der Dropdown-Liste:
<asp:DropDownList ID="grdv_ddl_Zustand" runat="server" DataSourceID="SqlDataSource_Zustand" DataTextField="Zustand" DataValueField="Zustand" SelectedValue='<%# Bind("Zustand") %>'> </asp:DropDownList>
Damit die Parameter mit der Stored Procedure zusammenpassen, gibt man sowohl für DataTextField, als auch für DataValueField und SelectedValue "Zustand" an. Der aspx-Code der SqlDataSource:
<asp:SqlDataSource ID="SqlDataSource_Zustand" runat="server" ConnectionString="<%$ ConnectionStrings:AMS2ConnectionString1 %>" SelectCommand="SELECT [Zustand] FROM [T_Zustand] ORDER BY [Zustand]"> </asp:SqlDataSource>
Die ID wird nicht benötigt. ASP.net Development Server ohne VS startenDOS-Batchfile mit folgendem Inhalt anlegen: @echo off Eigene 404-PageDamit eine individuelle 404-Page gefeuert wird, muß in der Web.config nur die CustomErrors-Sektion dekommentiert werden. Selbstredend daß man noch entsprechende Errorpages designed und zum Projekt hinzufügt. Exception handling in ASP.net
1. Beliebige Errorpage gestalten. 2. Die Headerzeile der Default-Page (*) um den Eintrag ErrorPage erweitern. Siehe Codebeispiel: <%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" ErrorPage="~/Error.aspx" %> (*): Oder einer anderen Seite, falls individuelle Errorpages angefahren werden sollen. Automatisches Anpassen einer Grafik an die Fenstergröße <head>
Das Bild selber kann in der Breite nicht in Prozent angegeben werden, aber der DIV, in den das Bild eingebettet ist. Darauf ist zu achten. Wenn die Breite des DIV in Pixeln angegeben ist, funktioniert das Ganze nicht. Schritt für Schritt: 1. Layer auf die Seite setzen. 2. Bild in den Layer schieben. 3. Layerposition korrigieren. 4. im HTML-Code die width- und height-Properties des Layers von px auf % ändern. 5. Obigen Code in der Head-Sektion platzieren. Scrollposition merken<%@ Page Language="C#" MaintainScrollPositionOnPostback="true" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %> Durch das boolean Property MaintainScrollPositionOnPostback behält die Webseite ihre augenblickliche Position, statt nach einem Postback wieder an das obere Ende zu springen. Control-Generierung und handling zur Laufzeit, Part 3/5: Form1.csusing System; using System.Collections.Generic; using System.Windows.Forms; using System.Threading; using System.Drawing; namespace ControlGenerationDynamic { public partial class Form1 : Form { #region Global Class members private string basicPictureBoxName; private Thread bgThread; private int numberOfSubControls; private List<PictureBox> pictureBoxList; protected delegate void PictureBoxCallBack(int pictureBoxNumber, Color colorState); private static Object syncLock = new Object(); #endregion #region Constructors public Form1() { basicPictureBoxName = "pictureBox_"; bgThread = new Thread(new ThreadStart(DoColorSequence)); numberOfSubControls = 25; pictureBoxList = new List<PictureBox>(); InitializeComponent(); } #endregion #region EventHandler private void Form1_FormClosing(object sender, FormClosingEventArgs e) { AbortAndJoinThread(); } private void Form1_Load(object sender, EventArgs e) { PopulateFlowLayoutPanel(); bgThread.Name = "ShowThread"; bgThread.Start(); } private void radioButton_Sequential_CheckedChanged(object sender, EventArgs e) { AbortAndJoinThread(); if(radioButton_Sequential.Checked) { ResetControls(); bgThread = new Thread(new ThreadStart(DoColorSequence)); bgThread.Start(); } } private void radioButton_Random_CheckedChanged(object sender, EventArgs e) { AbortAndJoinThread(); if(radioButton_Random.Checked) { ResetControls(); bgThread = new Thread(new ThreadStart(DoRandom)); bgThread.Start(); } } #endregion #region Methods private void AbortAndJoinThread() { bgThread.Abort(); bgThread.Join(); } private void DoColorSequence() { lock(syncLock) { while(true) { for(int i = 0; i < numberOfSubControls; i++) { InvokePictureBox(i, Color.Orange); Thread.Sleep(250); InvokePictureBox(i, Color.BlueViolet); } } } } private void DoRandom() { lock(syncLock) { Random rnd = new Random(); int randomNumber = 0; while(true) { randomNumber = rnd.Next(25); InvokePictureBox(randomNumber, Color.Orange); Thread.Sleep(250); InvokePictureBox(randomNumber, Color.BlueViolet); } } } private void InvokePictureBox(int pictureBoxNumber, Color colorState) { if(pictureBoxList[pictureBoxNumber].InvokeRequired) { PictureBoxCallBack pbc = new PictureBoxCallBack(InvokePictureBox); pictureBoxList[pictureBoxNumber].Invoke(pbc, new object[] { pictureBoxNumber, colorState }); } else pictureBoxList[pictureBoxNumber].BackColor = colorState; } private void PopulateFlowLayoutPanel() { for(int i = 0; i < numberOfSubControls; i++) { PictureBox myPictureBox = new PictureBox(); myPictureBox.Name = basicPictureBoxName + (i + 1).ToString(); myPictureBox.Size = new Size(32, 32); myPictureBox.BackColor = Color.BlueViolet; pictureBoxList.Add(myPictureBox); this.flowLayoutPanel1.Controls.Add(pictureBoxList[i]); } } private void ResetControls() { for(int i = 0; i < numberOfSubControls; i++) { pictureBoxList[i].BackColor = Color.BlueViolet; } } #endregion } } Control-Generierung und handling zur Laufzeit, Part 2/5: Form1.Designer.csnamespace ControlGenerationDynamic { partial class Form1 { /// <summary> /// Erforderliche Designervariable. /// </summary> private System.ComponentModel.IContainer components = null; /// <summary> /// Verwendete Ressourcen bereinigen. /// </summary> /// <param name="disposing">True, wenn verwaltete Ressourcen gelöscht werden sollen; andernfalls False.</param> protected override void Dispose(bool disposing) { if(disposing && (components != null)) { components.Dispose(); } base.Dispose(disposing); } #region Vom Windows Form-Designer generierter Code /// <summary> /// Erforderliche Methode für die Designerunterstützung. /// Der Inhalt der Methode darf nicht mit dem Code-Editor geändert werden. /// </summary> private void InitializeComponent() { this.flowLayoutPanel1 = new System.Windows.Forms.FlowLayoutPanel(); this.radioButton_Sequential = new System.Windows.Forms.RadioButton(); this.radioButton_Random = new System.Windows.Forms.RadioButton(); this.SuspendLayout(); // // flowLayoutPanel1 // this.flowLayoutPanel1.BackColor = System.Drawing.Color.Navy; this.flowLayoutPanel1.Location = new System.Drawing.Point(50, 40); this.flowLayoutPanel1.Name = "flowLayoutPanel1"; this.flowLayoutPanel1.Size = new System.Drawing.Size(190, 190); this.flowLayoutPanel1.TabIndex = 0; // // radioButton_Sequential // this.radioButton_Sequential.AutoSize = true; this.radioButton_Sequential.Checked = true; this.radioButton_Sequential.ForeColor = System.Drawing.SystemColors.Control; this.radioButton_Sequential.Location = new System.Drawing.Point(50, 243); this.radioButton_Sequential.Name = "radioButton_Sequential"; this.radioButton_Sequential.Size = new System.Drawing.Size(75, 17); this.radioButton_Sequential.TabIndex = 1; this.radioButton_Sequential.TabStop = true; this.radioButton_Sequential.Text = "Sequential"; this.radioButton_Sequential.UseVisualStyleBackColor = true; this.radioButton_Sequential.CheckedChanged += new System.EventHandler(this.radioButton_Sequential_CheckedChanged); // // radioButton_Random // this.radioButton_Random.AutoSize = true; this.radioButton_Random.ForeColor = System.Drawing.SystemColors.Control; this.radioButton_Random.Location = new System.Drawing.Point(175, 243); this.radioButton_Random.Name = "radioButton_Random"; this.radioButton_Random.Size = new System.Drawing.Size(65, 17); this.radioButton_Random.TabIndex = 2; this.radioButton_Random.Text = "Random"; this.radioButton_Random.UseVisualStyleBackColor = true; this.radioButton_Random.CheckedChanged += new System.EventHandler(this.radioButton_Random_CheckedChanged); // // Form1 // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.BackColor = System.Drawing.Color.Black; this.ClientSize = new System.Drawing.Size(292, 272); this.Controls.Add(this.radioButton_Random); this.Controls.Add(this.radioButton_Sequential); this.Controls.Add(this.flowLayoutPanel1); this.Name = "Form1"; this.Text = "Form1"; this.Load += new System.EventHandler(this.Form1_Load); this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.Form1_FormClosing); this.ResumeLayout(false); this.PerformLayout(); } #endregion private System.Windows.Forms.FlowLayoutPanel flowLayoutPanel1; private System.Windows.Forms.RadioButton radioButton_Sequential; private System.Windows.Forms.RadioButton radioButton_Random; } } Control-Generierung und handling zur Laufzeit, Part 1/5: BeschreibungDieses Demo zeigt, wie zur Laufzeit Controls generiert und angesteuert werden. December 09 Fehler oder nicht?Am 4.12. schrieb ich, es sei ein Fehler daß die FadingMessageBox für jeden Aufruf neu instanziiert werden muß. Seit ein paar Tagen bin ich mir da nicht mehr so sicher. Eigentlich ist dieser Umstand doch positiv zu bewerten - es spart Resourcen und ein "manuelles" Dispose zur Designzeit entfällt (z.B. über using). |
|
|