Gibt es eine Möglichkeit, eine DataGridView zu zwingen, ihr CellFormatting-Ereignis für alle Zellen auszulösen?

StackOverflow https://stackoverflow.com//questions/10651702

Frage

Wir verwenden das CellFormatting-Ereignis, um Zellen in verschiedenen Rastern in unserer gesamten Anwendung farblich zu kennzeichnen.

Wir haben generischen Code, der den Export nach Excel (und das Drucken) übernimmt, allerdings in Schwarzweiß.Dies wollen wir nun ändern und die Farbe aus den Rastern übernehmen.

Das Frage Antwort hat geholfen (und es funktioniert) ...außer dass es ein Problem mit größeren Rastern gibt, die über einen einzelnen Bildschirm hinausgehen.Für die Teile des Rasters, die noch nicht auf dem Bildschirm angezeigt wurden, wird der CellFormatting-Code (logischerweise) nie ausgelöst, und daher wird die zugrunde liegende Farbe nie festgelegt.Dadurch ergibt sich in Excel die Farbkodierung verpufft auf halber Höhe der Seite.

Es scheint, dass es drei Lösungen gibt:

1) Teilen Sie dem Benutzer mit, dass er zu allen Teilen des Rasters scrollen muss, bevor er einen Export nach Excel durchführt. Ha!Keine ernsthafte Lösung

2) Scrollen Sie programmgesteuert zu allen Teilen des Rasters, bevor Sie einen Export nach Excel durchführen. Nur etwas weniger schrecklich als (1)

3) Lösen Sie in unserem Code „Nach Excel exportieren“ oben etwas aus, das DataGridView anweist, seinen gesamten Bereich zu malen/formatieren, z. B.

  MyDataGridView.FormatAllCells()

Gibt es etwas, das so etwas macht???

Oh, und es gibt noch eine vierte Option, aber diese erfordert, dass eine große Menge vorhandener Codes berührt wird:

4) Beenden Sie die Verwendung des CellFormatting-Ereignisses und formatieren Sie die Zellen beim Laden.Das Problem dabei ist, dass wir jedes Raster in unserer Anwendung umrüsten müssten, da CellFormatting die Art und Weise ist, wie wir es seit dem letzten Jahr machen.

War es hilfreich?

Lösung 3

Vorausgesetzt, wie @DavidHall vorschlägt, gibt es keine Magie .FormatAllCells Unsere einzige Möglichkeit besteht darin, CellFormatting nicht mehr zu verwenden.

Ein neues Problem hierbei besteht jedoch darin, dass die Anwendung der Formatierung im Zellstil während des Ladevorgangs offenbar keine Auswirkung hat.Es gibt viele Beiträge da draußen, wenn man sie googelt.Sie weisen außerdem darauf hin, dass der Code funktioniert, wenn Sie denselben Code unter eine Schaltfläche im Formular einfügen und nach dem Laden darauf klicken (statt beim Laden).Daher muss das Raster sichtbar sein, bevor das Styling angewendet werden kann.Die meisten Ratschläge zu diesem Thema schlagen vor, dass Sie Folgendes verwenden:Trommelwirbel ...Zellformatierung.Aargh!

Irgendwann habe ich einen Beitrag gefunden, der die Verwendung von vorschlägt DataBindingComplete Ereignis des Gitters.Und das funktioniert.

Zugegebenermaßen handelt es sich bei dieser Lösung um eine Variante meiner unerwünschten Option „4“.

Andere Tipps

Ich habe eine mögliche Lösung - in Ihrer Exportfunktion Zugriff auf das Cell.FormatedValue-Eigenschaft jeder Zelle.Laut Microsoft , er zwingt dasCellformating-Ereignis zum Feuer.

Wie in den anderen Antworten erwähnt, ist der Zugriff auf DataGridViewCell.FormattedValue ist in der Tat eine einfache Möglichkeit, das zu erzwingen CellFormatting Ereignis, das für eine bestimmte Zelle (erneut) aufgerufen werden soll.In meinem Fall führte diese Eigenschaft jedoch auch zu unerwünschten Nebeneffekten, die die automatische Größenänderung der Spalten betrafen.Während ich lange nach einer praktikablen Lösung suchte, bin ich schließlich auf die folgenden magischen Methoden gestoßen, die perfekt funktionieren: DataGridView.Invalidate(), DataGridView.InvalidateColumn(), DataGridView.InvalidateRow(), Und DataGridView.InvalidateCell().

Diese 4 Methoden erzwingen die CellFormatting Das Ereignis kann nur für den angegebenen Bereich (Zelle, Spalte, Zeile oder ganze Tabelle) erneut aufgerufen werden, und zwar ohne unangenehme Artefakte bei der automatischen Größenänderung.

Ich hatte das gleiche Problem und bin am Ende auf etwas gestoßen, das Ihrer Lösung Nr. 4 sehr ähnlich ist.Wie du habe ich das verwendet DataBindingComplete Ereignis.Aber da ich die Erweiterungsmethode verwendet habe, sind die Änderungen im vorhandenen Code erträglich:

internal static class DataGridViewExtention
{
    public static void SetGridBackColorMyStyle(this DataGridView p_dgvToManipulate)
    {
        p_dgvToManipulate.RowPrePaint += p_dgvToManipulate_RowPrePaint;
        p_dgvToManipulate.DataBindingComplete += p_dgvToManipulate_DataBindingComplete;
    }

