Вопрос по – Есть ли способ заставить DataGridView запустить событие CellFormatting для всех ячеек?

12

Мы используем событие CellFormatting для окрашивания ячеек кода в различных сетках по всему нашему приложению.

У нас есть некоторый общий код, который обрабатывает экспорт в Excel (и печатает), но делает это в черно-белом режиме. Теперь мы хотим изменить это и выбрать цвет из сетки.

Этовопрос отве помог (и это работает) ... за исключением проблемы с большими сетками, которые выходят за рамки одного экрана. Части сетки, которые еще не отображались на экране, (по логике) никогда не запускают свой код CellFormatting, поэтому их основной цвет никогда не устанавливается. В результате в Excel цветовое кодирование исчезает На полпути вниз по странице.

Кажется, есть три решения:

1) Скажите пользователю, что он должен прокрутить все части сетки, прежде чем выполнять экспорт в Excel.Ha! Не серьезное решение

2) Программно прокрутите все части сетки перед выполнением экспорта в Excel. Только чуть менее ужасно, чем (1)

3) В нашем коде «Экспорт в Excel» запустите что-нибудь вверху, что говорит DataGridView рисовать / форматировать всю область, наприме

  MyDataGridView.FormatAllCells()

Есть ли что-то подобное?

О, и есть четвертый вариант, но это будет касаться огромного количества существующего кода:

4) Прекратите использовать событие CellFormatting, отформатируйте ячейки во время загрузки. Проблема в том, что нам пришлось бы переоснастить каждую сетку в нашем приложении, поскольку CellFormatting - это способ, которым мы делали это с года.

У меня плохое предчувствие, что не будет решения для варианта 3. Я могу предложить вариант 5. В настоящее время у вас есть логика форматирования, которая задает цвет и, возможно, некоторые другие свойства стиля, основанные на значении ячейки. Если вы сделаете эту логику новым методом, вы можете вызвать этот метод как из форматирования ячейки, так и из кода Excel. Таким образом вы гарантируете, что Excel и форматирование ячеек всегда одинаковы, но больше не полагаетесь на форматирование ячеек, вызванное для экспорта в Excel. David Hall
Другой вариант (вариант 4) - использовать CellValueChanged для форматирования. David Hall

Ваш Ответ

5   ответов
6

уп к свойству Cell.FormattedValue каждой ячейки. Согласно с Microsoft, это вызывает событие CellFormattin

на самом деле, это звучит как справедливое предложение hawbsl
Благодарность.Dim strValue As String For r As Integer = 0 To dgv.Rows.Count - 1 For c As Integer = 0 To dgv.Columns.Count - 1 strValue = dgv.Rows(r).Cells(c).FormattedValue() Next Next AjV Jsy
3

DataGridViewCell.FormattedValue действительно простой способ заставиCellFormatting событие, которое будет (повторно) вызываться для конкретной ячейки. В моем случае, однако, это свойство также приводило к нежелательным побочным эффектам, связанным с автоматическим изменением размера столбцов. В поисках подходящего решения долгое время я, наконец, столкнулся со следующими магическими методами, которые отлично работают:DataGridView.Invalidate(), DataGridView.InvalidateColumn(), DataGridView.InvalidateRow(), а такжеDataGridView.InvalidateCell().

Эти 4 метода заставляютCellFormatting событие, которое будет вызываться повторно только для указанной области (ячейка, столбец, строка или вся таблица), а также без каких-либо неприятных артефактов автоматического изменения размера.

2

.FormatAllCells наш единственный вариант - прекратить использование CellFormatting.

Однако новая проблема заключается в том, что применение форматирования стиля ячейки во время загрузки, похоже, не дает никакого эффекта. Много постов там, если вы Google это. Также они указывают, что если вы поместите тот же код под кнопкой на форме и щелкнете по ней после загрузки (вместо загрузки, код будет работать ... поэтому сетка должна быть видимой, прежде чем можно будет применить стиль). Большинство советов по этой теме предлагает вам использовать ... барабанную дробь ... CellFormatting. Aargh

В конце концов нашел пост, который предлагает использоватьDataBindingComplete событие сетки. И это работает.

Правда, это решение является вариантом моей нежелательной опции "4".

2

и в итоге я нашел нечто похожее на ваше решение № 4. как ты, я использовалDataBindingComplete мероприятие. но, поскольку я использовал метод Extension, изменения в существующем коде терпимы:

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);
        }
    }
}
1

если вы хотите повторно использовать форматирование, предоставляемое во время события Cellformatting (например, элементы cellstyle, такие как fontbold и backgroundcolor). Эти стили ячеек, по-видимому, доступны только между событиями 'cellformatting' и 'cellpainting', но не в самом стиле ячейки datagridview ..

Захватите стили ячеек во время события cellformatting вторым обработчиком, подобным этому:

в экспортном модуле добавить общий список, массив или словарь для хранения стилей ячеек:

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

initialize словарь и добавьте второй обработчик к представлению данных в вашем коде печати или экспорта. В vb.net как то так:

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

Добавьте код для обработчика

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

Очень важны: чтобы убедиться, что исходное событие cellformating (и второй обработчик cellformatting после этого) действительно вызваны, вы должны запросить FormattedValue для каждой ячейки, которую вы хотите напечатать (например,

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

!

При печати вы можете проверить, имеет ли ячейка форматирование. Например.

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

в конце экспорта или printcode удалите обработчик и установите словарь в ничто

RemoveHandler DirectCast(itemToPrint.TheControl, DataGridView).CellFormatting, AddressOf OnPrintDataGridView_CellFormatting
oDataGridFormattingDictionary = nothing

Похожие вопросы