Click here to Skip to main content
15,891,033 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
I am attempting to create a program, where in the Windows Forms Form, the user clicks on a button, is able to choose an image from the file explorer, which is displayed in a picture box. With the Console application code, the file path of the image is then used to find the image, turn it into a byte array, and then send it along with necessary API keys to an API. This then returns a response, which I would like to output in the Form in a textbox.

The issue is, is that I am unable to get the two parts of my project to "talk' to each other - I cannot "call" the tasks in the form.cs from the progam.cs, which may be because they are async? I am a beginner to C#, and I am not sure if combining these two elements into one program is even possible.

Here is my forms.cs code:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace customvisionframework
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            string Chosen_File = "";


            openFD.InitialDirectory = "C:";
            openFD.Title = "Submit an Image";
            openFD.FileName = "";
            openFD.Filter = "JPEG Images|*.jpg|GIF Images|*.gif";

            if (openFD.ShowDialog() == DialogResult.Cancel)
            {
                MessageBox.Show("Operation Cancelled");
            }
            else
            {
                Chosen_File = openFD.FileName;
                pictureBox1.Image = Image.FromFile(Chosen_File);
                string imageFilePath = Path.GetDirectoryName(Chosen_File); //ideally i would then call the method/task MakePredictionRequest(string imageFilePath) but it says 'makepredictionrequest' doesn't exist in this context



            }

        }
    }
}


and here is my program.cs code:
using System;
using Newtonsoft.Json;
using System.IO;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;
using System.Text;
using System.Web;
using System.Windows.Forms;
using customvisionframework;

namespace fakeBrokenBones
{
    public static class Program
    {

        public static void Main()
        {
            Application.EnableVisualStyles();

            Application.Run(new Form1());
            
        }
        // MAKING THE PREDICTION REQUEST

        public static async Task MakePredictionRequest(string imageFilePath)
        {
            //create a new HTTP request
            var client = new HttpClient();

            // adding valid Prediction-Key to Header.
            client.DefaultRequestHeaders.Add("Prediction-Key", "prediction key");

            // this is the URL of the Prediction API that the HTTP request will be sent to.
            string url = "api url";

            HttpResponseMessage response;

            // the byte array created from the image submitted is then added to the body of the HTTP request.
            byte[] byteData = GetImageAsByteArray(imageFilePath);


            using (var content = new ByteArrayContent(byteData))
            {
                // sets the Content Type Header of the HTTP request to "application/octet-stream".
                content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");

                // SENDING A REQUEST

                // sends HTTP request to the Prediction URL using the POST request method as an asynchronous operation.
                response = await client.PostAsync(url, content);
                // returns response from Prediction API, which has been serialised, as a string.

                //RETRIEVING A RESPONSE

                var responseString = await response.Content.ReadAsStringAsync();
                // this response is then deserialised so that the desired data can be extracted.
                dynamic stuff = JsonConvert.DeserializeObject<object>(responseString);
                string broken = stuff.predictions[0].probability;
                string negative = stuff.predictions[1].probability;
//ideally then I could use output the string negative and string broken in a rich textbox in my GUI>

            }


        }
        // CONVERTING FILE TO BYTE ARRAY

        private static byte[] GetImageAsByteArray(string imageFilePath)
        {
            // image from specified file path is open and read
            FileStream fileStream = new FileStream(imageFilePath, FileMode.Open, FileAccess.Read);
            // intialises BinaryReader class to convert image to binary
            BinaryReader binaryReader = new BinaryReader(fileStream);
            return binaryReader.ReadBytes((int)fileStream.Length);
        }
    }
}


What I have tried:

I've looked everywhere, but I can't see anything that resembles my problem. I've tried copying all my program.cs code into the forms.cs, but it really doesn't like that either.

At this point, I just want to know if this is actually possible, because I've spent so many hours trying to make it work to no avail. If there is a way to do this, I would be so grateful and appreciative if you could help me.
Posted
Updated 8-Jul-20 0:23am

1 solution

You're not trying to call a console application from a Windows Forms application; you're trying to call a method in one class from another class.

Since the method you're trying to call is static, you just need to put the name of the containing class before it.

Since the method you're trying to call is async, you'll need an async method to call it if you want to use the results. But you should avoid async void methods[^] wherever possible.

Update your MakePredictionRequest method to return the value you want to use:
C#
public static async Task<object> MakePredictionRequest(string imageFilePath)
{
    ...
        string responseString = await response.Content.ReadAsStringAsync();
        return JsonConvert.DeserializeObject<object>(responseString);
    }
}
Then update your form code to call it and use the result:
C#
private void button1_Click(object sender, EventArgs e)
{
    openFD.InitialDirectory = "C:";
    openFD.Title = "Submit an Image";
    openFD.FileName = "";
    openFD.Filter = "JPEG Images|*.jpg|GIF Images|*.gif";

    if (openFD.ShowDialog() == DialogResult.Cancel)
    {
        MessageBox.Show("Operation Cancelled");
        return;
    }
    
    string Chosen_File = openFD.FileName;
    pictureBox1.Image = Image.FromFile(Chosen_File);
    string imageFilePath = Path.GetDirectoryName(Chosen_File);
    
    _ = Predict(Chosen_File);
}

private async Task Predict(string imageFilePath)
{
    dynamic stuff = await Program.MakePredictionRequest(imageFilePath);
    string broken = stuff.predictions[0].probability;
    string negative = stuff.predictions[1].probability;
    ...
}
 
Share this answer
 
Comments
Member 14883937 8-Jul-20 7:26am    
Hi Richard, thank you for replying so quickly. Unfortunately (and this may just be lack of knowledge of C# on my part), a couple of errors have popped up.

What should I put for where you have left a _ : "_ = Predict(Chosen_File)"?
And what should I put in the ...?

Also, it says in the Form.cs that the name 'Program' does not exist in this context, and that in the Program.cs it says that the name 'imageFilePath' does not exist in this context.

Do i also have to add a reference to system.range? and it says that 'range operator' is not available in C#7.3.

Thanks again,
Richard Deeming 8-Jul-20 7:36am    
The _ is a "discard", which was added in C# 7.0:
Discards - C# Guide | Microsoft Docs[^]
This just prevents the "unused return value" compiler warning.

The ... in the MakePredictionRequest method is the existing code from your question. I was just indicating where you needed to make changes to that method so that you could use the return value.

Your Form1 and Program classes are in different namespaces. Either move them to the same namespace, or prefix the class name with the namespace:
dynamic stuff = await fakeBrokenBones.Program.MakePredictionRequest(imageFilePath);


The imageFilePath parameter definitely exists in your Program methods based on the code in your question. If you're getting an error saying it doesn't, then the code in your question doesn't match the code you're trying to run.

And you will need to replace ... in the Predict method with your code to use the returned values.
Member 14883937 9-Jul-20 5:49am    
Thank you so much! Everything works perfectly now :)

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900