Autor Beitrag
Kasko
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 126
Erhaltene Danke: 1

Win 10
C# C++ (VS 2017/19), (Java, PHP)
BeitragVerfasst: Mo 20.08.18 21:50 
Hallo zusammen,

da ich mit den Möglichkeiten zur Anpassung einer ComboBox nicht zufrieden bin, möchte ich mir kurzerhand eine eigene ComboBox erstellen. Zuerst einmal die Gründe warum ich nicht zufrieden bin:

Es geht vor allem um das Design, welches in diesem standard Control-Grau vorliegt, und welches man nur bedingt anpassen kann. Es gibt zwar die Möglichkeit Eigenschaften, wie die backcolor zu setzen, aber auch das zeigt nur in Maßen die gewünschten Resultate. Eine weitere Möglichkeit ist es die DrawItem-Methode bzw. das DrawItem-Event zu verwenden aber dies hat auch einige Lücken. Es gibt demnach 3 Dinge die mich stören:

1. Die Eigenschaft backcolor verändert lediglich den Hintergrund des DropDowns und des TextFeldes bzw. des Feldes, in dem das aktuelle Item angezeigt wird (nur im Modus DropDown ein TextFeld mit AutoComplete). Unverändert bleiben sowohl die Border als auch der "Foldout-Pfeil". Diese behalten ihre Control-Color, was bei einigen UI-Designs unerträglich ist.

2. Die Farbe der Textmarkierung lässt sich nicht verändern. Bei einer Hintergrundfarbe von beispielsweise R:45 G:45 B:45, also einem dunklen Grau, sieht das Blau zum Beispiel sehr, sehr unpassend aus.

3. Um das Dropdown-Element wird eine bläuliche Border gezogen, welche im normalen Control-Design vielleicht ganz schön aussieht, aber mit anderen Farben sticht sie erstens zu sehr heraus und zweitens sieht sie einfach blöd aus.

Dies sind die 3 Hauptgründe, warum ich eine eigene ComboBox erstellen möchte. Die einzige Sache, die mir schon im theoretischen Ansatz Kopfzerbrechen bereitet ist die Dropdown-List. Diese ist nämlich anscheinend nicht direkt Teil des Steuerelementes. Hier was ich meine:

Normalerweise werden Steuerelemente, wenn sie mit einer Dockeigenschaft versehen werden, welche nicht None lautet, immer neu arrangiert (Location und Size), je nachdem welche Elemente gerade sichtbar sind und welche nicht. Eine ComboBox verhält sich jedoch grundlegend anders. Wenn man den DockStyle auf Top setzt und und ein weiteres beliebiges Element darunter platziert, ebenfalls mit Dock -> Top, und man das Dropdown Element ausfährt, dann wird es über das andere Element drüber gezeichnet, was beweißt, dass es nicht direkt Teil des ComboBox-Formulares ist, da sonst die Höhe hätte verändert werden müssen um das Element sichtbar zu machen und dies hätte das andere Element nach unten geschoben. Mir stellt sich also die Frage, aus was besteht so ein DropDown und wie kann ich das nachbauen?

LG Kasko ;)

PS Wenn jemand Lösungen zu den 3 oben genannten Problemen hat, sind diese auch gerne willkommen.
Ralf Jansen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4700
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: Mo 20.08.18 22:25 
Zitat:
Mir stellt sich also die Frage, aus was besteht so ein DropDown und wie kann ich das nachbauen?


Eine ComboBox besteht nicht aus Einzelteilen die in Winforms schon da sind. Es ist ein Windows Standardcontrol und der Winforms Wrapper darum eine mehr oder weniger leere Hülle. Nun ja leer ist etwas übertrieben aber zumindest bezogen auf das visuelle ziemlich treffend. Die DropDown Liste (wenn du nur das Verhalten/Aussehen beim DropDownStyle DropDown meinst) kannst du dir am ehesten als eigene (nichtmodale) Form vorstellen.

Bedenke bei deinem Rant über das Aussehen der ComboBox das der Look auf allen Windowsversionen mit allen eingestellten Themes halbwegs funktionieren muss. Die Windows Standardcontrols sind so geschrieben um einen applikationsübergreifenden einheitlichen Look zu gewährleisten und nicht um das individuelle Ausleben irgendwelcher Designideen zu erleichtern. Wenn du alle Freiheiten willst bist du bei Winforms falsch. Bei den Standardcontrols optisch irgendetwas auch nur leicht anders machen zu wollen führt üblicherweise dazu alles selbst machen zu müssen.
Kasko Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 126
Erhaltene Danke: 1

