{"id":94,"date":"2015-06-03T18:12:07","date_gmt":"2015-06-03T16:12:07","guid":{"rendered":"http:\/\/dtp-soft.de\/?p=94"},"modified":"2015-06-03T14:12:08","modified_gmt":"2015-06-03T12:12:08","slug":"c-progressstepbar","status":"publish","type":"post","link":"http:\/\/dtp-soft.de\/?p=94","title":{"rendered":"c#: ProgressStepBar"},"content":{"rendered":"<p>Manchmal m\u00f6chte man gerne f\u00fcr verschiedene Schritte einen Fortschrittsbalken anzeigen, um zu verdeutlichen, wo man sich gerade befindet.<\/p>\n<p>Ein einfacher Fortschrittsbalken kann aber nur einen prozentualen Wert darstellen. Was wir brauchten war ein Fortschrittsbalken, in dem die Schritte benannt werden k\u00f6nnen, die man zu durchwandern hat. Und der Balken sollte nicht einfach langweilige Rechtecke aneinander h\u00e4ngen.<!--more--><\/p>\n<p>Die L\u00f6sung war ein Balken, der Beschriftungen aufnehmen kann und Pfeilspitzen zum Abgrenzen der einzelnen Schritte benutzt.<\/p>\n<pre class=\"lang:c# decode:true\" title=\"ProgressStepBar\">using System;\r\nusing System.ComponentModel;\r\nusing System.Drawing;\r\nusing System.Linq;\r\nusing System.Windows.Forms;\r\n\r\nnamespace MyControls\r\n{\r\n\t\/\/\/ &lt;summary&gt;\r\n\t\/\/\/ Die Klassse stellt einen Fortschrittsbalken mit Schritten dar. Die Schritte k\u00f6nnen beschriftet sein.\r\n\t\/\/\/ Mann kan mittels &lt;see cref=\"ArrowWidth\"\/&gt; die Breite der Pfeilspitze verstellen und so optimal an die H\u00f6he \r\n\t\/\/\/ des Controls anpassen.\r\n\t\/\/\/ &lt;\/summary&gt;\r\n\tpublic class ProgressStepBar : UserControl\r\n\t{\r\n\t\tpublic ProgressStepBar()\r\n\t\t\t: base()\r\n\t\t{\r\n\t\t}\r\n\r\n\t\t#region Properties\r\n\t\tprivate int _ArrowWidth = 20;\r\n\t\t\/\/\/ &lt;summary&gt;\r\n\t\t\/\/\/ Mit ArrowWith kann man die Breite der Pfeilspitze einstellen.\r\n\t\t\/\/\/ &lt;\/summary&gt;\r\n\t\t[Browsable(true), Category(\"MyControl\"), Description(\"Legt die Breite der Pfeilspitze fest\")]\r\n\t\tpublic int ArrowWidth\r\n\t\t{\r\n\t\t\tget { return _ArrowWidth; }\r\n\t\t\tset { _ArrowWidth = value; }\r\n\t\t}\r\n\r\n\t\tprivate int _ActiveStep = 0;\r\n\t\t\/\/\/ &lt;summary&gt;\r\n\t\t\/\/\/ Hiermit wird der aktive Schritt eingestellt. \r\n\t\t\/\/\/ &lt;\/summary&gt;\r\n\t\t[Browsable(true), Category(\"MyControl\"), Description(\"Legt da aktive Element fest\")]\r\n\t\tpublic int ActiveStep\r\n\t\t{\r\n\t\t\tget { return _ActiveStep; }\r\n\t\t\tset { _ActiveStep = value; }\r\n\t\t}\r\n\r\n\t\tprivate Color _ActiveStepColor = Color.DodgerBlue;\r\n\t\t\/\/\/ &lt;summary&gt;\r\n\t\t\/\/\/ Mit dieser Farbe wird das aktive Element gef\u00fcllt\r\n\t\t\/\/\/ &lt;\/summary&gt;\r\n\t\t[Browsable(true), Category(\"MyControl\"), Description(\"Legt die Farbe des aktiven Elements fest\")]\/\/, DefaultValue(typeof(Color), \"0x1E90FF\")\r\n\t\tpublic Color ActiveStepColor\r\n\t\t{\r\n\t\t\tget { return _ActiveStepColor; }\r\n\t\t\tset { _ActiveStepColor = value; }\r\n\t\t}\r\n\r\n\t\tprivate Color _CompletetStepsColor = Color.LightBlue;\r\n\t\t\/\/\/ &lt;summary&gt;\r\n\t\t\/\/\/ Mit dieser Farbe werden die bereits erledigten Schritte gef\u00fcllt\r\n\t\t\/\/\/ &lt;\/summary&gt;\r\n\t\t[Browsable(true), Category(\"MyControl\"), Description(\"Legt die Farbe f\u00fcr erledigte Elemente fest\")]\r\n\t\tpublic Color CompletetStepsColor\r\n\t\t{\r\n\t\t\tget { return _CompletetStepsColor; }\r\n\t\t\tset { _CompletetStepsColor = value; }\r\n\t\t}\r\n\r\n\t\tprivate Color _UncompletetStepsColor = Color.Transparent;\r\n\t\t\/\/\/ &lt;summary&gt;\r\n\t\t\/\/\/ Mit dieser Farbe werden die noch unerledigten Schritte gef\u00fcllt\r\n\t\t\/\/\/ &lt;\/summary&gt;\r\n\t\t[Browsable(true), Category(\"MyControl\"), Description(\"Legt die Farbe f\u00fcr unerledigte Elemente fest\")]\r\n\t\tpublic Color UncompletetStepsColor\r\n\t\t{\r\n\t\t\tget { return _UncompletetStepsColor; }\r\n\t\t\tset { _UncompletetStepsColor = value; }\r\n\t\t}\r\n\r\n\t\tbool _DynamicStepWidth = false;\r\n\t\t\/\/\/ &lt;summary&gt;\r\n\t\t\/\/\/ Diese Eigenschaft gibt an, ob die Einteilung in gleichm\u00e4\u00dfige Pfeile gemacht werden soll oder ob \r\n\t\t\/\/\/ die Breite eines Pfeils von der Breite seiner Beschriftung abh\u00e4ngt.\r\n\t\t\/\/\/ &lt;\/summary&gt;\r\n\t\t[Browsable(true), Category(\"MyControl\"), Description(\"Legt fest, ob die Breite der Steps gleichm\u00e4\u00dfig oder dynamisch sein soll.\")]\r\n\t\tpublic bool DynamicStepWidth\r\n\t\t{\r\n\t\t\tget { return _DynamicStepWidth; }\r\n\t\t\tset { _DynamicStepWidth = value; }\r\n\t\t}\r\n\r\n\t\t\/\/\/ &lt;summary&gt;\r\n\t\t\/\/\/ Beschriftungen f\u00fcr die einzelnen Schritte\r\n\t\t\/\/\/ &lt;\/summary&gt;\r\n\t\t[Browsable(true), Category(\"MyControl\"), Editor(\"System.Windows.Forms.Design.StringArrayEditor\", typeof(System.Drawing.Design.UITypeEditor))]\r\n\t\tpublic string[] Steps { get; set; }\r\n\r\n\t\t#endregion\r\n\r\n\r\n\t\t\/\/\/ &lt;summary&gt;\r\n\t\t\/\/\/ Die Methode summiert die ersten &lt;paramref name=\"stepnr\"\/&gt; Werte des Arrays &lt;paramref name=\"widths\"\/&gt;. Arraygrenzen werden dabei ber\u00fccksichtigt.\r\n\t\t\/\/\/ &lt;\/summary&gt;\r\n\t\t\/\/\/ &lt;param name=\"stepnr\"&gt;Anazhl der zu summierenden Werte&lt;\/param&gt;\r\n\t\t\/\/\/ &lt;param name=\"widths\"&gt;Array mit den Werten&lt;\/param&gt;\r\n\t\t\/\/\/ &lt;returns&gt;Summe der Werte bis &lt;paramref name=\"stepnr\"\/&gt;&lt;\/returns&gt;\r\n\t\tprivate int SumWidths(int stepnr, int[] widths)\r\n\t\t{\r\n\t\t\tint ret = 0;\r\n\t\t\tfor (int i = 0; i &lt; Math.Min(stepnr, widths.Length); i++)\r\n\t\t\t{\r\n\t\t\t\tret += widths[i];\r\n\t\t\t}\r\n\t\t\treturn ret;\r\n\t\t}\r\n\r\n\t\tprotected override void OnPaint(PaintEventArgs e)\r\n\t\t{\r\n\t\t\tbase.OnPaint(e);\r\n\t\t\tif (Steps == null || Steps.Length == 0)\r\n\t\t\t{\r\n\t\t\t\te.Graphics.DrawRectangle(Pens.Black, new Rectangle(0, 0, Width - 1, Height - 1));\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t\tstring[] steps = Steps;\/\/.Split('|');\r\n\r\n\t\t\tGraphics g = e.Graphics;\r\n\t\t\tint width = this.Width - 1;\r\n\t\t\tint height = this.Height - 1;\r\n\r\n\t\t\tPen pen = new Pen(Color.Black, 3f);\r\n\r\n\t\t\tint[] stepLengths = new int[steps.Length];\r\n\r\n\t\t\tif (DynamicStepWidth)\r\n\t\t\t{\r\n\t\t\t\tfor (int i = 0; i &lt; steps.Length; i++)\r\n\t\t\t\t{\r\n\t\t\t\t\tstepLengths[i] = (int)g.MeasureString(steps[i], this.Font).Width;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tfloat sumLenghts = stepLengths.Sum();\r\n\t\t\tif (sumLenghts &lt; width)\r\n\t\t\t{\r\n\t\t\t\tint rest = width - (int)sumLenghts;\r\n\t\t\t\tfor (int i = 0; i &lt; steps.Length; i++)\r\n\t\t\t\t{\r\n\t\t\t\t\tstepLengths[i] += rest \/ steps.Length;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\t\/\/1. links ohne Pfeil\r\n\t\t\t\/\/2-(n-1) mit zwei Pfeilen\r\n\t\t\t\/\/n. rechts ohne Pfeil\r\n\t\t\tfor (int i = 0; i &lt; steps.Count(); i++)\r\n\t\t\t{\r\n\t\t\t\tint startX = SumWidths(i, stepLengths);\/\/ i* stepWidth;\r\n\t\t\t\tPoint[] points = CreateArrowPoints(i, startX, stepLengths[i]);\r\n\r\n\t\t\t\tg.FillPolygon(GetBrush(i), points);\r\n\t\t\t\tg.DrawPolygon(pen, points);\r\n\r\n\t\t\t\tSizeF textWidth = g.MeasureString(steps[i], this.Font);\r\n\t\t\t\tg.DrawString(steps[i], this.Font, Brushes.Black, new PointF(SumWidths(i, stepLengths) + stepLengths[i] \/ 2 - textWidth.Width \/ 2, height \/ 2 - textWidth.Height \/ 2));\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tprivate Brush GetBrush(int stepNr)\r\n\t\t{\r\n\t\t\tif (stepNr == ActiveStep) return new SolidBrush(ActiveStepColor);\r\n\t\t\tif (stepNr &lt; ActiveStep) return new SolidBrush(CompletetStepsColor);\r\n\t\t\treturn new SolidBrush(UncompletetStepsColor);\r\n\t\t}\r\n\r\n\t\tprivate Point[] CreateArrowPoints(int stepNr, int startX, int stepWidth)\r\n\t\t{\r\n\t\t\tPoint[] points = new Point[7];\r\n\t\t\tint width = Width - 1;\r\n\t\t\tint height = Height - 1;\r\n\r\n\t\t\tif (stepNr == 0)\r\n\t\t\t\tpoints[0] = new Point(startX, 0);\r\n\t\t\telse\r\n\t\t\t\tpoints[0] = new Point(startX - ArrowWidth \/ 2, 0);\r\n\r\n\t\t\tif (stepNr == Steps.Count() - 1)\r\n\t\t\t{\r\n\t\t\t\tpoints[1] = new Point(width, 0);\r\n\t\t\t\tpoints[2] = new Point(width, height \/ 2);\r\n\t\t\t\tpoints[3] = new Point(width, height);\r\n\t\t\t}\r\n\t\t\telse\r\n\t\t\t{\r\n\t\t\t\tpoints[1] = new Point(startX + stepWidth - ArrowWidth \/ 2 - 1, 0);\r\n\t\t\t\tpoints[2] = new Point(startX + stepWidth + ArrowWidth \/ 2 - 1, height \/ 2);\r\n\t\t\t\tpoints[3] = new Point(startX + stepWidth - ArrowWidth \/ 2 - 1, height);\r\n\t\t\t}\r\n\r\n\t\t\tif (stepNr == 0)\r\n\t\t\t{\r\n\t\t\t\tpoints[4] = new Point(startX, height);\r\n\t\t\t\tpoints[5] = new Point(startX, height \/ 2);\r\n\t\t\t\tpoints[6] = new Point(startX, 0);\r\n\t\t\t}\r\n\t\t\telse\r\n\t\t\t{\r\n\t\t\t\tpoints[4] = new Point(startX - ArrowWidth \/ 2, height);\r\n\t\t\t\tpoints[5] = new Point(startX + ArrowWidth \/ 2, height \/ 2);\r\n\t\t\t\tpoints[6] = new Point(startX - ArrowWidth \/ 2, 0);\r\n\t\t\t}\r\n\t\t\treturn points;\r\n\t\t}\r\n\r\n\t\t\/\/\/ &lt;summary&gt;\r\n\t\t\/\/\/ Setzt den aktiven Schritt eine Stelle weiter\r\n\t\t\/\/\/ &lt;\/summary&gt;\r\n\t\tpublic void Next()\r\n\t\t{\r\n\t\t\tif(ActiveStep&lt;Steps.Length)\r\n\t\t\t\tActiveStep++;\r\n\t\t}\r\n\r\n\t}\r\n}\r\n<\/pre>\n<p>Man kann dem ProgressStepBar die Schritte einfach als string-Array reinreichen, die Felder werden dann einfach angepasst.<\/p>\n<p>Man kann mit\u00a0<span class=\"lang:default decode:true  crayon-inline \">DynamicStepWidth<\/span>\u00a0 festlegen, ob die Breiten alle gleich sein sollen oder sich dynamisch der Beschriftung anpassen. \u00dcberstehender Platz wird dann auf alle gleichm\u00e4\u00dfig verteilt.<\/p>\n<p>Mit\u00a0<span class=\"lang:default decode:true  crayon-inline\">ActiveStepColor<\/span>\u00a0kann man die Farbe des aktiven Schritts festlegen, ebenso mit\u00a0<span class=\"lang:default decode:true  crayon-inline\">CompletetStepsColor<\/span>\u00a0und\u00a0<span class=\"lang:default decode:true  crayon-inline \">UncompletetStepsColor<\/span>\u00a0 die Farben der erledigten und unerledigten Schritte.<\/p>\n<p>Mit\u00a0<span class=\"lang:default decode:true  crayon-inline \">ArrowWidth<\/span>\u00a0kann man festlegen, wie viele Pixel die Spitze des Pfeils breit sein soll.<\/p>\n<p>Mit\u00a0<span class=\"lang:default decode:true  crayon-inline \">ActiveStep<\/span>\u00a0legt man den aktiven Schritt fest.<\/p>\n<p>Mit der Methode\u00a0<span class=\"lang:default decode:true  crayon-inline \">Next()<\/span>\u00a0schaltet man einfach auf den n\u00e4chsten Schritt weiter.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Manchmal m\u00f6chte man gerne f\u00fcr verschiedene Schritte einen Fortschrittsbalken anzeigen, um zu verdeutlichen, wo man sich gerade befindet. Ein einfacher Fortschrittsbalken kann aber nur einen prozentualen Wert darstellen. Was wir brauchten war ein Fortschrittsbalken, in dem die Schritte benannt werden k\u00f6nnen, die man zu durchwandern hat. Und der Balken sollte nicht einfach langweilige Rechtecke aneinander&hellip;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[1],"tags":[],"class_list":["post-94","post","type-post","status-publish","format-standard","hentry","category-allgemein"],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"http:\/\/dtp-soft.de\/index.php?rest_route=\/wp\/v2\/posts\/94","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/dtp-soft.de\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/dtp-soft.de\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/dtp-soft.de\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/dtp-soft.de\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=94"}],"version-history":[{"count":3,"href":"http:\/\/dtp-soft.de\/index.php?rest_route=\/wp\/v2\/posts\/94\/revisions"}],"predecessor-version":[{"id":97,"href":"http:\/\/dtp-soft.de\/index.php?rest_route=\/wp\/v2\/posts\/94\/revisions\/97"}],"wp:attachment":[{"href":"http:\/\/dtp-soft.de\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=94"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/dtp-soft.de\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=94"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/dtp-soft.de\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=94"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}