    // for the first part - Coloring the whole grid I used the `DataGridView.DataBindingComplete` event:
    private static void p_dgvToManipulate_DataBindingComplete(object sender, DataGridViewBindingCompleteEventArgs e)
    {
        foreach (DataGridViewRow objCurrRow in ((DataGridView)sender).Rows)
        {
            // Get the domain object from row 
            DomainObject objSelectedItem = (DomainObject)objCurrRow.DataBoundItem;

            // if item is valid ....
            if objSelectedItem != null)
            {
                // Change backcolor of row using my method
                objCurrRow.DefaultCellStyle.BackColor = GetColorForMyRow(objSelectedItem);
            }
        }
    }

    // for the second part (disabling the Selected row from effecting the BackColor i've setted myself, i've used `DataGridView.RowPrePaint` event:
    private static void p_dgvToManipulate_RowPrePaint(object sender, DataGridViewRowPrePaintEventArgs e)
    {
        // If current row about to be painted is selected by user
        if (((DataGridView)sender).Rows[e.RowIndex].Selected)
        {
            // Get current grid row
            var objGridRow = ((DataGridView)sender).Rows[e.RowIndex];

            // Get selectedItem
            DomainObject objSelectedItem = (DomainObject)objGridRow.DataBoundItem;

            // if item is valid ....
            if (objSelectedItem != null && objSelectedItem.ObjectId != 0)
            {
                // Set color for row instead of "DefaultCellStyle" (same color as we used at DataBindingComplete event)
                objGridRow.DefaultCellStyle.SelectionBackColor = GetColorForMyRow(objSelectedItem);
            }

            // Since the selected row is no longer unique, we need to let the used to identify it by making the font Bold
            objGridRow.DefaultCellStyle.Font = new Font(((DataGridView)sender).Font.FontFamily, ((DataGridView)sender).Font.Size, FontStyle.Bold);
        }
        // If current row is not selected by user
        else
        {
            // Make sure the Font is not Bold. (for not misleading the user about selected row...)
            ((DataGridView)sender).Rows[e.RowIndex].DefaultCellStyle.Font = new Font(((DataGridView)sender).Font.FontFamily,
                                                                                   ((DataGridView)sender).Font.Size, FontStyle.Regular);
        }
    }
}

Eine mögliche Lösung, wenn Sie die während des CellFormating-Events bereitgestellte Formatierung wiederverwenden möchten (z. B. die Zellstyle-Elemente wie Fontbold und BackgroundColor). Diese Zellstyles scheinen nur zwischen den Ereignissen der Celfformating- und 'CELLPAINTING-Ereignisse verfügbar sein, jedoch nicht im DataGridView-Cell's-Stil selbst ..

Erfassen Sie die Zellstyles während des Cellformating-Events mit einem zweiten Handler wie diesem:

    .
  1. Im ExportModule Fügen Sie eine gemeinsam genutzte Liste, ein Array oder das Wörterbuch hinzu, um die Zellstylen zu speichern:

    Dim oDataGridFormattingDictionary as  Dictionary(Of String, DataGridViewCellStyle) = nothing
    

  2. Initialisieren Sie das Wörterbuch und fügen Sie dem DataGridView in Ihrem Druck- oder Exportcode einen zweiten Handler hinzu. In vb.net so etwas so:

     oDataGridFormattingDictionary = New Dictionary(Of String, DataGridViewCellStyle)
     AddHandler MyDatagridviewControl.CellFormatting, AddressOf OnPrintDataGridView_CellFormatting
    

  3. Fügen Sie den Code für den Handler hinzu

    Private Sub OnPrintDataGridView_CellFormatting(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewCellFormattingEventArgs)
    If e.RowIndex > -1 AndAlso e.ColumnIndex > -1 AndAlso Not e.CellStyle Is Nothing Then
       If Not oDataGridFormattingDictionary Is Nothing andalso oDataGridFormattingDictionary.ContainsKey(e.RowIndex & "_" & e.ColumnIndex) = False Then
        oDataGridFormattingDictionary.Add(e.RowIndex & "_" & e.ColumnIndex, e.CellStyle)
       End If
    End If
    End Sub
    

  4. sehr wichtig : Um sicherzustellen, dass das ursprüngliche Cellformating-Event (und der zweite Celloformating-Handler danach) tatsächlich aufgerufen werden, müssen Sie den formattedvalue anfordern für jede Zelle, die Sie drucken möchten (z. B. generasacodicetagpre.

    !

  5. Wenn Sie beim Drucken drucken, können Sie jetzt prüfen, ob die Zelle das Formatieren hat. E.g.:

    oValue = Datagridview.rows(printRowIndex).Cells(printColumnIndex).FormattedValue)
    

  6. Am Ende des Exports oder Printcode Entfernen Sie den Handler und setzen Sie das Wörterbuch auf nichts

    if not oDataGridFormattingDictionary is nothing andalso oDataGridFormattingDictionary.ContainsKey(printRowIndex & "_" & printColumnIndex) Then
    ... the cellstyle is accesible via:
    oDataGridFormattingDictionary(printRowIndex & "_" & printColumnIndex)
    end if 
    

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top