none
Sample Code: DataGridView progress bar column

    Question

  • 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

    Wednesday, December 21, 2005 6:47 PM

Answers

  • 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"

    Wednesday, December 21, 2005 9:39 PM

All replies

  • 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"

    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.

     

    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”

     

    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

     

    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”

     

     

    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.

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

    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

    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"

     

    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!
    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"

     

    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!
    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

     

    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.
    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));

    }

    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?
    Thursday, July 13, 2006 6:37 PM
  • Im having the same error, any workarounds or fixes ? Im using .net 2.0
    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...

    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...

    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

    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)


    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

    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?
    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();
    }


    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
    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

    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.0 or 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.

    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()

     

    ??????

    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

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

    Tuesday, April 01, 2008 9:22 AM
  • Here is an example of Creating a Custom Percentage Column in DataGridView Control

     

    DataGridView Custom Percentage Column

     

    Regards,

    Arsalan Tamiz

    http://arsalantamiz.blogspot.com

    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

    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. I have 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.

    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

    Wednesday, May 14, 2008 5:26 PM
  • Hi Mark,

     

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

    But I am able to see only two values, 0 and 100 being set in the progress bar.The reason for this is that the paint 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();

    }

     

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

            }

    Saturday, August 15, 2009 6:09 PM
  • I know this post is old, but I am running into an issue trying to use this. I am able to add a column to my datagridview with this class, but how do I assign values to it? Im trying to fun a For Next Loop to Set the bounds (upper and lower) between two dates, and get the difference to set the value, but I dont even know where to begin with this. Normally I blieve you would set a progress bars bounds, and assign a value. Im not seeing these properties with the this column. Any help would be appreciated.
    Wednesday, December 16, 2009 5:01 PM
  • I think the implementation is clear. You should choose a way to display percentage.

    like :
    DateTime BeginDate = DateTime.Now.AddDays(-1); // Place your begin date here
    CurrentDate = DateTime.Now,
    EndDate = DateTime.Now.AddDays(1);  // Place your end date here
    
    TimeSpan tsValue = CurrentDate.Subtract(BeginDate);
    TimeSpan tsMaxValue = EndDate.Subtract(BeginDate);
    
    int Percentage = (int)(100 * (tsValue.TotalMinutes / tsMaxValue.TotalMinutes));
    
    //Then Assign this Percentage to the column



    There is always more to learn...
    Sunday, December 20, 2009 10:53 AM
  • Anyone know whether WPF would make the issue of displaying a progress bar as one of the columns in a grid type display?  (i.e. would WPF be able to do this out-of-the-box, as opposed to with WinForms having to do the manual coding).   Or is it the same amount of effort in WPF?
    Monday, January 04, 2010 8:25 AM
  • here you can find some useful datagridview tips

    http://csharp.net-informations.com/datagridview/csharp-datagridview-tutorial.htm

     

    liam.

     

     

    Monday, August 02, 2010 11:14 AM
  • Great work feszty, however I ran into some problems in Vista (Win32Exception :: cannot create window ) I believe you need to dispose the objects in the Paint method, because when there are a lot of rows using the progress bar the garbage collector is not fast enough:

     

    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;
    	using (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;
    		using (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;
    			using (LinearGradientBrush myLinearGradientBrush = new LinearGradientBrush(myRectangle, Color.LightGreen, Color.MediumSeaGreen, LinearGradientMode.Vertical))
    			{
    				myLinearGradientBrush.SetBlendTriangularShape((float).5);
    				g.FillRectangle(myLinearGradientBrush, myRectangle);
    			}
    		}
    	}
    }
    

    Tuesday, September 21, 2010 4:37 PM
  • I was looking at this and thinking... If you are going to draw the rectangle like that, then why go to the trouble of instantiating the progress bar and the bitmap?  Why not just draw it from scratch.  In fact, I took the example and improved a little.  There are a couple of fund advantages here...

    1. Deriving from DataGridViewTextBoxCell instead of the image one means that you have a cell where the value can be edited by the user.
    2. Used the cellStyle parameter to read the margins that should be used so that the look is customizable simply by editing the style.
    3. This version displays the percentage value on top of the bar and the font and position of that text obey the style settings that are defined for the column / cell.
    4. The default formatting for the value adds the percent sign, but the Format property of the DefaultCellStyle can be used to change the way in which the number is formatted (or can be used to remove it altogether.

    Now for the code...

    //---------------------------------------------------------------------
    //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.ComponentModel;
    using System.Drawing;
    using System.Drawing.Drawing2D;
    using System.Windows.Forms;
    
    namespace CustomProgressControl
    {
      /// <summary>
      /// A DataGridViewColumn implementation that provides a column that
      /// will display a progress bar.
      /// </summary>
      public class DataGridViewProgressBarColumn : DataGridViewTextBoxColumn 
      {
        public DataGridViewProgressBarColumn()
        {
          // Set the cell template
          CellTemplate = new DataGridViewProgressBarCell();
    
          // Set the default style padding
          Padding pad = new Padding(
            DataGridViewProgressBarCell.STANDARD_HORIZONTAL_MARGIN,
            DataGridViewProgressBarCell.STANDARD_VERTICAL_MARGIN,
            DataGridViewProgressBarCell.STANDARD_HORIZONTAL_MARGIN,
            DataGridViewProgressBarCell.STANDARD_VERTICAL_MARGIN);
          DefaultCellStyle.Padding = pad;
    
          // Set the default format
          DefaultCellStyle.Format = "## \\%";
        }
    
        
      }
    
      /// <summary>
      /// A DataGridViewCell class that is used to display a progress bar
      /// within a grid cell.
      /// </summary>
      public class DataGridViewProgressBarCell : DataGridViewTextBoxCell
      {
        /// <summary>
        /// Standard value to use for horizontal margins
        /// </summary>
        internal const int STANDARD_HORIZONTAL_MARGIN = 4;
    
        /// <summary>
        /// Standard value to use for vertical margins
        /// </summary>
        internal const int STANDARD_VERTICAL_MARGIN = 4;
    
        /// <summary>
        /// Constructor sets the expected type to int
        /// </summary>
        public DataGridViewProgressBarCell()
        {
          this.ValueType = typeof(int);
        }
    
        /// <summary>
        /// Paints the content of the cell
        /// </summary>
        protected override void Paint(Graphics g, Rectangle clipBounds, Rectangle cellBounds,
          int rowIndex, DataGridViewElementStates cellState,
          object value, object formattedValue,
          string errorText,
          DataGridViewCellStyle cellStyle,
          DataGridViewAdvancedBorderStyle advancedBorderStyle,
          DataGridViewPaintParts paintParts)
        {
          int leftMargin = STANDARD_HORIZONTAL_MARGIN;
          int rightMargin = STANDARD_HORIZONTAL_MARGIN;
          int topMargin = STANDARD_VERTICAL_MARGIN;
          int bottomMargin = STANDARD_VERTICAL_MARGIN;
          int imgHeight = 1;
          int imgWidth = 1;
          int progressWidth = 1;
          PointF fontPlacement = new PointF(0,0);
    
          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));
    
          // Get margins from the style
          if (null != cellStyle)
          {
            leftMargin = cellStyle.Padding.Left;
            rightMargin = cellStyle.Padding.Right;
            topMargin = cellStyle.Padding.Top;
            bottomMargin = cellStyle.Padding.Bottom;
          }
    
          // Calculate the sizes
          imgHeight = cellBounds.Bottom - cellBounds.Top - (topMargin + bottomMargin);
          imgWidth = cellBounds.Right - cellBounds.Left - (leftMargin + rightMargin);
          if (imgWidth <= 0)
          {
            imgWidth = 1;
          }
          if (imgHeight <= 0)
          {
            imgHeight = 1;
          }
    
          // Calculate the progress
          progressWidth = (imgWidth * (progressVal) / 100);
          if (progressWidth <= 0)
          {
            if (progressVal > 0)
            {
              progressWidth = 1;
            }
            else
            {
              progressWidth = 0;
            }
          }
    
          // Calculate the font
          if (null != formattedValue)
          {
            SizeF availArea = new SizeF(imgWidth, imgHeight);
            SizeF fontSize = g.MeasureString(formattedValue.ToString(), cellStyle.Font, availArea);
    
            #region [Font Placement Calc]
    
            if (null == cellStyle)
            {
              fontPlacement.Y = cellBounds.Y + topMargin + (((float)imgHeight - fontSize.Height) / 2);
              fontPlacement.X = cellBounds.X + leftMargin + (((float)imgWidth - fontSize.Width) / 2);
            }
            else
            {
              // Set the Y vertical position
              switch (cellStyle.Alignment)
              {
                case DataGridViewContentAlignment.BottomCenter:
                case DataGridViewContentAlignment.BottomLeft:
                case DataGridViewContentAlignment.BottomRight:
                  {
                    fontPlacement.Y = cellBounds.Y + topMargin + imgHeight - fontSize.Height;
                    break;
                  }
                case DataGridViewContentAlignment.TopCenter:
                case DataGridViewContentAlignment.TopLeft:
                case DataGridViewContentAlignment.TopRight:
                  {
                    fontPlacement.Y = cellBounds.Y + topMargin - fontSize.Height;
                    break;
                  }
                case DataGridViewContentAlignment.MiddleCenter:
                case DataGridViewContentAlignment.MiddleLeft:
                case DataGridViewContentAlignment.MiddleRight:
                case DataGridViewContentAlignment.NotSet:
                default:
                  {
                    fontPlacement.Y = cellBounds.Y + topMargin + (((float)imgHeight - fontSize.Height) / 2);
                    break;
                  }
              }
              // Set the X horizontal position
              switch (cellStyle.Alignment)
              {
    
                case DataGridViewContentAlignment.BottomLeft:
                case DataGridViewContentAlignment.MiddleLeft:
                case DataGridViewContentAlignment.TopLeft:
                  {
                    fontPlacement.X = cellBounds.X + leftMargin;
                    break;
                  }
                case DataGridViewContentAlignment.BottomRight:
                case DataGridViewContentAlignment.MiddleRight:
                case DataGridViewContentAlignment.TopRight:
                  {
                    fontPlacement.X = cellBounds.X + leftMargin + imgWidth - fontSize.Width;
                    break;
                  }
                case DataGridViewContentAlignment.BottomCenter:
                case DataGridViewContentAlignment.MiddleCenter:
                case DataGridViewContentAlignment.TopCenter:
                case DataGridViewContentAlignment.NotSet:
                default:
                  {
                    fontPlacement.X = cellBounds.X + leftMargin + (((float)imgWidth - fontSize.Width) / 2);
                    break;
                  }
              }
            }
            #endregion [Font Placement Calc]
          }
    
          // Draw the background
          Rectangle backRectangle = new Rectangle(cellBounds.X + leftMargin, cellBounds.Y + topMargin, imgWidth, imgHeight);
          using (SolidBrush backgroundBrush = new SolidBrush(Color.FromKnownColor(KnownColor.LightGray)))
          {
            g.FillRectangle(backgroundBrush, backRectangle);
          }
    
          // Draw the progress bar
          if (progressWidth > 0)
          {
            Rectangle progressRectangle = new Rectangle(cellBounds.X + leftMargin, cellBounds.Y + topMargin, progressWidth, imgHeight);
            using (LinearGradientBrush progressGradientBrush = new LinearGradientBrush(progressRectangle, Color.LightGreen, Color.MediumSeaGreen, LinearGradientMode.Vertical))
            {
              progressGradientBrush.SetBlendTriangularShape((float).5);
              g.FillRectangle(progressGradientBrush, progressRectangle);
            }
          }
    
          // Draw the text
          if (null != formattedValue && null != cellStyle)
          {
            using (SolidBrush fontBrush = new SolidBrush(cellStyle.ForeColor))
            {
              g.DrawString(formattedValue.ToString(), cellStyle.Font, fontBrush, fontPlacement);
            }
          }
        }
      }
    
    }
    My next goal is to make it so the column has a 'progress bar style' on it that will allow you to define the colors for the progress bar and other such properties.  If anyone has suggestions for the easiest / best way to achieve that, feel free to contribute.
    Thursday, March 10, 2011 11:43 PM
  • Not to sound too dumb but how do you progress the bar along? Tried to set the cell value but this just causes an error with the setting of (int)Value stating it must be less than infinite?
    Tuesday, May 10, 2011 11:58 AM
  • You should be able to just set the cell value.  If it didn't work for you, perhaps you can post an actual code sample that demonstrates your problem so that we can look at what your issue might be...?
    Tuesday, May 10, 2011 5:10 PM
  • Aha - me being dumb as I suspected. Kept trying to set the column value instead of the actual row/cell :P.

    My last problem with this is i cannot get it to work in Windows 7 - the green never shows like it does on my main PC using XP. The display is currnelty perfect and Ive even managed to get this added to a transparent datagridview. Ive seen a c++ mention of how to doget this working but not C# and I think I need a code example cause i just cant make it appear...

     

    Tuesday, May 10, 2011 7:31 PM
  • It works on XP, Win 2003 and Win 2008.  Not sure why it would have issues on Win 7 but I'm not in a position to test / play with that right now.  Perhaps someone else with Win 7 experience can offer some insight.

    Tuesday, May 10, 2011 8:02 PM
  • I created a separate class file with the post provided by Volox 4, and I notice a strange thing.

    When I compile and run the solution for the first time since I started VS2010 (both Express and Pro) everything is fine, but beginning from the next stop-modify-restart it won't compile saying the EXE file is in use; I unlocked the exe with Unlocker and it says that the user section is in use.

    I removed the class and its references, and everything's fine again.

    Any ideas?

    Using c# 2010.

     

    Thanks in advance

    Morenz

    Sunday, July 10, 2011 3:37 PM