Images not loading in DataGridView C# - Visual Studio 2022

592 views Asked by At

all.

I know this issue is not new here. I found several similar ones (here, here, here and here) during my research, but I still could not make it work on my "to do list" like program.

Since it is a short term planning task manager, I chose to save the tasks in a XML file and I import all the data from it to the DataGridView. Based on the priority value (0 is low, 1 is normal and 2 is high) I want to show the corresponding picture on the respective cell of a DataGridViewImageColumn for each task.

I have already used breakpoints and watches to check if the logic is wrong, but I could not find any issue with it. It is correctly reading the priority values and choosing the correct option inside the switch statement. I loaded these three images as resources, but they are not being shown in the DataGridViewImageCells.

enter image description here

Column 0 is hidden in the dataGridView. Column 1 (header is "P" in the picture) has the task priority values.

Below follows the code excerpt (XMLReader is a class I wrote to import the data):

    XMLReader tasks = new XMLReader("tasks.xml");
    tasks.Open();
    statusBarLabel.Text = tasks.TaskCount.ToString() + " tasks listed - Priority: " +
        tasks.TaskLowCount.ToString() + " low, " + tasks.TaskNormalCount.ToString() +
        " normal, " + tasks.TaskHighCount.ToString() + " high";

    DataSet dataset = new DataSet();
    dataset.ReadXml("tasks.xml");
    dataGridView.DataSource = dataset.Tables[0];
    dataGridView.Columns[1].HeaderText = "P"; // Priority level
    dataGridView.Columns[2].HeaderText = "Due to"; // Task due date
    dataGridView.Columns[3].HeaderText = "Description"; //Task description
    dataGridView.Columns.Add(new DataGridViewImageColumn());
    for (int i = 0; i <= dataGridView.Rows.Count - 1; i++)
    {
        switch (dataGridView.Rows[i].Cells[1].Value.ToString())
        {
            case "0":
                dataGridView.Rows[i].Cells[4].Value = Properties.Resources.Low_16x;
                break;
            case "1":
                dataGridView.Rows[i].Cells[4].Value = Properties.Resources.Normal_16x;
                break;
            case "2":
                dataGridView.Rows[i].Cells[4].Value = Properties.Resources.High_16x;
                break;
            default:
                dataGridView.Rows[i].Cells[4].Value = null;
                break;
        }
    }

What am I doing wrong?

I appreciate any help.

UPDATE:

As I mentioned in the comments below, I noticed something strange in the Resources folder that I have never seen before. I removed the images from the solution resources, keeping only one of them that is in use in a button. After that I added to the solution resources only one of the three images I want to display in the DataGridViewImageCells and the screenshot below shows the status of evertything after adding the image to it.

enter image description here

In this screenshot you can see that the image exists in the solution resources, but it is not being copied to the solution Resources folder. I also captured the File Explorer opened showing the folder contents to illustrate it better.

I believe this may be the problem that is not allowing me to properly show the images inside the DataGridViewImageColumn cells.

Any clues on how to solve it? It did not happen in a test solution I created to check if it would work (and it worked - you can check it here).

1

There are 1 answers

0
Marcelo C. On

I made it work! I thought about not using the code shared in the question, which loads the XML file content inside a Dataset which, in turn, was used as the DataGridView's data source. Instead of this approach, I tried to programmatically load each of the tasks into the DataGridView.

I made it by using an XMLReader object instantiated based on a class that I had previously created for this solution. This class has a Content property that holds all the data from inside the XML file opened by using its Open method. Here is the XMLReader Open method code:

public bool Open()
{
    try
    {
        this.Content = XElement.Load(this.File);
        this.TaskCount = UpdateTaskCount();
        this.TaskHighCount = PriorityTaskCount(2);
        this.TaskLowCount = PriorityTaskCount(0);
        this.TaskNormalCount = PriorityTaskCount(1);
    }
    catch (FileNotFoundException e)
    {
        MessageBox.Show("File not found: " + e.FileName + "\nSystem message: " + e.Message,
            "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
        return false;
    }
    catch (IOException e)
    {
        MessageBox.Show("Unknown I/O exception.\nError code: " + e.HResult +
            "\nSystem message: " + e.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
        return false;
    }
    return true;
}

Content property sets a content field, which is of XElement type.

With the XML file data loaded on it, I replaced the previous approach by the following one (also changed the DataGridView name):

XMLReader tasks = new XMLReader("tasks.xml");
tasks.Open();
statusBarLabel.Text = tasks.TaskCount.ToString() + " tasks listed - Priority: " +
    tasks.TaskLowCount.ToString() + " low, " + tasks.TaskNormalCount.ToString() +
    " normal, " + tasks.TaskHighCount.ToString() + " high";

dgvTasks.Columns.Add(new DataGridViewImageColumn()); // Col 0 - Priority image
dgvTasks.Columns.Add(new DataGridViewTextBoxColumn()); // Col 1 - Due date
dgvTasks.Columns.Add(new DataGridViewTextBoxColumn()); // Col 2 - Description

dgvTasks.Columns[0].Width = 25;
dgvTasks.Columns[1].Width = 100;

IEnumerable<XElement> allTasks = tasks.Content.Descendants("task");
foreach (var task in allTasks)
{
    dgvTasks.Rows.Add();                
    DataGridViewImageCell prioImg = (DataGridViewImageCell)dgvTasks.Rows[dgvTasks.Rows.Count - 1].Cells[0];
    DataGridViewTextBoxCell date = (DataGridViewTextBoxCell)dgvTasks.Rows[dgvTasks.Rows.Count - 1].Cells[1];
    DataGridViewTextBoxCell description = (DataGridViewTextBoxCell)dgvTasks.Rows[dgvTasks.Rows.Count - 1].Cells[2];
    Int32.TryParse(task.Element("priority").Value, out int priority);
    switch (priority)
    {
        case 0:
            prioImg.Value = Properties.Resources.Low;
            break;
        case 1:
            prioImg.Value = Properties.Resources.Normal;
            break;
        case 2:
            prioImg.Value = Properties.Resources.High;
            break;
        default:
            prioImg.Value = null;
            break;
    }
    date.Value = task.Element("dueDate").Value;
    description.Value = task.Element("description").Value;
}

And here it is:

enter image description here

Once more, thank you so much Karen Payne and JohnG for your support. Your insights made me think in the correct direction, although the solution was not based on the original approach.