Link to home
Start Free TrialLog in
Avatar of Brian
BrianFlag for United States of America

asked on

GridView Customization

Hello Experts,

I would like to add an image called CheckImage.png to a field labeled pldg_complete if the field has a value of 1.

If it has a value of 0 then I would like to display an image called NoCheckImage.png for that row in the GridView Control.

Is this possible and if so how?

Please see my CodeBehind for retrieving the data to the GridView Control.


protected void RetrieveAllPledgeParticipants()
    {
        using (SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["WellnessChoice"].ConnectionString))
        {
            SqlCommand cmd = new SqlCommand();
            cmd.CommandText = "WellnessChoiceAdmin_RetrieveAllPledgeParticipants";
            cmd.CommandType = CommandType.StoredProcedure;
            cmd.Connection = conn;

            DataTable dtPledgeParticipants = new DataTable();
            SqlDataAdapter adp = new SqlDataAdapter();

            try
            {
                conn.Open();

                adp.SelectCommand = cmd;
                adp.Fill(dtPledgeParticipants);

                gv_Pledge.DataSource = dtPledgeParticipants;
                gv_Pledge.DataBind();
            }

            catch (Exception ex)
            {
                ex.Message.ToString();
            }
        }
    }

Open in new window

Avatar of Seven price
Seven price
Flag of United States of America image

In grid view you can try a rowDatabound and for example

  If btn IsNot Nothing Then
                    If String.IsNullOrEmpty(btn.ImageUrl) Then
                        btn.ImageUrl = "image.gif"
else
                        btn.ImageUrl = NoCheckImage.png"
                    End If
                End If
Avatar of Brian

ASKER

