Laden...

DataGridViewComboBoxColumn soll verschiedenfarbige Einträge enthalten

Erstellt von diana vor 11 Jahren Letzter Beitrag vor 11 Jahren 3.941 Views
D
diana Themenstarter:in
586 Beiträge seit 2004
vor 11 Jahren
DataGridViewComboBoxColumn soll verschiedenfarbige Einträge enthalten

Hallo,

suche leider vergebens nach einem vernünftigen Ansatz für oben genanntes Problem. Eine DataGridViewComboBoxColumn soll z.B. rot markierte Einträge enthalten, wenn eine andere Spalte im Dataset (Datenquelle) true/false ist.
Das Problem ist wohl eher die Anzeige beim aufklappen der Combobox-Spalte, dass da dann die markierten Items auch wie gewünscht angezeigt werden. Hat jemand eine Idee?

:::

49.485 Beiträge seit 2005
vor 11 Jahren

Hallo diana,

das wird wohl nur mit einer OwnerDrawn-ComBobox gehen. Ob DataGridViewComboBoxen OwnerDrawn sein können, weiß ich allerdings nicht.

herbivore

D
diana Themenstarter:in
586 Beiträge seit 2004
vor 11 Jahren

OwnerDraw? Ich hatte auch schon nach Draw-Events für diese Column gesucht, aber nix. Muss ich dann für diese Spalte ein anderes Coltrol verwenden? Wenn ja welchen "Combobox"-Typen?

:::

C
258 Beiträge seit 2011
vor 11 Jahren

Du kannst das OnCellPaint vom DGV verwenden um selbst zu Zeichnen oder einfach die DGVComboBoxColumn & DGVComboBoxCell ableiten und das Paint überschreiben

public class MyDataGridViewColumn: DataGridViewComboBoxColumn
    {
        public override DataGridViewCell CellTemplate
        {
            get { return new MyDataGridViewCell(); }
        }
    }

    public class MyDataGridViewCell : DataGridViewComboBoxCell
    {
      
        protected override void Paint(Graphics graphics, Rectangle clipBounds, Rectangle cellBounds, int rowIndex, DataGridViewElementStates elementState, object value, object formattedValue, string errorText, DataGridViewCellStyle cellStyle, DataGridViewAdvancedBorderStyle advancedBorderStyle, DataGridViewPaintParts paintParts)
        {
            .....
        }
    }

EDIT: geht bei einer ComboBox nicht wie gewünscht (siehe unten)

D
diana Themenstarter:in
586 Beiträge seit 2004
vor 11 Jahren

Und dann bring ich meine Markierung im Paint unter?

:::

C
258 Beiträge seit 2011
vor 11 Jahren

Bei der Combobox läuft das wohl anders habs gerade ausprobiert.

Das hier könte helfen

        private void dataGridView1_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e)
        {
            if(e.Control is ComboBox)
                ((ComboBox)e.Control).DrawItem += new DrawItemEventHandler(Form1_DrawItem);
        }

        void Form1_DrawItem(object sender, DrawItemEventArgs e)
        {
        }

Source DGVComboBox mit Icons

D
diana Themenstarter:in
586 Beiträge seit 2004
vor 11 Jahren

Danke. Werde ich mal probieren!

:::

D
diana Themenstarter:in
586 Beiträge seit 2004
vor 11 Jahren

Achso, ich verwende aber eine DataGridViewComboBoxColumn und die besitzt leider kein Draw-Event:?

:::

4.221 Beiträge seit 2005
vor 11 Jahren

Früher war ich unentschlossen, heute bin ich mir da nicht mehr so sicher...

D
diana Themenstarter:in
586 Beiträge seit 2004
vor 11 Jahren

So nach dem ich mir die Beispiele etwas näher angeschaut habe, weiß ich auch wo ich ca. hin will. Eigentlich zum DrawItem-Event der DatagridViewComboboxColumn, aber das gibt es leider nicht. Diese Möglichkeit bietet nur die Combobox selbst. Also ein eigenes Control mit den Klassen DataGridViewComboboxColumn : DataGridViewColoumn, Combobox : DataGridViewComboboxCell und ComboboxEditingControl: Combobox , IDataGridViewEditingControl
aufsetzen und die Eigenschaft DrawMode und das Event DrawItem der Combobox der
DataGridViewComboboxColumn durchreichen? Leider weiß ich eben nicht genau, ob mein Lösungsansatz überhaupt Sinn macht und ich so auch wirklich irgendwann an die Forecolor des einzelnen Items rankomme? Oder gibt es eine einfachere Lösung?

:::

D
diana Themenstarter:in
586 Beiträge seit 2004
vor 11 Jahren

Hat vielleicht jemand noch eine Idee, ob ich auf der richtigen Fährte bin oder wie würdet ihr das realisieren?

:::

49.485 Beiträge seit 2005
vor 11 Jahren

