Windows Develop Bookmark and Share   
 index > Windows Forms Data Controls and Databinding > Sample Code: DataGridView progress bar column
 

Sample Code: DataGridView progress bar column

I have a column that has integer data in it, I want to display it as a progress bar in the column so the user can quickly identify lagging processes.

 

I just started with 2005 and it looks great but does anyone know a quick way to do this?

I would also like to change the color of the progress bar based on the cells value.

I found in the data sources toolbox where I can change the column to progress bar but that does not pass through to the grid.

 

Thanks for ANY help with this

Stephen Hauck  Wednesday, December 21, 2005 6:47 PM

Here is an unsupported progress bar cell/column sample in VB and C#:

VB:


'---------------------------------------------------------------------
' THIS CODE AND INFORMATION ARE PROVIDED AS IS WITHOUT WARRANTY OF ANY
' KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
' IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
' PARTICULAR PURPOSE.
'---------------------------------------------------------------------

Imports System.Drawing
Imports System.ComponentModel

Public Class DataGridViewProgressColumn
    Inherits DataGridViewImageColumn

    Public Sub New()
        Me.CellTemplate = New DataGridViewProgressCell
    End Sub

End Class
Public Class DataGridViewProgressCell
    Inherits DataGridViewImageCell
   
    Sub New()
        ValueType = Type.GetType("Integer")
    End Sub

    ' Method required to make the Progress Cell consistent with the default Image Cell.
    ' The default Image Cell assumes an Image as a value, although the value of the Progress Cell is an Integer.
    Protected Overrides Function GetFormattedValue( _
        ByVal value As Object, _
        ByVal rowIndex As Integer, _
        ByRef cellStyle As DataGridViewCellStyle, _
        ByVal valueTypeConverter As TypeConverter, _
        ByVal formattedValueTypeConverter As TypeConverter, _
        ByVal context As DataGridViewDataErrorContexts _
        ) As Object

        Static emptyImage As Bitmap = New Bitmap(1, 1, System.Drawing.Imaging.PixelFormat.Format32bppArgb)
        GetFormattedValue = emptyImage
    End Function


    Protected Overrides Sub Paint(ByVal g As System.Drawing.Graphics, ByVal clipBounds As System.Drawing.Rectangle, ByVal cellBounds As System.Drawing.Rectangle, ByVal rowIndex As Integer, ByVal cellState As System.Windows.Forms.DataGridViewElementStates, ByVal value As Object, ByVal formattedValue As Object, ByVal errorText As String, ByVal cellStyle As System.Windows.Forms.DataGridViewCellStyle, ByVal advancedBorderStyle As System.Windows.Forms.DataGridViewAdvancedBorderStyle, ByVal paintParts As System.Windows.Forms.DataGridViewPaintParts)
        Dim progressVal As Integer = CType(value, Integer)
        Dim percentage As Single = CType((progressVal / 100), Single)
        Dim backBrush As Brush = New SolidBrush(cellStyle.BackColor)
        Dim foreBrush As Brush = New SolidBrush(cellStyle.ForeColor)

        ' Call the base class method to paint the default cell appearance.
        MyBase.Paint(g, clipBounds, cellBounds, rowIndex, cellState, _
            value, FormattedValue, ErrorText, cellStyle, _
            advancedBorderStyle, paintParts)

        If percentage > 0.0 Then
            ' Draw the progress bar and the text
            g.FillRectangle(New SolidBrush(Color.FromArgb(163, 189, 242)), cellBounds.X + 2, cellBounds.Y + 2, Convert.ToInt32((percentage * cellBounds.Width - 4)), cellBounds.Height - 4)
            g.DrawString(progressVal.ToString() & "%", cellStyle.Font, foreBrush, cellBounds.X + 6, cellBounds.Y + 2)
        Else
            'draw the text

            If Not Me.DataGridView.CurrentCell Is Nothing AndAlso Me.DataGridView.CurrentCell.RowIndex = rowIndex Then
                g.DrawString(progressVal.ToString() & "%", cellStyle.Font, New SolidBrush(cellStyle.SelectionForeColor), cellBounds.X + 6, cellBounds.Y + 2)
            Else
                g.DrawString(progressVal.ToString() & "%", cellStyle.Font, foreBrush, cellBounds.X + 6, cellBounds.Y + 2)
            End If
        End If
    End Sub

End Class
 

Here is the C# version:


//---------------------------------------------------------------------
//THIS CODE AND INFORMATION ARE PROVIDED AS IS WITHOUT WARRANTY OF ANY
//KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
//IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
//PARTICULAR PURPOSE.
//---------------------------------------------------------------------

using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Drawing;
using System.ComponentModel;

namespace Sample
{
    public class DataGridViewProgressColumn : DataGridViewImageColumn
    {
        public DataGridViewProgressColumn()
        {
            CellTemplate = new DataGridViewProgressCell();
        }
    }
}

