Member 14883937 Ответов: 1

C# - как "подключить" код консольного приложения к графическому интерфейсу windows forms?


Я пытаюсь создать программу, в которой в форме Windows Forms пользователь, нажав на кнопку, может выбрать изображение из проводника файлов, которое отображается в графическом окне. С помощью кода консольного приложения путь к файлу изображения затем используется для поиска изображения, преобразования его в массив байтов, а затем отправки его вместе с необходимыми ключами API в API. Затем он возвращает ответ, который я хотел бы вывести в виде текстового поля.

Проблема в том, что я не могу заставить две части моего проекта "разговаривать "друг с другом - я не могу" вызывать " задачи в форме.cs из progam.cs, что может быть связано с тем, что они асинхронны? Я новичок в C#, и я не уверен, что объединение этих двух элементов в одну программу вообще возможно.

Вот мой код forms.cs:

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



            }

        }
    }
}


а вот и мой программный код.cs:
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);
        }
    }
}


Что я уже пробовал:

Я искал везде, но не нашел ничего похожего на мою проблему. Я пробовал скопировать весь свой код program.cs в forms.cs, но ему это тоже не нравится.

На данный момент я просто хочу знать, возможно ли это на самом деле, потому что я потратил так много часов, пытаясь заставить его работать безрезультатно. Если есть способ сделать это, я был бы так благодарен и благодарен, если бы вы могли мне помочь.

1 Ответов

Рейтинг:
9

Richard Deeming

Вы не пытаетесь вызвать консольное приложение из приложения Windows Forms; вы пытаетесь вызвать метод в одном классе из другого класса.

Поскольку метод, который вы пытаетесь вызвать, является static, вам просто нужно поставить перед ним имя содержащего класса.

Поскольку метод, который вы пытаетесь вызвать, является async, вам понадобится async метод, чтобы вызвать его, если вы хотите использовать результаты. Но вы должны это сделать избегать async void методы[^] везде, где это возможно.

Обновите свой MakePredictionRequest метод возврата значения, которое вы хотите использовать:

public static async Task<object> MakePredictionRequest(string imageFilePath)
{
    ...
        string responseString = await response.Content.ReadAsStringAsync();
        return JsonConvert.DeserializeObject<object>(responseString);
    }
}
Затем обновите код формы, чтобы вызвать его и использовать полученный результат:
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;
    ...
}


Member 14883937

Привет, Ричард, спасибо, что так быстро ответил. К сожалению (и это может быть просто недостаток знаний C# с моей стороны), появилась пара ошибок.

Что я должен поставить там, где вы оставили _ : "_ = Predict(Chosen_File)"?
И что я должен положить в ...?

Кроме того, он говорит в форме.CS, что программа не существует в этом контексте и что в программе.КС она говорит, что imageFilePath именем ' не существует в этом контексте.

Должен ли я также добавить ссылку на system.range? и он говорит, что "оператор диапазона" недоступен в C#7.3.

Спасибо снова,

Richard Deeming

То _ это "отбрасывание", которое было добавлено в C# 7.0:
Отбрасывает - Руководство По C# | Microsoft Docs[^]
Это просто предотвращает предупреждение компилятора "неиспользуемое возвращаемое значение".

То ... в MakePredictionRequest метод-это существующий код из вашего вопроса. Я просто указывал, где вам нужно внести изменения в этот метод, чтобы вы могли использовать возвращаемое значение.

Ваш Form1 и Program классы находятся в разных пространствах имен. Либо переместите их в одно пространство имен, либо префикс имени класса с этим пространством имен:

dynamic stuff = await fakeBrokenBones.Program.MakePredictionRequest(imageFilePath);


То imageFilePath параметр определенно существует в вашем Program методы, основанные на коде в вашем вопросе. Если вы получаете сообщение об ошибке, говорящее, что это не так, то код в вашем вопросе не соответствует коду, который вы пытаетесь запустить.

И вам нужно будет заменить его ... в Predict метод с вашим кодом для использования возвращаемых значений.

Member 14883937

Большое вам спасибо! Теперь все работает отлично :)