Hallo diana,

da es doch einige Klassen, Interfaces, Beziehungen und Unbekannte im Spiel sind, wird das wohl kaum jemand nur nach deiner Beschreibung bestätigen können. Man müsste es ausprobieren. Das kannst und solltest du jedoch am besten selber machen. Wenn Probleme konkrete damit auftauchen, die du genau beschreibst, ist es vermutlich wieder einfacher zu helfen.

herbivore

D
diana Themenstarter:in
586 Beiträge seit 2004
vor 11 Jahren

Ich habe es vorerst noch mal mit dem EditingControlShowing-Event des DataGridView versucht:

 private void dgrv_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e)
        {
            ((ComboBox)e.Control).DrawMode = DrawMode.OwnerDrawFixed;
            ((ComboBox)e.Control).DrawItem += new DrawItemEventHandler(Frm_DrawItem);
            
        }
private void Frm_DrawItem(object sender, DrawItemEventArgs e)
        {
            ComboBox cbo = (ComboBox)sender;
            int yPostition = (e.Index - cbo.Top) * cbo.ItemHeight + 100;

            e.Graphics.DrawString(ds.dt[0]["ANZEIGE_NAME"].ToString(), cbo.Font, new SolidBrush(Color.Blue), 0.0f, yPostition);                            
        }  

Kurz: Ich würde gern bestimmte Items in der DataGridViewComboBox farbig hervor heben! Nach dem obigen ersten wackligen Testcode, bekomme ich zwar farbige Einträge, aber irgentwo im Control und meine Datenbankeinträge aus meinem ds, weiß ich leider auch noch nicht, wie ich die reinbringe, da dieses DrawItem-Event immer ausgeführt wird, wenn ich mit der Mouse drauf binim ausgeklappten Zustand. Vielleicht traut sich jemand ran...:/
Wichtig ist auch erstmal wie zeichne ich die Items, die aus dem DataSet kommen, hab es schon auf die herkömmliche versucht, hat nicht funktioniert.

:::

C
258 Beiträge seit 2011
vor 11 Jahren

Du hast ja den Text sowieso in deiner ComboBox (weil du ja deine daten darauf gemappt hast)

string text = ((ComboBox)sender).Items[e.Index].ToString();

Dann fragst du deine Bedingungen ab,


if(text.Contains("whatever"))
       myBrush = Brushes.Purple;

und am ende Zeichnest du das ganze noch

e.DrawBackground();
e.Graphics.DrawString(text, ((Control)sender).Font, myBrush, e.Bounds.X, e.Bounds.Y);

D
diana Themenstarter:in
586 Beiträge seit 2004
vor 11 Jahren

Vielen Dank für deine Antwort. Gemappt heit sicherlich an eine Datenspalte gehangen, dass habe ich per:

this.col = new DataGridViewComboBoxColumn();                                
                this.col.DataSource = ds.Tables["Name"].DefaultView;
                this.col.DataPropertyName = "NR";
                this.col.ValueMember = "NR";
                this.col.DisplayMember = "ANZEIGE_NR";

realisiert, aber sobald ich das DrawItem-Event verwende, wir kein Eintrag als Textitem in der Combobox angezeigt. Während der Laufzeit ist text auch leider null, also hat die Combobox die Daten doch noch nicht oder nicht mehr, obwohl, was etwas verwundert, die Länge der Count auf die Items stimmt nur der text wird eben nicht abgezeigt:/

:::

C
258 Beiträge seit 2011
vor 11 Jahren

Natürlich wird der Text nicht angezeigt weil du ihn selbst zeichnen musst wenn du das DrawItem Event überschreibst 😉

ComboBox DrawItem

D
diana Themenstarter:in
586 Beiträge seit 2004
vor 11 Jahren

Ich dachte text = ((ComboBox)sender).Items[e.Index].ToString(); hat die einzelnen Items!

Also brauche ich eine solche benutzerdefinierte Combobox? Leider wurde auch nicht beschrieben, wo ich das Add der Items vornehme, im DrawItem? oder vorher?

Habe mal versucht im DrawItem mein ds per Foreach duchzugehen und dann die Einträge per Add zu setzen, da zeigt mir die ComboBox leider nur System.Data-DataRowView an. (Habe den Code zum Test schnell kopiert)

e.DrawBackground();        
            Brush brush;
            // Get the item text.

            try
            {
                foreach (DataRow dr in ds.dt.Rows)
                {
                    ((ComboBox)sender).Items.Add(dr["ANZEIGE_NAME"].ToString());
                }
            }
            catch { }

            string text = ((ComboBox)sender).Items[e.Index].ToString();
            if ((e.State & DrawItemState.Selected) == DrawItemState.Selected)
            {
                brush = Brushes.Yellow;
            }
            else
            {

                    brush = Brushes.Red;
               
            }
            // Draw the text.

            e.Graphics.DrawString(text, ((Control)sender).Font, brush, e.Bounds.X, e.Bounds.Y);