Not sure I understand what you mean :( I have all data getting retrieved on Page_Load.
Avatar of Brian

ASKER

I still don't understand how to add the image based on the value for that field. Nor did I understand the link you sent. I already saw that link before posting here.
Ok give me a sec i will try to show you.
sorry i just got real busy but try this link and let me know if this works.

http://forums.asp.net/t/1169201.aspx/1
Avatar of Brian

ASKER

Hi sevensnake77,

No, I don't understand what I need to do or how to set this up. I have searched for help on google for this issue and could not find anything useful or at least that I could understand which is why I'm hear asking for help.
The gridview control has an event called rowdatabound. This is the event you will use to look at each individual row and make a decision about the value of pldg_complete. In this event after you have looked at pldg_complete and made a distinction between 0 or 1 then you have to find the control in that row that needs its image changed.

A more specifically meaningful example cannot be created for you without seeing the code for your gridview. If you post the code for your gridview maybe one of the others will elaborate. If they dont I will (I dont want to steal their points if they are willing to show you).
Avatar of Brian

ASKER

@ddayx10,

Thank you for the offer!! I have attached my GridView Markup.

Thanks in advance!!!
<asp:GridView ID="gv_Pledge" runat="server" AutoGenerateColumns="False" 
                    Width="600px" OnRowDataBound="gv_Pledge_RowDataBound">
                    <Columns>
                        <asp:BoundField DataField="pi_id">
                        <HeaderStyle CssClass="label" HorizontalAlign="Left" />
                        <ItemStyle CssClass="gridviewlabel" />
                        </asp:BoundField>
                        <asp:BoundField DataField="pi_fname" HeaderText="First Name">
                        <HeaderStyle CssClass="label" HorizontalAlign="Left" />
                        <ItemStyle CssClass="gridviewlabel" />
                        </asp:BoundField>
                        <asp:BoundField DataField="pi_lname" HeaderText="Last Name">
                        <HeaderStyle CssClass="label" HorizontalAlign="Left" />
                        <ItemStyle CssClass="gridviewlabel" />
                        </asp:BoundField>
                        <asp:BoundField DataField="pldg_date" DataFormatString="{0:d}" 
                            HeaderText="Date Completed">
                        <HeaderStyle CssClass="label" HorizontalAlign="Left" />
                        <ItemStyle CssClass="gridviewlabel" />
                        </asp:BoundField>
                        <asp:BoundField DataField="pldg_complete" HeaderText="Status">
                        <HeaderStyle CssClass="label" HorizontalAlign="Left" />
                        <ItemStyle CssClass="gridviewlabel" />
                        </asp:BoundField>
                    </Columns>
                    <EmptyDataTemplate>
                        <asp:ImageButton ID="ImageButton1" runat="server" />
                    </EmptyDataTemplate>
                </asp:GridView>

Open in new window

Avatar of Brian

ASKER

@ddayx10,

Please note: I did add the OnRowDataBound="gv_Pledge_RowDataBound" to the GridView Above in the Markup but DO NOT have any code associated to it since I don't know what to do. I initially added it when sevensnake77 told me that I needed it but I did not understand his sample or tutorials he supplied links to. I also searched google for what I need and was unable to find what I'm dealing with.
Ok so note I added a templatefield to your gridview. We cant add an image and modify it to an asp:Boundfield.

In the templatefield I added a label so you could see your pldg_complete value and I added an asp:Image.

In the rowdatabound event I find the image, check the value of pldg_complete and set a src for the image based on this value.

Once you understand how this works you may want to remove your old boundfield for pldg_complete and the label I have put in the templatefield. You may want to change it around completely but this should give you the concept for how to do what you are asking.

Ah what the heck I'll throw in the dog .png's too :)
***ASPX PAGE****
    <asp:GridView ID="gv_Pledge" runat="server" AutoGenerateColumns="False" Width="600px" OnRowDataBound="gv_Pledge_RowDataBound">
        <Columns>
            <asp:BoundField DataField="pi_id">
            <HeaderStyle CssClass="label" HorizontalAlign="Left" />
            <ItemStyle CssClass="gridviewlabel" />
            </asp:BoundField>
            <asp:BoundField DataField="pi_fname" HeaderText="First Name">
            <HeaderStyle CssClass="label" HorizontalAlign="Left" />
            <ItemStyle CssClass="gridviewlabel" />
            </asp:BoundField>
            <asp:BoundField DataField="pi_lname" HeaderText="Last Name">
            <HeaderStyle CssClass="label" HorizontalAlign="Left" />
            <ItemStyle CssClass="gridviewlabel" />
            </asp:BoundField>
            <asp:BoundField DataField="pldg_date" DataFormatString="{0:d}" 
                HeaderText="Date Completed">
            <HeaderStyle CssClass="label" HorizontalAlign="Left" />
            <ItemStyle CssClass="gridviewlabel" />
            </asp:BoundField>
            <asp:BoundField DataField="pldg_complete" HeaderText="Status">
            <HeaderStyle CssClass="label" HorizontalAlign="Left" />
            <ItemStyle CssClass="gridviewlabel" />
            </asp:BoundField>
            <asp:TemplateField HeaderText="Status W Image">
				<ItemTemplate>
					<asp:Label ID="LbPldg_Complete" runat="server" Text='<%#Bind("pldg_complete") %>' />
					<asp:Image ID="ImgDynamic" runat="server" ImageUrl="" Height="49px" Width="49px" />
				</ItemTemplate>
            </asp:TemplateField>
        </Columns>
        <EmptyDataTemplate>
            <asp:ImageButton ID="ImageButton1" runat="server" />
        </EmptyDataTemplate>
    </asp:GridView>

Open in new window

****CODE BEHIND ROWDATABOUND EVENT****
    //fires for every row that's been bound in gridview
    protected void gv_Pledge_RowDataBound(Object sender, GridViewRowEventArgs e)
    {
        //check if its a data row (not footer or header for example)
        if (e.Row.RowType == DataControlRowType.DataRow)
        {
            //find image in our itemtemplate
            Image img = (Image)e.Row.FindControl("ImgDynamic");

            //get the column value we want to check against (0 or 1)
            string pldg_complete = (string)DataBinder.Eval(e.Row.DataItem, "pldg_complete");

            //set our img src based on pldg_complete value (0 or 1)
            if (pldg_complete == "0")
            {
                img.ImageUrl = "img/dog.png";
            }
            else
            {
                img.ImageUrl = "img/nodog.png";
            }
        }

    }