Win 10
C# C++ (VS 2017/19), (Java, PHP)
BeitragVerfasst: Mo 20.08.18 23:04 
Zitat:
Wenn du alle Freiheiten willst bist du bei Winforms falsch.


Was gibt es denn für Alternativen, die mir mehr Spielraum im Punkt UI-Design geben, aber trotzdem noch ungefähr die Strukturierungsmöglichkeiten von Winforms haben?
Christian S.
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 20451
Erhaltene Danke: 2264

Win 10
C# (VS 2019)
BeitragVerfasst: Mo 20.08.18 23:56 
Eine große Flexibilität in Bezug auf das Erstellen von individuellen Benutzeroberflächen bietet im .NET-Bereich die Windows Presentation Foundation (WPF): docs.microsoft.com/d...ing-started-with-wpf

Die arbeitet nicht mit den klassichen Windows-Controls und Du kannst - bei entsprechender Einarbeitung in die Materie - alles selber styles und designen.

Der Umstieg von WinForms auf WPF ist aber nicht trivial. Da ist zum einen ein neues Framework für UI samt einer neuen, XML-basierten Beschreibungssprache (XAML), zugleich ist WPF aber auch sehr viel stärker darauf ausgelegt, dass man ein Pattern wie MVVM durchzieht und die Benutzerobefläche durch Data Binding mit Leben gefüllt wird.

_________________
Zwei Worte werden Dir im Leben viele Türen öffnen - "ziehen" und "drücken".
Th69
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 4764
Erhaltene Danke: 1052

Win10
C#, C++ (VS 2017/19/22)
BeitragVerfasst: Di 21.08.18 09:36 
How to create a custom ComboBox from scratch erstellt eine eigene (WinForms-)ComboBox auf Basis einer TextBox und einer ListBox.
Kirk1701A
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 126
Erhaltene Danke: 3

Linux, Ubuntu, Mac, IOS, Android (4.2.x - 9.x.x), Win Mob., Micro. DOS, Win 95, Win 98, Win 2000, Win ME, Win XP, Win Vista, Win 7, Win8.1, Win 10
C# (VS 2017 Community/Enterprise, VS 2019 Professional/Enterprise), VB (VBA), JavaScript
BeitragVerfasst: Di 21.08.18 19:03 
Ich hätte das in einer CSS festgelegt und dann einen Verweis darauf gesetzt, dass es auch funktioniert.

_________________
"Ich war es und werde es immer bleiben... Ihr Freund!"
@Spock -> Star Trek II: Der Zorn des Khan
Christian S.
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 20451
Erhaltene Danke: 2264

Win 10
C# (VS 2019)
BeitragVerfasst: Di 21.08.18 19:08 
CSS in WinForms :gruebel:

_________________
Zwei Worte werden Dir im Leben viele Türen öffnen - "ziehen" und "drücken".
Kasko Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 126
Erhaltene Danke: 1

Win 10
C# C++ (VS 2017/19), (Java, PHP)
BeitragVerfasst: Mi 22.08.18 16:55 
Ich bin jetzt dabei das DropDown Menu zu erstellen. Ich nutze dafür ein ToolStripDropDown. Es gibt nur ein Problem. Sowohl die Hintergrundfarbe des DropDown als auch die Hintergrundfarben der Label die die Item repräsentieren lassen sich nicht setzen. Hat jemand dafür eine Lösung? Im Internet finde ich Lösungen zu ToolStrips in denen ToolStripRenderer verwendet werden. Ich weiß aber nicht genau wie ich sie einsetzen soll um das zu erreichen was ich möchte.
Ralf Jansen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4700
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: Mi 22.08.18 20:04 
Ich vermute mal du meinst die einzelnen ListBox Items die in deiner ListBox stecken die du als DropDown mißbrauchst? Zumindest macht das der verlinkte Beispielcode.