Leider sehe ich immer noch nicht so richtig durch, was noch fehlt:/

:::

C
258 Beiträge seit 2011
vor 11 Jahren

Also du Lädst ja Irgendwo dein DataSet, dannach solltest du deine ComboBox Items auffüllen, (nicht im Interface / sonst hast du in einer InterfaceMethode einen zugriff auf BackgroundDaten was nicht schön ist)

also nachdem dein DataSet Complet ist füllst du deine CombBox

((ComboBox)sender).Items.Add(dr["ANZEIGE_NAME"].ToString())

was du hier machst ist denke ich falsch weil du deine Items mit DataRows auffüllst und nicht mit DataCells (das ToString auf eine DataRow gibt nur den KlassenNamen)

((ComboBox)sender).Items.Add(dr["ANZEIGE_NAME"].Cells[0].ToString())

Würde dir zum Beispiel den wert in der ersten Spalte geben.

EDIT: Stimmt war falsch aber wie man mit einem DataSet arbeitet findest du bestimmt selbst raus.

In deiner DrawItem Methode solltest du dann wieder die Items verwenden so wie es im link Oben auch gemacht wurde.

D
diana Themenstarter:in
586 Beiträge seit 2004
vor 11 Jahren

.Cells wird in diesem Zusammenhang gar nicht angeboten...

Wie man mit einem DataSet arbeitet ist nicht das Problem, sondern das Arbeiten mit einer DataGridViewComboBoxColumn...:/

:::

D
diana Themenstarter:in
586 Beiträge seit 2004
vor 11 Jahren

Daten werden nun aus dem Dataset in die DataGridViewComboBoxColumn geladen, nur leider bringt:

((ComboBox)sender).Items[e.Index].ToString();

im DrawItem immer -1 als Index, sodass kein Item in der DataGridViewComboBoxColumn angezeigt wird. Ich habe es mal mit 0 ausprobiert, da kommt mein erster Eintrag korrekt.
Nun also die nächste Frage, wie komme ich an einen e.Index, sodass mein DrawIndex-Event die Einträge ordentlich anzeigen kann? Momentan siehts so aus, dass ich nur statisch den Index setzen kann z.B. 0 und so wird mein erster Eintrag soviel mal wie Items.Count angezeigt, was ja logisch ist:/ Ich brauche also den "dynamischen Index"?

:::

D
diana Themenstarter:in
586 Beiträge seit 2004
vor 11 Jahren

Guten Morgen,

leider bin ich noch zu keiner weiteren Erkenntnis gekommen, warum e.Index im DrawItem immernoch -1 ist. Habe schon einige Einstellungen verändert, DrawMode, DropDownStyle nichts passiert, obwohl die DataGridViewComboBoxColumn die Daten ja schon hat... Hat jemand noch eine Idee?

:::

C
258 Beiträge seit 2011
vor 11 Jahren

EDIT:
Ich glaube -1 steht für den Header?

Frag einfach auf -1 ab und mach in dem Fall nichts.

Hab ein dummy Projekt erstellt:

public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void dataGridView1_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e)
        {
            ((ComboBox)e.Control).DrawMode = DrawMode.OwnerDrawFixed;
            ((ComboBox)e.Control).DrawItem += new DrawItemEventHandler(Form1_DrawItem);
        }

        void Form1_DrawItem(object sender, DrawItemEventArgs e)
        {
            if (e.Index == -1)
                return;

            e.DrawBackground();
            Brush brush;

            string text = ((ComboBox)sender).Items[e.Index].ToString();
            if ((e.State & DrawItemState.Selected) == DrawItemState.Selected)
            {
                brush = Brushes.Yellow;
            }
            else
            {
                if (text.Contains("special"))
                    brush = Brushes.Red;
                else
                    brush = Brushes.Black;
            }

            e.Graphics.DrawString(text, ((Control)sender).Font, brush, e.Bounds.X, e.Bounds.Y);
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            ((DataGridViewComboBoxColumn)this.dataGridView1.Columns[0]).Items.AddRange(new string[] { "test", "special", "test", "test", "test", "test" });
        }
    }

Nichts für ungut, aber das hat mich ca 5 Minuten gekostet um das auszuprobieren und es funktioniert, mehr eigeninitiative beim nächsten mal

D
diana Themenstarter:in
586 Beiträge seit 2004
vor 11 Jahren
if (e.Index == -1) return;

Hatte gefehlt, ansonsten sieht mein Code genauso aus wie deiner, dass hier natürlich im Header angefangen wird mit zählen, muss man erst wissen, sodass man das abfängt und es dann fröhlich weiter geht. Vielen vielen Dank. Sorry, aber man weiß eben einfach nicht mehr wo man noch suchen soll! Funktioniert alles prima:)

:::