Open in new window

dog.png
nodog.png
NOTE:

In this line:
            //get the column value we want to check against (0 or 1)
            string pldg_complete = (string)DataBinder.Eval(e.Row.DataItem, "pldg_complete");


I used a string emulating my datatype as maybe a varchar but your datatype may be an int or something and you will have to adjust as necessary and also in if statement below.
Avatar of Brian

ASKER

@ddayx10,

Ok, I added your code and made a change to the pldg_complete field since its an int type and not a string. When I run my code I only see one returned row and before I added you code I was getting around 200 + returned rows of data. Not sure if this matters but I have all data returned to a DataTable. Also, is there a way to handle which image to display within the RetrieveAllPledgeParticipants() Event Handler Code rather than using the RowDataBound? Please see attached updated code using your method.


protected void Page_Load(object sender, EventArgs e)
    {
        RetrieveAllPledgeParticipants();
    }

    protected void gv_Pledge_RowDataBound(Object sender, GridViewRowEventArgs e)
    {
        //check if its a data row (not footer or header for example)
        if (e.Row.RowType == DataControlRowType.DataRow)
        {
            //find image in our itemtemplate
            Image img = (Image)e.Row.FindControl("ImgDynamic");

            //get the column value we want to check against (0 or 1)
            int pldg_complete = (Int32)DataBinder.Eval(e.Row.DataItem, "pldg_complete");

            //set our img src based on pldg_complete value (0 or 1)
            if (pldg_complete == 1)
            {
                img.ImageUrl = "../images/complete.png";
            }
            else
            {
                img.ImageUrl = "../images/not_complete.png";
            }
        }
    }

    protected void RetrieveAllPledgeParticipants()
    {
        using (SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["WellnessChoice"].ConnectionString))
        {
            SqlCommand cmd = new SqlCommand();
            cmd.CommandText = "WellnessChoiceAdmin_RetrieveAllPledgeParticipants";
            cmd.CommandType = CommandType.StoredProcedure;
            cmd.Connection = conn;

            DataTable dtPledgeParticipants = new DataTable();
            SqlDataAdapter adp = new SqlDataAdapter();

            try
            {
                conn.Open();

                adp.SelectCommand = cmd;
                adp.Fill(dtPledgeParticipants);

                gv_Pledge.DataSource = dtPledgeParticipants;
                gv_Pledge.DataBind();
            }

            catch (Exception ex)
            {
                ex.Message.ToString();
            }
        }
    }

Open in new window

Avatar of Brian

ASKER

@ddayx10,

Ok, so I removed your RowDataBound Even Handler Code and modified the GridView Control to not fire that Event and modified my original code below. When I run the code I see a column for the image and it's displaying a broken Image URL. Any idea why it's not showing the images?


protected void RetrieveAllPledgeParticipants()
    {
        using (SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["WellnessChoice"].ConnectionString))
        {
            SqlCommand cmd = new SqlCommand();
            cmd.CommandText = "WellnessChoiceAdmin_RetrieveAllPledgeParticipants";
            cmd.CommandType = CommandType.StoredProcedure;
            cmd.Connection = conn;

            DataTable dtPledgeParticipants = new DataTable();
            SqlDataAdapter adp = new SqlDataAdapter();

            try
            {
                conn.Open();

                adp.SelectCommand = cmd;
                adp.Fill(dtPledgeParticipants);

                Image img = new Image();

                if (dtPledgeParticipants != null)
                {
                    DataRow data = dtPledgeParticipants.Rows[0];

                    if (data["pldg_complete"] == "1")
                    {
                        img.ImageUrl = "../../images/complete.png";
                    }
                    else
                    {
                        img.ImageUrl = "../../images/complete.png";
                    }                  
                }

                gv_Pledge.DataSource = dtPledgeParticipants;
                gv_Pledge.DataBind();
            }

            catch (Exception ex)
            {
                ex.Message.ToString();
            }
        }
    }

Open in new window

The way you had it the first time is correct (37035839) the second way you posted it is not good at all (37035891).