namespace Sample
{
    class DataGridViewProgressCell : DataGridViewImageCell 
    {
        // Used to make custom cell consistent with a DataGridViewImageCell
        static Image emptyImage;
        static DataGridViewProgressCell()
        {
            emptyImage = new Bitmap(1, 1, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
        }

        public DataGridViewProgressCell()
        {
            this.ValueType = typeof(int);
        }

        // Method required to make the Progress Cell consistent with the default Image Cell.
        // The default Image Cell assumes an Image as a value, although the value of the Progress Cell is an int.
        protected override object GetFormattedValue(object value,
                            int rowIndex, ref DataGridViewCellStyle cellStyle,
                            TypeConverter valueTypeConverter,
                            TypeConverter formattedValueTypeConverter,
                            DataGridViewDataErrorContexts context)
        {
            return emptyImage;
        }

       
        protected override void Paint(System.Drawing.Graphics g, System.Drawing.Rectangle clipBounds, System.Drawing.Rectangle cellBounds, int rowIndex, DataGridViewElementStates cellState, object value, object formattedValue, string errorText, DataGridViewCellStyle cellStyle, DataGridViewAdvancedBorderStyle advancedBorderStyle, DataGridViewPaintParts paintParts)
        {
            int progressVal = (int)value;
            float percentage = ((float)progressVal / 100.0f); // Need to convert to float before division; otherwise C# returns int which is 0 for anything but 100%.
            Brush backColorBrush = new SolidBrush(cellStyle.BackColor);
            Brush foreColorBrush = new SolidBrush(cellStyle.ForeColor);

            // Draws the cell grid
            base.Paint(g, clipBounds, cellBounds,
             rowIndex, cellState, value, formattedValue, errorText,
             cellStyle, advancedBorderStyle, (paintParts & ~DataGridViewPaintParts.ContentForeground));

            if (percentage > 0.0)
            {
                // Draw the progress bar and the text
                g.FillRectangle(new SolidBrush(Color.FromArgb(163, 189, 242)), cellBounds.X + 2, cellBounds.Y + 2, Convert.ToInt32((percentage * cellBounds.Width - 4)), cellBounds.Height - 4);
                g.DrawString(progressVal.ToString() + "%", cellStyle.Font, foreColorBrush, cellBounds.X + 6, cellBounds.Y + 2);
            }
            else
            {
                // draw the text
                if (this.DataGridView.CurrentRow.Index == rowIndex)
                    g.DrawString(progressVal.ToString() + "%", cellStyle.Font, new SolidBrush(cellStyle.SelectionForeColor), cellBounds.X + 6, cellBounds.Y + 2);
                else
                    g.DrawString(progressVal.ToString() + "%", cellStyle.Font, foreColorBrush, cellBounds.X + 6, cellBounds.Y + 2);
            }
        }
    }
}

 

-mark
DataGridView Program Manager
Microsoft
This post is provided "as-is"

Mark Rideout  Wednesday, December 21, 2005 9:39 PM

Here is an unsupported progress bar cell/column sample in VB and C#:

VB:


'---------------------------------------------------------------------
' THIS CODE AND INFORMATION ARE PROVIDED AS IS WITHOUT WARRANTY OF ANY
' KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
' IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
' PARTICULAR PURPOSE.
'---------------------------------------------------------------------

Imports System.Drawing
Imports System.ComponentModel

Public Class DataGridViewProgressColumn
    Inherits DataGridViewImageColumn

    Public Sub New()
        Me.CellTemplate = New DataGridViewProgressCell
    End Sub

End Class
Public Class DataGridViewProgressCell
    Inherits DataGridViewImageCell
   
    Sub New()
        ValueType = Type.GetType("Integer")
    End Sub

    ' Method required to make the Progress Cell consistent with the default Image Cell.
    ' The default Image Cell assumes an Image as a value, although the value of the Progress Cell is an Integer.
    Protected Overrides Function GetFormattedValue( _
        ByVal value As Object, _
        ByVal rowIndex As Integer, _
        ByRef cellStyle As DataGridViewCellStyle, _
        ByVal valueTypeConverter As TypeConverter, _
        ByVal formattedValueTypeConverter As TypeConverter, _
        ByVal context As DataGridViewDataErrorContexts _
        ) As Object

        Static emptyImage As Bitmap = New Bitmap(1, 1, System.Drawing.Imaging.PixelFormat.Format32bppArgb)
        GetFormattedValue = emptyImage
    End Function


    Protected Overrides Sub Paint(ByVal g As System.Drawing.Graphics, ByVal clipBounds As System.Drawing.Rectangle, ByVal cellBounds As System.Drawing.Rectangle, ByVal rowIndex As Integer, ByVal cellState As System.Windows.Forms.DataGridViewElementStates, ByVal value As Object, ByVal formattedValue As Object, ByVal errorText As String, ByVal cellStyle As System.Windows.Forms.DataGridViewCellStyle, ByVal advancedBorderStyle As System.Windows.Forms.DataGridViewAdvancedBorderStyle, ByVal paintParts As System.Windows.Forms.DataGridViewPaintParts)
        Dim progressVal As Integer = CType(value, Integer)
        Dim percentage As Single = CType((progressVal / 100), Single)
        Dim backBrush As Brush = New SolidBrush(cellStyle.BackColor)
        Dim foreBrush As Brush = New SolidBrush(cellStyle.ForeColor)

        ' Call the base class method to paint the default cell appearance.
        MyBase.Paint(g, clipBounds, cellBounds, rowIndex, cellState, _
            value, FormattedValue, ErrorText, cellStyle, _
            advancedBorderStyle, paintParts)

        If percentage > 0.0 Then
            ' Draw the progress bar and the text
            g.FillRectangle(New SolidBrush(Color.FromArgb(163, 189, 242)), cellBounds.X + 2, cellBounds.Y + 2, Convert.ToInt32((percentage * cellBounds.Width - 4)), cellBounds.Height - 4)
            g.DrawString(progressVal.ToString() & "%", cellStyle.Font, foreBrush, cellBounds.X + 6, cellBounds.Y + 2)
        Else
            'draw the text