In dem Fall musst du die ListBox auf selbstzeichnen stellen (via der DrawMode Property). Jetzt zeichnet die ListBox ihren Inhalt nicht mehr sondern feuert für dich den DrawItem Event wo du dann das Item selbst zeichnen kannst. Die Doku für ListBox.DrawMode hat dafür ein Beispiel. Sei dir aber bewusst das das Beispiel nur ein Beispiel ist. Was das zeichnen betrifft ist es natürlich unvollständig. Es zeigt nur wie man irgendetwas in dem Event zeichnet aber nicht was man alles noch berücksichtigen muss oder sollte. Z.B. sollten das markierte Item anders aussehen als die anderen. Wenn man mit der Maus über einem Item hovert soll es möglicherweise auch anders aussehen etc.

Übrigens Controls haben natürlich auch bestimmte Verhalten nicht nur aussehen. Die Wahrscheinlichkeit das eine ListBox in einem ToolStrip sich genauso verhält wie eine ComboBox ist eher gering. Ich vermute mal schwer das man so die Tastaturbedienung zerlegt bzw. sich das anders verhält und sich eine solche ~Combobox~ regelmäßig zu den falschen Zeitpunkten schließt oder ähnliches. Will sagen deine Combobox mag nachher schöner aussehen sie wird sich aber vermutlich in vielen Bereichen anders verhalten um nicht zu sagen falsch.
Kasko Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 126
Erhaltene Danke: 1

Win 10
C# C++ (VS 2017/19), (Java, PHP)
BeitragVerfasst: Mi 22.08.18 22:58 
Ich verwende keine ListBox. Ich verwende einfach nur ein ToolStripDropDown, dem ich dann mehrere ToolStripLabel hinzufüge. Es gibt aber mehrere Probleme aber zuvor mein momentaner Render-Code:

ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
using System.Drawing;
using System.Windows.Forms;

namespace CustomControls {
    public class LabelToolStripRenderer : ToolStripRenderer {
        private Color toolStripBorderColor, labeBackColor;

        public LabelToolStripRenderer(Color borderColor, Color labelColor) {
            labeBackColor = labelColor;
            toolStripBorderColor = borderColor;
        }

        protected override void OnRenderLabelBackground(ToolStripItemRenderEventArgs e) {
            SolidBrush brush = new SolidBrush(labeBackColor);
            Rectangle rect = new Rectangle(e.Item.ContentRectangle.X, e.Item.ContentRectangle.Y, e.ToolStrip.Width - 2, e.Item.Height);
            e.Graphics.FillRectangle(brush, e.Item.ContentRectangle);
            brush.Dispose();
        }

        protected override void OnRenderToolStripBorder(ToolStripRenderEventArgs e) {
            Pen pen = new Pen(toolStripBorderColor, 1);
            e.Graphics.DrawRectangle(pen, e.ToolStrip.Bounds);
        }
    }
}


Hier die Probleme:

1. Es wird nicht immer die gesamte Zeile des Labels mit der Hintergrundfarbe gefüllt. Der Grund ist klar. Die AutoSize Eigenschaft ist auf true gesetzt und deshalb reicht das Label halt nicht immer bis zum Ende. Das Problem ist, da ich möchte dass immer die gesamte Zeile ausgefüllt wird, muss ich AutoSize auf false setzen. Dabei treten aber einige Probleme auf. Zum einen schrumpft das DropDown auf eine Breite von nicht mehr als 10, egal welchen Wert ich für Width einsetze. Zudem liegen die Labels nicht mehr an der linken Seite sondern sind zentriert auf ihrer Zeile.

2. Kurz und knapp. Die OnRenderToolStripBorder Methode zeichnet die Border nicht.

3. Ebenfalls kurz und knapp. Ich finde keine Methode, mit der ich das Zeichnen des Hintergrundes des DropDowns anpassen kann. Die Eigenschaft BackColor funktioniert auch nicht.

Edit:

Nur noch das 1. Problem.
Ralf Jansen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4700
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: Do 23.08.18 19:51 
Da sind wir aber jetzt aber ziemlich weit weg von einer ComboBox.

Wenn sich dein ToolStripRenderer komisch verhält hilft dir vielleicht anzusehen wie Microsoft das gelöst hat? Z.b. im ToolStripProfessionalRenderer.

OnRenderLabelBackground sieht zwar unauffällig aus (nicht prinzipiell anders als dein Code) aber vielleicht siehst du ja ein Detail das dir entgangen ist.