The code we added for the onrowdatabound will have nothing to do with how many rows display. That is all controlled by your RetrieveAllPledgeParticipants function (which you already know).

You cannot in any way affect the image properly from the RetrieveAllPledgeParticipants function.
Have you debugged and checked if you are having an exception somewhere?

you could try changing ex.Message.ToString(); to be:

Response.Write(ex.Message.ToString());

This way if there is an error you will get some indication.
Using the same code I gave you and a db that was setup to emulate your table schema I get it to work just fine <see image>.

The problem is in your data, or your pulling of the data. BTW programmers debugging mantra #37 = "It worked before therefore it should work now is faulty logic."

The way you are connecting with your grid using an adapter? Well I wouldn't bother I'd do it more like this (see snippet).
protected void RetrieveAllPledgeParticipants()
    {
        using (SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["WellnessChoice"].ConnectionString))
        {
            SqlCommand cmd = new SqlCommand("WellnessChoiceAdmin_RetrieveAllPledgeParticipants",conn);
            cmd.CommandType = CommandType.StoredProcedure;
            try
            {
                conn.Open();
                gv_Pledge.DataSource = cmd.ExecuteReader();
                gv_Pledge.DataBind();
            }

            catch (Exception ex)
            {
                ex.Message.ToString();
            }
        }
    }

Open in new window

crazygrid.jpg
Avatar of Brian

ASKER

Hi ddayx10,

Ok, I change my code back to how it was (37035839) and I also added Response.Write(ex.Message.ToString()); and when I run the code I get the following message from Response.Write. Not sure what that means.

Error Message:
Specified cast is not valid.
Avatar of Brian

ASKER

Hi ddayx10,

I believe you, I just can't figure out why it's not working for me. I also made the change to the code an just used SqlDataReader but I still get the same results.
I know its dumb but have you checked the data to make sure some process didnt delete it.

Go into sql and run the stored proc and make sure its returning all rows. I mean if its just SELECT * FROM tblName then its probably fine, but if there's a where clause for a date range or something??

Did you make some sort of syntax error in the GridView causing it not to render properly?

Ahhhh.... anyway I know its frustrating but dont overlook anything obvious, make no assumptions because its probably something simple.
Ahhh I just saw your note above (37035958). Its telling you that your casting of pldg_complete is not correct. It is not able to cast from whatever type in your database to an Int32 most likely.
Avatar of Brian

ASKER

Hi ddayx10,

Yes, that was the first thing I did :) I executed the SP and it returned all 200 + rows. Also, I fixeed the one error "Specified cast is not valid" but now I have another error :( that says "Object cannot be cast from DBNull to other types." The only thing I can think of is that the pldg_date field WILL contain NULL values for the rows that contain the value 0 for field dg_complete.

The "specified cast is not valid" was on line below. Below is the correction I made.

Before:
int pldg_complete = (int)DataBinder.Eval(e.Row.DataItem, "pldg_complete"));

After:
int pldg_complete = Convert.ToInt32(DataBinder.Eval(e.Row.DataItem, "pldg_complete"));
Avatar of Brian

ASKER

Oh, crap, I just saw that pldg_complete DOES contain some NULL values. So I was wrong then, pldg_complete will either contain NULL or 1 :(
what type is it? bit or varchar or int or bigint or ??
Avatar of Brian

ASKER

pldg_complete is int.
ASKER CERTIFIED SOLUTION
Avatar of Member_2_4913559
Member_2_4913559
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of Brian

ASKER

@ddayx10,

That worked. Thank you. Now what would I need to change if I was dealing with a 0 rather than NULL?
Nothing. It will work with 0, 1 or Null as is.

The variable is initially set to 0

If the db.value is null that variable doesnt change and its what we're using in our if statement later

If db.value is not null it will be assigned to the variable (Int32 pldg_complete) so it will be 0 or 1

This code will work whether you change or not.

Im going to bed :)

Im glad you got it working.
sooo

null = 0
0 = 0
1 = 1

hope that makes sense...now sleep
Avatar of Brian

ASKER

Thank you ddayx10!!! I appreciate all your help. Yes, going to sleep now :)