            If Not Me.DataGridView.CurrentCell Is Nothing AndAlso Me.DataGridView.CurrentCell.RowIndex = rowIndex Then
                g.DrawString(progressVal.ToString() & "%", cellStyle.Font, New SolidBrush(cellStyle.SelectionForeColor), cellBounds.X + 6, cellBounds.Y + 2)
            Else
                g.DrawString(progressVal.ToString() & "%", cellStyle.Font, foreBrush, cellBounds.X + 6, cellBounds.Y + 2)
            End If
        End If
    End Sub

End Class
 

Here is the C# version:


//---------------------------------------------------------------------
//THIS CODE AND INFORMATION ARE PROVIDED AS IS WITHOUT WARRANTY OF ANY
//KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
//IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
//PARTICULAR PURPOSE.
//---------------------------------------------------------------------

using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Drawing;
using System.ComponentModel;

namespace Sample
{
    public class DataGridViewProgressColumn : DataGridViewImageColumn
    {
        public DataGridViewProgressColumn()
        {
            CellTemplate = new DataGridViewProgressCell();
        }
    }
}

namespace Sample
{
    class DataGridViewProgressCell : DataGridViewImageCell 
    {
        // Used to make custom cell consistent with a DataGridViewImageCell
        static Image emptyImage;
        static DataGridViewProgressCell()
        {
            emptyImage = new Bitmap(1, 1, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
        }

        public DataGridViewProgressCell()
        {
            this.ValueType = typeof(int);
        }

        // Method required to make the Progress Cell consistent with the default Image Cell.
        // The default Image Cell assumes an Image as a value, although the value of the Progress Cell is an int.
        protected override object GetFormattedValue(object value,
                            int rowIndex, ref DataGridViewCellStyle cellStyle,
                            TypeConverter valueTypeConverter,
                            TypeConverter formattedValueTypeConverter,
                            DataGridViewDataErrorContexts context)
        {
            return emptyImage;
        }

       
        protected override void Paint(System.Drawing.Graphics g, System.Drawing.Rectangle clipBounds, System.Drawing.Rectangle cellBounds, int rowIndex, DataGridViewElementStates cellState, object value, object formattedValue, string errorText, DataGridViewCellStyle cellStyle, DataGridViewAdvancedBorderStyle advancedBorderStyle, DataGridViewPaintParts paintParts)
        {
            int progressVal = (int)value;
            float percentage = ((float)progressVal / 100.0f); // Need to convert to float before division; otherwise C# returns int which is 0 for anything but 100%.
            Brush backColorBrush = new SolidBrush(cellStyle.BackColor);
            Brush foreColorBrush = new SolidBrush(cellStyle.ForeColor);

            // Draws the cell grid
            base.Paint(g, clipBounds, cellBounds,
             rowIndex, cellState, value, formattedValue, errorText,
             cellStyle, advancedBorderStyle, (paintParts & ~DataGridViewPaintParts.ContentForeground));

            if (percentage > 0.0)
            {
                // Draw the progress bar and the text
                g.FillRectangle(new SolidBrush(Color.FromArgb(163, 189, 242)), cellBounds.X + 2, cellBounds.Y + 2, Convert.ToInt32((percentage * cellBounds.Width - 4)), cellBounds.Height - 4);
                g.DrawString(progressVal.ToString() + "%", cellStyle.Font, foreColorBrush, cellBounds.X + 6, cellBounds.Y + 2);
            }
            else
            {
                // draw the text
                if (this.DataGridView.CurrentRow.Index == rowIndex)
                    g.DrawString(progressVal.ToString() + "%", cellStyle.Font, new SolidBrush(cellStyle.SelectionForeColor), cellBounds.X + 6, cellBounds.Y + 2);
                else
                    g.DrawString(progressVal.ToString() + "%", cellStyle.Font, foreColorBrush, cellBounds.X + 6, cellBounds.Y + 2);
            }
        }
    }
}

 

-mark
DataGridView Program Manager
Microsoft
This post is provided "as-is"

Mark Rideout  Wednesday, December 21, 2005 9:39 PM

Thanks.... THAT IS SWEET!

Here is my dilemma, to make this happen in all grids in my app I would I have to create a descendant DatGridView and put the code in it, correct?

If this is not correct please tell me how else I could accomplish this.

 

Stephen Hauck  Wednesday, December 21, 2005 9:57 PM

Nope - just add the classes to your application. Compile once and then you can goto the Edit columns dialog and add a progress bar column. If you are databound, then you can just change the column type of an integer column that has 0 through 100 values.

 

-mark

DataGridView Program Manager

Microsoft

This post is provided “as-is�/SPAN>

 

Mark Rideout  Wednesday, December 21, 2005 10:10 PM

OK, I made the class and added it and all worked well.

Here is my question, why can't we just embed the progressbar control like we can the button or checkbox ?

Thanks

 

Stephen Hauck  Wednesday, December 21, 2005 10:50 PM

Check out the FAQ. The DataGridView does not support embedding controls in the cells. The grid only draws the cells to look like controls. Only when a cell is in edit mode does it actually host a control.

 

-mark

DataGridView Program Manager

Microsoft

This post is provided “as-is�/SPAN>

 

 

Mark Rideout  Wednesday, December 21, 2005 10:54 PM

OK, thanks for the info.

 

I have printed FAQ but have not had time to read the whole thing.

 

Thanks agaion for your help.

Stephen Hauck  Thursday, December 22, 2005 12:10 PM
Hi.

I found this code extremely useful, except I converted it to managed C++/CLR for a project I'm working on. It compiles and runs, but I get a runtime error and am unsure of what is causing it. Here is the error I get. I tried to display the screenshot inline but apparently it won't let me, so here's the link:

DataGridView Default Error Dialog

Here is the converted code. I used the C# version as a basis for the managed C++/CLR version. Keep in mind I don't really know C#, so I may have made a "rookie mistake" in translating it to C++/CLR. Can anyone please point me in the right direction to getting this to work? Thanks.


#pragma once

//---------------------------------------------------------------------
//THIS CODE AND INFORMATION ARE PROVIDED AS IS WITHOUT WARRANTY OF ANY
//KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
//IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
//PARTICULAR PURPOSE.
//---------------------------------------------------------------------
using namespace System;
using namespace System::Collections::Generic;
using namespace System::Text;
using namespace System::Windows::Forms;
using namespace System::Drawing;
using namespace System::ComponentModel;

ref class DataGridViewProgressCell : public DataGridViewImageCell
{
public:
// Used to make custom cell consistent with a DataGridViewImageCell
static Image^ emptyImage;
static DataGridViewProgressCell()
{
emptyImage = gcnew Bitmap(1, 1, System::Drawing::Imaging::PixelFormat::Format32bppArgb);
}
DataGridViewProgressCell()
{
this->ValueType = Int32::typeid;
}
// Method required to make the Progress Cell consistent with the default Image Cell.
// The default Image Cell assumes an Image as a value, although the value of the Progress Cell is an int.
protected: virtual Object^ GetFormattedValue(Object^ value,
int rowIndex, DataGridViewCellStyle^ cellStyle,
TypeConverter^ valueTypeConverter,
TypeConverter^ formattedValueTypeConverter,
DataGridViewDataErrorContexts^ context) override
{
return emptyImage;
}

protected: virtual void Paint(System::Drawing::Graphics^ g, System::Drawing::Rectangle clipBounds, System::Drawing::Rectangle cellBounds, int rowIndex, DataGridViewElementStates cellState, Object^ value, Object^ formattedValue, String^ errorText, DataGridViewCellStyle^ cellStyle, DataGridViewAdvancedBorderStyle^ advancedBorderStyle, DataGridViewPaintParts paintParts) override
{
int progressVal = (int)value;
float percentage = ((float)progressVal * 0.01f);
Brush^ backColorBrush = gcnew SolidBrush(cellStyle->BackColor);
Brush^ foreColorBrush = gcnew SolidBrush(cellStyle->ForeColor);

// Draws the cell grid
DataGridViewImageCell::Paint(g, clipBounds, cellBounds, rowIndex, cellState, value, formattedValue, errorText, cellStyle, advancedBorderStyle, (paintParts & ~DataGridViewPaintParts::ContentForeground));
if (percentage > 0.0) {
// Draw the progress bar and the text
g->FillRectangle(gcnew SolidBrush(Color::FromArgb(163, 189, 242)), cellBounds.X + 2, cellBounds.Y + 2, Convert::ToInt32((percentage * cellBounds.Width - 4)), cellBounds.Height - 4);
g->DrawString(progressVal + "%", cellStyle->Font, foreColorBrush, cellBounds.X + 6, cellBounds.Y + 2);
} else {
// draw the text
if (this->DataGridView->CurrentRow->Index == rowIndex) {
g->DrawString(progressVal + "%", cellStyle->Font, gcnew SolidBrush(cellStyle->SelectionForeColor), cellBounds.X + 6, cellBounds.Y + 2);
} else {
g->DrawString(progressVal + "%", cellStyle->Font, foreColorBrush, cellBounds.X + 6, cellBounds.Y + 2);
}
}
}
};

public ref class DataGridViewProgressColumn : public DataGridViewImageColumn
{
public:
DataGridViewProgressColumn()
{
CellTemplate = gcnew DataGridViewProgressCell();
}
};

aaronexodus  Wednesday, February 01, 2006 11:09 PM

Mark,

This is a fantastic solution that I have spent the last couple of days searching for.  Very nice work.  Thank you for your contribution.

I have a question about using this in my application.  For a single sourced datagrid, this works like a champ, very simple too.  My application, however uses a datagrid in which the user selects multiple sources of data for.  I would like to know how I can, based on the text of a label on the form, apply a datagridview progress bar to a column for only this source. 

Can you explain how I might be able to do that?   The other selected sources for data should not have a progressbar column.

your help would be appreciated.

Chris

CMBrown  Friday, February 17, 2006 12:03 AM

Not sure I understand -- you just add a progress bar column and set the DataPropertyName when your DataGridView is showing content that you want. There is no support for auto changing a column's type, but you just remove and add a different DataGridView column type based upon what datasource you are showing. When the text of your label on the form identifies the datasource that should use the progress bar column you should just add it to the grid (and possibly remove any other columns). Does that make sense?

-mark
DataGridView Program Manager
Microsoft
This post is provided "as-is"

Mark Rideout  Friday, February 17, 2006 12:11 AM
Hi Mark,

I know that source code is provided "as-is", but do you have any input for me on the C++/CLR version I translated? If you could just point me in the right direction I would be gratefull. Thanks!
aaronexodus  Friday, February 17, 2006 3:29 PM

I'll ask someone on the C# team if someone can convert the source. It might take a bit.

-mark
DataGridView Program Manager
Microsoft
This post is provided "as-is"

Mark Rideout  Saturday, February 18, 2006 1:54 AM
Thanks! I really appreciate it. The code I posted above compiles and is pretty much a direct conversion of the C# code, but I get that error, so I must have done something wrong or am missing something required in the C++ version. Feel free to give them a head start by posting my code if you like. Thanks again!
aaronexodus  Saturday, February 18, 2006 6:38 AM

Hello,

I got the same error because of the Paint method. At the design time, the value being pass in is null or whatever. What you can do is to make a quick check if the value is null or empty, then assign it = 1. It will solve the problem at the design time.

have fun

Phong Nguyen  Tuesday, March 28, 2006 9:45 PM
Please tell me how to do that check and whta value should I change for solving the design time problem.
ssandu  Friday, May 19, 2006 5:31 AM

I've modified the Paint method from the original sample code to paint an actual ProgressBar.  It looks pretty nice.  Modify the value of the margin variable to get the look you want. 

protected override void Paint(System.Drawing.Graphics g, System.Drawing.Rectangle clipBounds, System.Drawing.Rectangle cellBounds, int rowIndex, DataGridViewElementStates cellState, object value, object formattedValue, string errorText, DataGridViewCellStyle cellStyle, DataGridViewAdvancedBorderStyle advancedBorderStyle, DataGridViewPaintParts paintParts)

{

int progressVal = (int)value;

float percentage = ((float)progressVal / 100.0f); // Need to convert to float before division; otherwise C# returns int which is 0 for anything but 100%.

Brush backColorBrush = new SolidBrush(cellStyle.BackColor);

Brush foreColorBrush = new SolidBrush(cellStyle.ForeColor);

// Draws the cell grid

base.Paint(g, clipBounds, cellBounds,rowIndex, cellState, value, formattedValue, errorText,cellStyle, advancedBorderStyle, (paintParts & ~DataGridViewPaintParts.ContentForeground));

const int margin = 4;

ProgressBar pb = new ProgressBar();

pb.Height = cellBounds.Bottom - cellBounds.Top - (margin * 2);

pb.Width = cellBounds.Right - cellBounds.Left - (margin * 2);

pb.Value = progressVal;

Bitmap bmp = new Bitmap(pb.Width, pb.Height);

pb.DrawToBitmap(bmp, pb.ClientRectangle);

g.DrawImage(bmp, new Point(cellBounds.X + margin, cellBounds.Y + margin));

}

Joel Harris  Friday, June 02, 2006 7:02 PM
How do you "change the column type of an integer column" in the databound case? I'm just setting the DataSource property of a datagridview and it's automatically figuring out what type of columns to use. How do I make it use my new column type in certain situations? Is there a method I can override on datagridview?
jeffand  Thursday, July 13, 2006 6:37 PM
Im having the same error, any workarounds or fixes ? Im using .net 2.0
Abdullah.Ahmed  Wednesday, July 26, 2006 5:16 AM

Here's how you fix that error. In the Virtual void Paint method....Replace

int progressVal = (int)value;

with

int progressVal;
if(value!=null
)
progressVal = (int
)value;
else

progressVal = 1;
 

Hope that helps...

Abdullah.Ahmed  Wednesday, July 26, 2006 7:33 AM

Here's how you fix that error. In the Virtual void Paint method....Replace

int progressVal = (int)value;

with

int progressVal;
if(value!=null
)
progressVal = (int
)value;
else

progressVal = 1;

Hope that helps...

Abdullah.Ahmed  Wednesday, July 26, 2006 7:36 AM

Many thanks, Mark.

Some obvious, little changes are required to make it designer friendly but this code allowed me to quickly get what I just needed.

Tomasz

Tom Jastrzebski  Monday, September 25, 2006 5:27 AM
The prototytpe for GetFormatedValue is
Object^ DataGridViewProgressCell::GetFormattedValue(Object^ value,
int rowIndex, DataGridViewCellStyle ^%cellStyle,
TypeConverter^ valueTypeConverter,
TypeConverter^ formattedValueTypeConverter,
DataGridViewDataErrorContexts context)


The Assar  Wednesday, October 04, 2006 1:59 PM
Hi group.

Quick question...

Is there any reason something like this would not be appropriate?

There is no mucking around with owner drawn stuff, and you get all the benefits of the regular progressbar control. Or am i missing something?

Public Class DataGridViewProgressBarColumn

Inherits DataGridViewImageColumn

Public Sub New()

Me.CellTemplate = New DataGridViewProgressBarCell

End Sub

End Class

Public Class DataGridViewProgressBarCell

Inherits DataGridViewImageCell

Public Sub New()

Me.ValueType = GetType(Integer)

End Sub

Protected Overrides Function GetFormattedValue( _
ByVal value As Object, _
ByVal rowIndex As Integer, _
ByRef cellStyle As DataGridViewCellStyle, _
ByVal valueTypeConverter As TypeConverter, _
ByVal formattedValueTypeConverter As TypeConverter, _
ByVal context As DataGridViewDataErrorContexts _
) As Object


Dim bm As New Bitmap(OwningColumn.Width, OwningRow.Height)

Using g As Graphics = Graphics.FromImage(bm)

Using pb As New ProgressBar
pb.Height = bm.Height
pb.Width = bm.Width
pb.Value = CInt(value)
pb.DrawToBitmap(bm, New Rectangle(0, 0, bm.Width, bm.Height))
End Using

End Using

Return bm

End Function

End Class

blake1  Thursday, December 07, 2006 2:47 AM
Thanks alott!
I've implemented this in C++ and it works just fine.
But then came Vista!
Seems like the Paint-method is not called when run in Vista.

Do anyone have a solution to this?

// Assar

Edit:
Found out that Paint-method is called.
However when calling DrawToBitmap it won't draw the the blocks representing the value.

Do anyone have a solution to this behaviour?
The Assar  Thursday, December 21, 2006 2:02 PM
Liked your solution!
Won't work in Vista though, and neither did the previous solution.
ProgressBar in Vista is smoth on startup and will not show green bar att all with this solution.

To solve the problem I've put the instance of progressbar in class.
And: I want the actual value to display too.
Use it and obuse it at your own will.
Here is my (C++) solution, although not perfect.


DataGridViewProgressBar.h

#pragma once

using namespace System;
using namespace System::Collections::Generic;
using namespace System::Text;
using namespace System::Windows::Forms;
using namespace System::Drawing;
using namespace System::ComponentModel;

namespace Components {
public ref class DataGridViewProgressCell : DataGridViewImageCell
{
private:
ProgressBar^ mProgressBar;

public:
DataGridViewProgressCell();

protected:
virtual Object^ DataGridViewProgressCell::GetFormattedValue(Object^ value,
int rowIndex, DataGridViewCellStyle ^%cellStyle,
TypeConverter^ valueTypeConverter,
TypeConverter^ formattedValueTypeConverter,
DataGridViewDataErrorContexts context) override;

};

public ref class DataGridViewProgressColumn : DataGridViewImageColumn
{
public:
DataGridViewProgressColumn();
};
}


DataGridViewProgressBar.cpp

#include "StdAfx.h"
#include "DataGridViewProgressBar.h"

using namespace System;
using namespace System::Collections::Generic;
using namespace System::Text;
using namespace System::Windows::Forms;
using namespace System::Drawing;
using namespace System::ComponentModel;

using namespace Components;

DataGridViewProgressCell::DataGridViewProgressCell()
{
this->ValueType = int::typeid;
this->mProgressBar = gcnew ProgressBar();
}

Object^ DataGridViewProgressCell::GetFormattedValue(Object^ value,
int rowIndex, DataGridViewCellStyle ^%cellStyle,
TypeConverter^ valueTypeConverter,
TypeConverter^ formattedValueTypeConverter,
DataGridViewDataErrorContexts context)
{
Bitmap^ bmp = gcnew Bitmap(OwningColumn->Width -1, OwningRow->Height -1);
Bitmap^ bmptxt = gcnew Bitmap(OwningColumn->Width -1, OwningRow->Height -1);
Label^ lbl = gcnew Label();

mProgressBar->Height = bmp->Height -4;
mProgressBar->Width = bmp->Width -4;
mProgressBar->BackColor = cellStyle->BackColor;
mProgressBar->Style = ProgressBarStyle::Blocks;
mProgressBar->Value = (int) value;
mProgressBar->Update();
mProgressBar->DrawToBitmap(bmp, System::Drawing::Rectangle(2, 2, bmp->Width -4, bmp->Height -4));

lbl->AutoSize = false;
lbl->TextAlign = ContentAlignment::MiddleCenter;
lbl->Height = bmptxt->Height -4;
lbl->Width = bmptxt->Width -4;
lbl->Image = bmp;
lbl->BackColor = cellStyle->BackColor;
lbl->Text = String::Format( "{0}%", (int) value);
lbl->DrawToBitmap(bmptxt, System::Drawing::Rectangle(2, 2, bmp->Width -4, bmp->Height -4));

return bmptxt;
}

DataGridViewProgressColumn::DataGridViewProgressColumn()
{
CellTemplate = gcnew DataGridViewProgressCell();
}


The Assar  Friday, December 22, 2006 12:36 PM
Hi Mark,

Thanks for this posting the code. I would like to ask a few questions for update purposes:
  1. Does the aforementioned code exist in any other location such a codeplex?
  2. Are there any updates since the initial post to be aware of?
  3. Does the next version of DataGridView support newer controls in the columns that .Net 2 version currently does not?
advTHANKSance
OmegaMan  Thursday, December 28, 2006 6:24 PM

Hi, I used the code of custom DataGridViewProgressColumn. Its good in runtime but unfortunately it is giving exception in Design mode. i.e whenever I am going to open the form containing the DataGridView, there is a messagebox of Exception : Object Reference not set shown. But its working in runtime.

So please, anyone give me the suggestion how can I solve this.

Thanks,

Nabil Ahmed

Nabil Ahmed  Monday, March 12, 2007 11:15 AM

I use ProgressBarRenderer class to draw the progressbar out on the datagridviewcell, and it worked great on both Vista and other platforms that supports .net 2.0or 3.0 and visual styles are enabled.

For the platforms visual styles are not supported, I still have to fall back to the bitmap way.

Jun Wang  Tuesday, June 26, 2007 8:48 PM

This is awesome, but how can I change the column type of a datagridview when I am creating the dataset dynamically?

szSql = szSql & "Select Column1, Column2, [Column1] * [Column2] / 100 As Colum3 From Broker_Data"

dsBkr = New DataSet

dvBkr = New DataView

Dim adBkr As New SqlDataAdapter(szSql, conSLX)

adBkr.Fill(dsBkr, "Broker_Data")

dvBkr.Table = dsBkr.Tables("Broker_Data")

dgvBrokers.DataSource = dvBkr

dgvBrokers.Columns("Column1").DefaultCellStyle.Format = "c"

dgvBrokers.Columns("Column2").DefaultCellStyle.Format = "c"

' So far so good

' Now how to set column3 to progress bar type

dgvBrokers.Columns("Column3).Type = DataGridViewProgressColumn

' Above line does not work

dgvBrokers.Refresh()

??????

Lloy Sanders  Tuesday, September 25, 2007 5:50 PM
Hi Mark,

I am trying to get the code you provided for creating a Progress Bar column in a DataGridView working in a simple sample WinForm C# project.

I am working in Studio 2005 .Net 2.0 and that may be the reason the code is throwing an exception in Design Time.

Can you take a look or forward this to someone who might know?

Did the following:
1. Create new WinForm C# project
2. Created a new class and copied the code you provided into that class.
3. Changed the name space in your code to my project's name space...
4. Added a DataGridView to the WinForm
5. Added a Text column no problem.
6. Tried to add the new DataGridViewProgressColumn type to the grid and that causes the following exception:
(Which I have to type by hand because the exception text is in a MessageBox show statement it appears)

The control System.Windows.Forms.DataGridView has thrown an unhandled exception in the designer and has been disabled.

Exception:
Object reference not set to an instance of an object.

Stack trace:
at System.Windows.Forms.DataGridViewCell.PaintWord(Graphics graphics, Rectangle clipBounds, Re3ctangle cellBounds, Int32 rowIndex, DataGridViewElementStates cellState, DataGridViewCellStyle cellStyle, DataGridViewAdvancedBorderStyle advancedBorderStyle, DataGridViewPaintParts paintParts) in C:\Documents and Settings\Clint Carter\My Documents\Visual Studio 2005\ProgressBarInDataGridView\ProgressBarCell.cs: line 54

at System.Windows.Forms.DataGridViewRow.PaintCells(Graphics graphics, Rectangle clipBounds, Rectangle rowBounds, Int32 rowIndex, DataGridViewElementStates rowState, Boolean isFirstDisplayedRow, Boolean isLastVisibleRow, DataGridViewPaintParts paintParts)

at System.Windows.Forms.DataGridViewRow.Paint(Graphics graphics, Rectangle clipBounds, Rectangle rowBounds, Int32 rowIndex, DataGridViewElementStates rowState, Boolean isFirstDisplayedRow, Boolean isLastVisibleRow, DataGridViewPaintParts paintParts)

at System.Windows.Forms.DataGridView.PaintRows(.....)
at System.Windows.Forms.DataGridView.PaintGrid(....)

etc...

That file is where I placed the code for the new cell/column type...

Here are the lines of code around that:


protected override void Paint(System.Drawing.Graphics g, System.Drawing.Rectangle clipBounds,
System.Drawing.Rectangle cellBounds, int rowIndex, DataGridViewElementStates cellState,
object value, object formattedValue, string errorText, DataGridViewCellStyle cellStyle,
DataGridViewAdvancedBorderStyle advancedBorderStyle, DataGridViewPaintParts paintParts)
{
Line 54: int progressVal = (int)value;
float percentage = ((float)progressVal / 100.0f); // Need to convert to float before division; otherwise C# returns int which is 0 for anything but 100%.
.....


So I thought perhaps "value" is null.
I put a check around "value" before trying to assign it but I still get the same exception.

Any ideas?

Thanks,


Clint Carter

Clint Carter  Friday, January 25, 2008 5:25 PM
I figured it out...I was close but my problem is that I didn't do a rebuild before trying...

Basically, the Paint event I need to test "value" for null before trying to assign...

And also down lower I needed to test "CurrentRow" before trying to access a method from it...

Here is the modified code...not fully tested...with no guarantee's that it even works...but it at least compiles for now...


//---------------------------------------------------------------------
//THIS CODE AND INFORMATION ARE PROVIDED AS IS WITHOUT WARRANTY OF ANY
//KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
//IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
//PARTICULAR PURPOSE.
//---------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Drawing;
using System.ComponentModel;


namespace ProgressBarInDataGridView
{
public class DataGridViewProgressColumn : DataGridViewImageColumn
{
public DataGridViewProgressColumn()
{
CellTemplate = new DataGridViewProgressCell();
}
}
}

namespace ProgressBarInDataGridView
{
class DataGridViewProgressCell : DataGridViewImageCell
{
// Used to make custom cell consistent with a DataGridViewImageCell
static Image emptyImage;
static DataGridViewProgressCell()
{
emptyImage = new Bitmap(1, 1, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
}
public DataGridViewProgressCell()
{
this.ValueType = typeof(int);
}
// Method required to make the Progress Cell consistent with the default Image Cell.
// The default Image Cell assumes an Image as a value, although the value of the Progress Cell is an int.
protected override object GetFormattedValue(object value,
int rowIndex, ref DataGridViewCellStyle cellStyle,
TypeConverter valueTypeConverter,
TypeConverter formattedValueTypeConverter,
DataGridViewDataErrorContexts context)
{
return emptyImage;
}

protected override void Paint(System.Drawing.Graphics g, System.Drawing.Rectangle clipBounds, System.Drawing.Rectangle cellBounds, int rowIndex, DataGridViewElementStates cellState, object value, object formattedValue, string errorText, DataGridViewCellStyle cellStyle, DataGridViewAdvancedBorderStyle advancedBorderStyle, DataGridViewPaintParts paintParts)
{
//=============================================================
// WAS THROWING EXCPETION HERE AT DESIGN TIME IN STUDIO 2005
// ----> int progressVal = (int)value;
// HERE IS THE CHANGE
//=============================================================
int progressVal = 0;

if ( value != null )
progressVal = (int)value;

//===== END CHANGE ============================================

float percentage = ((float)progressVal / 100.0f); // Need to convert to float before division; otherwise C# returns int which is 0 for anything but 100%.
Brush backColorBrush = new SolidBrush(cellStyle.BackColor);
Brush foreColorBrush = new SolidBrush(cellStyle.ForeColor);
// Draws the cell grid
base.Paint(g, clipBounds, cellBounds,
rowIndex, cellState, value, formattedValue, errorText,
cellStyle, advancedBorderStyle, (paintParts & ~DataGridViewPaintParts.ContentForeground));
if (percentage > 0.0)
{
// Draw the progress bar and the text
g.FillRectangle(new SolidBrush(Color.FromArgb(163, 189, 242)), cellBounds.X + 2, cellBounds.Y + 2, Convert.ToInt32((percentage * cellBounds.Width - 4)), cellBounds.Height - 4);
g.DrawString(progressVal.ToString() + "%", cellStyle.Font, foreColorBrush, cellBounds.X + 6, cellBounds.Y + 2);
}
else
{
// draw the text
if (this.DataGridView.CurrentRow != null)
{
//=============================================================
// WAS THROWING EXCPETION HERE AT DESIGN TIME IN STUDIO 2005...
// SO I ADDED THE "if" CurrenRow != null above
//=============================================================
if (this.DataGridView.CurrentRow.Index == rowIndex)
g.DrawString(progressVal.ToString() + "%", cellStyle.Font, new SolidBrush(cellStyle.SelectionForeColor), cellBounds.X + 6, cellBounds.Y + 2);
else
g.DrawString(progressVal.ToString() + "%", cellStyle.Font, foreColorBrush, cellBounds.X + 6, cellBounds.Y + 2);
}
}
}
}
}
Clint Carter  Friday, January 25, 2008 5:36 PM

just before your RED LINE 54, insert this code piece:

if ( object ==null || object.GetType() == typeof(DBNull )

return;

Bluehunter  Tuesday, April 01, 2008 9:22 AM

Here is an example of Creating a Custom Percentage Column inDataGridView Control

DataGridView Custom Percentage Column

Regards,

Arsalan Tamiz

http://arsalantamiz.blogspot.com

Arsalan Tamiz  Wednesday, April 23, 2008 10:40 AM

Hi Mark,
I was working with datagridview control, with 4 databound columns, I want to add a checkboxcolumn. Which i'll use to pick the checked values from one datagridview into another. I figured that i need to copy those values 1st to a new table then bind that table to my control.

I cant actually get about the proper code to do this. Can you help me out.

Thanks!

Best Regards
Chetan Sehgal

Chetansehgal  Thursday, April 24, 2008 8:31 AM

Hi,

Here i just confuing with this code. I have tried this but i am not getting. Actually my query is try to add progress bar controls in grid view control. Before this i want to explain one thing that is i have generated Tab controls dynamically and in this tab controls i am generating Grid view controls. In this grid view i am displaying the Id row, Url row and "Status" row. Ihave used data table and binded to the grid. But in row "Status", i want to add "Progress bar" control dynamically. Here i have written some code to work this functionality.

try

{

//To bind list view items to Tabcontrol start

//TabControl tc = new TabControl();

for (int i = 0; i < lbProjname.Items.Count; i++)

{

string item = lbProjname.ItemsIdea.ToString();

if (!String.IsNullOrEmpty(item))

{

TabPage tabPage = new TabPage(item);

DataGridView dgv = new DataGridView();

//dgv.Columns.Add("Status");

dgv.Size = new Size(600, 200);

tbcProgressbar.TabPages.Add(tabPage);

DataTable dt = new DataTable("tbl");

DataColumn column = new DataColumn();

DataColumn column1 = new DataColumn();

DataColumn column2 = new DataColumn();

DataColumn column3 = new DataColumn();

DataRow row, row1, row2;

// Create new DataColumn, set DataType, ColumnName

//and add to DataTable.

//column = new DataColumn();

column.DataType = System.Type.GetType("System.Int32");

column.ColumnName = "ID";

column1.DataType = System.Type.GetType("System.String");

column1.ColumnName = "URL";

column2.DataType = System.Type.GetType("System.String");

column2.ColumnName = "Status";

//Add the Column to the DataColumnCollection.

dt.Columns.Add(column);

dt.Columns.Add(column1);

dt.Columns.Add(column2);

ImageSettings objImageSettings = new ImageSettings();

objImageSettings = ImageSettings.Restore(Application.StartupPath +"\\Projects\\"+ item + ".xml");

//int k;

//string filename = "C:\\Sites.txt";

//StreamReader sr19 = new StreamReader(filename);

//string file_names19 = sr19.ReadToEnd();

//file_names19 = file_names19.Replace("\r\n", "\r");

//string[] filenames19 = file_names19.Split('\r');

ProgressBar pbr = new ProgressBar();

for (int u = 0; u < objImageSettings.Sites.Count; u++)

{

row = dt.NewRow();

row["ID"] = u + 1;

row["URL"] = Convert.ToString(objImageSettings.SitesBroken Heart);

row["Status"] = "";

//row["Status"] = dgv.Controls.Add(pbr);

dt.Rows.Add(row);

}

//To get the files from Image settings

DataSet ds = new DataSet();

ds.Tables.Add(dt);

dgv.DataSource = ds.Tables[0];

tabPage.Controls.Add(dgv);

//dgv.Controls.Add(pbr);

//dgv.Rows.Add(pbr);

//dgv.CellFormatting +=new DataGridViewCellFormattingEventHandler(dgv_CellFormatting);

}

}

}

catch (Exception exc2)

{

MessageBox.Show("Projects are not there to generate the Thumbnails");

}

In above how can i add Progress bar controls, Please Find solution to my query, its most urjent. I am waiting for your reply.

Thanks,

Sahasra.

Sahasra  Monday, May 05, 2008 9:40 AM

plz can u plz give me the code for 'SEARCH & PRINT" option for Visual Studio Web Developer 2005!

plz i really need it urgently!

thnx in advance!

Rushaa

Rushaa  Wednesday, May 14, 2008 5:26 PM

Hi Mark,

I am trying toset the value of the progress bar using a databound integer column(as suggested by u)whose value I amchanging in a loop as and when a file is getting downloaded.

But I am able to see only two values, 0 and 100being set in the progress bar.The reason for this is that thepaint event is not getting fired for the intermediate values set in the loop.

Also, while debugging I am able to see the intermediate values being set as intented.

Could you pls help me in finding a solution for the above problem?

I am attaching the code for ur reference.

Thanks in advance.

FileInfo uploadedFile = new FileInfo(uploadedFullPath);

if (uploadedFile.Exists)

{

Byte[] buffer = new Byte[5000];

FileStream ipStream = new FileStream(uploadedFullPath, FileMode.Open, FileAccess.Read, FileShare.Read);

long dataToRead = ipStream.Length;

while (dataToRead > 0)

{

ipStream.Read(buffer, 0, 5000);

string downloadFullPath = downloadPath + "\\" + drCheckedRow["File Name"].ToString();

FileStream opStream = new FileStream(downloadFullPath, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite);

opStream.Write(buffer, 0, 5000);

opStream.Flush();

opStream.Close();

if (dataToRead > 0)

{

drCheckedRow["Status Value"] = ((float)(ipStream.Length - dataToRead) / ipStream.Length) * 100.0f; //Setting the value of progress bar.

drCheckedRow.AcceptChanges();

}

buffer = new Byte[5000];

dataToRead = dataToRead - 5000;

}

drCheckedRow["Status Value"] = 100.0f;

drCheckedRow.AcceptChanges();

ipStream.Close();

}

Shalini N  Wednesday, December 10, 2008 9:26 AM
While Joel's code works really well on XP, it does not work with Vista. The progress bar is just grey with no progress indicator.
I modified his code in a way that it would work under Vista. Cheers

protected override void Paint(System.Drawing.Graphics g, System.Drawing.Rectangle clipBounds, System.Drawing.Rectangle cellBounds, int rowIndex, DataGridViewElementStates cellState, object value, object formattedValue, string errorText, DataGridViewCellStyle cellStyle, DataGridViewAdvancedBorderStyle advancedBorderStyle, DataGridViewPaintParts paintParts)

{

int progressVal;

if (value != null)

progressVal = (int)value;

else

progressVal = 0;

// Draws the cell grid

base.Paint(g, clipBounds, cellBounds, rowIndex, cellState, value, formattedValue, errorText, cellStyle, advancedBorderStyle, (paintParts & ~DataGridViewPaintParts.ContentForeground));

const int margin = 4;

ProgressBar pb = new ProgressBar();

int lHeight = cellBounds.Bottom - cellBounds.Top - (margin * 3);

int lWidth = ((cellBounds.Right - cellBounds.Left - (margin * 2)) * (progressVal) / 100);

pb.Height = cellBounds.Bottom - cellBounds.Top - (margin * 2);

pb.Width = cellBounds.Right - cellBounds.Left - (margin * 2);

pb.Top = 0;

pb.Left = 0;

if (pb.Width == 0)

pb.Width = 10;

pb.Value = 0;

Bitmap bmp = new Bitmap(pb.Width, pb.Height);

pb.DrawToBitmap(bmp, pb.ClientRectangle);

g.DrawImage(bmp, new Point(cellBounds.X + margin, cellBounds.Y + margin));

Rectangle myRectangle = new Rectangle(cellBounds.X + margin + 1, cellBounds.Y + 1 + (int)(margin * 1.333), lWidth - 1, lHeight);

if (myRectangle.Width == 0)

myRectangle.Width = 1;

LinearGradientBrush myLinearGradientBrush = new LinearGradientBrush(myRectangle, Color.LightGreen, Color.MediumSeaGreen, LinearGradientMode.Vertical);

myLinearGradientBrush.SetBlendTriangularShape((float).5);

g.FillRectangle(myLinearGradientBrush, myRectangle);

}

feszty  Saturday, August 15, 2009 6:09 PM

You can use google to search for other answers

Custom Search

More Threads

• Regarding DataGrid
• Import tab delimted text file into datagrid
• How to Filter Date in BindingSource
• how to add a message to a databound combobox
• Datagridview - Error when trying to make a multiline cell
• How to merge column in DataGridView ?
• Moving Things Up in a list box order - Works Sometimes then stops working
• Streaming data to a DataGridView like in Sql Server Management Studio
• Extending DataGrid
• Problems displaying data in ComboBoxColumn/Cell