Как сделать вход в систему C# с помощью background worker + progress bar
Привет,
Может ли кто-нибудь объяснить мне, как на самом деле работает фоновый работник? Я хотел бы сделать простую форму входа в систему, которая покажет прогресс входа пользователю после того, как он нажмет loggin, так как обычно требуется много времени, чтобы прочитать данные входа, поэтому я хотел бы обновить пользователя вместо того, чтобы позволить пользовательскому интерфейсу зависнуть.
Я попробовал код ниже, но я не уверен, как и где я могу сохранить результат, чтобы я мог показать пользователю, если вход в систему успешен или нет.
Любая помощь будет очень признательна.
Что я уже пробовал:
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Threading; using System.Windows.Forms; using System.Data.OleDb; using Excel = Microsoft.Office.Interop.Excel; using System.Runtime.InteropServices; using System.Drawing.Printing; namespace LoginDemo { public partial class Form1 : Form { public Form1() { InitializeComponent(); } //Login will be cancelled private void btncancel_Click(object sender, EventArgs e) { if(backgroundWorker1.WorkerSupportsCancellation == true){ backgroundWorker1.CancelAsync(); btnlogin.Enabled = true; btncancel.Enabled = false; } } //Login will be processed private void btnlogin_Click(object sender, EventArgs e) { testobj.username = txtid.Text.Trim().ToString(); if (txtid.Text == string.Empty) { MessageBox.Show("Please enter username", "Login Error", MessageBoxButtons.OK, MessageBoxIcon.Error); txtid.Focus(); } else { lblMessage.Visible = true; progressBar1.Visible = true; testobj.ReadData(); backgroundWorker1.RunWorkerAsync(); btnlogin.Enabled = false; btncancel.Enabled = true; /* if (chckrbm.Checked == true) { IMACBOX.Properties.Settings.Default.loginUsername = username; IMACBOX.Properties.Settings.Default.Save(); }*/ // ReadData(connectionString); } } // Will handle the heavy work private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) { int dataload = 0; for (dataload = 0; dataload <= 100; dataload++) { if (backgroundWorker1.CancellationPending == true) { //user clicked cancel button e.Cancel = true; backgroundWorker1.ReportProgress(0); break; } else { //do the heavywork // ReadDatas(); // dataload += 1; // testobj.ReadData(); backgroundWorker1.ReportProgress(dataload);//Report progress } } e.Result = dataload; } // Will update progressbar on heavy work progress private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e) { //Updater progress bar progressBar1.Value = e.ProgressPercentage; lblMessage.Text = "Loading..." + e.ProgressPercentage.ToString() + " %"; } // Will update when progress is completed private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { //Check progress before displaying message if (e.Cancelled == true) { MessageBox.Show("Operation Cancelled ", "Cancelled ", MessageBoxButtons.OK, MessageBoxIcon.Information); progressBar1.Value = 0; // Reset progressbar value if user cancelled lblMessage.Text = "";//clear the label progressBar1.Visible = false; } else if (e.Error != null) { // String somethingwrong = e.Result.ToString(); MessageBox.Show(e.Error + "Error found " + e.Error.Message , "Error ", MessageBoxButtons.OK, MessageBoxIcon.Error); progressBar1.Value = 0; // Reset progressbar value if user cancelled lblMessage.Text = "";//clear the label } else { MessageBox.Show("Progress done " + e.Result.ToString() + " ","Done ",MessageBoxButtons.OK,MessageBoxIcon.Information); progressBar1.Value = 0; // Reset progressbar value if user cancelled lblMessage.Text = "";//clear the label } } //Method for doing the heavy work private void ReadDatas() { try { Thread.Sleep(100); }catch(Exception e){ MessageBox.Show("Login Result ", e.Message , MessageBoxButtons.OK,MessageBoxIcon.Information); progressBar1.Value = 0; // Reset progressbar value if user cancelled lblMessage.Text = "";//clear the label } } private void Form1_Load(object sender, EventArgs e) { // username = txtid.Text.Trim(); // status = lblMessage.Text.ToString(); // bar = progressBar1.Value; } } }
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Threading; using System.Windows.Forms; using System.Data.OleDb; using Excel = Microsoft.Office.Interop.Excel; using System.Runtime.InteropServices; using System.Drawing.Printing; using System.Data; namespace LoginDemo { class testobj { public static String username, lastname, firstname, status, lblMessage; public static int progressBar1Value = 0; public static string connectionString = @"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=D:\IMAC\APP\IMACDB\FormDB2.xlsx;Extended Properties='Excel 12.0;HDR=Yes;'"; // public string connectionString = @"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=\\132.186.144.184\d$\FormDB4.xlsx;Extended Properties='Excel 12.0;HDR=Yes;'"; // public string connectionString = @"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=\\132.186.144.239\d$\IMAC\APP\IMACDB\FormDB2.xlsx;Extended Properties='Excel 12.0;HDR=Yes;'"; public static OleDbConnection cnn; public static OleDbCommand cmd; public static OleDbDataAdapter da; public static OleDbDataReader dr; public DataSet dstResults = new DataSet(); public DataView myView; public DataTable dtable; public DataColumn c; public static void ReadData() { try { string queryString = "SELECT Employee_ID,LastName,FirstName FROM [Entries$] WHERE Employee_ID ='" + username.Trim().ToString() + "'"; dr = null; cnn = new OleDbConnection(connectionString); cmd = new OleDbCommand(queryString, cnn); cnn.Open(); dr = cmd.ExecuteReader(); if (dr.Read() == true) { Thread.Sleep(100); // MessageBox.Show("Progress bar"); firstname = dr[1].ToString(); lastname = dr[2].ToString(); MessageBox.Show("Login successfull"); } else { MessageBox.Show("Username Invalid", "Error Message"); } // Always call Close when done reading. dr.Close(); } // } catch (Exception e) { MessageBox.Show("Error " + e.Message, "Error"); } } } }
Richard Deeming
"Я не уверен, как и где я могу сохранить результат"
В e.Result
- как это уже делает ваш код.
В чем проблема?
Member 7763261
Привет Ричард,
Спасибо за ваш ответ. Пожалуйста, голые со мной, как я новичок в дело управления backgroundworker. Похоже, что мой progressbar выполняется только после того, как отнимает много времени код, из которого я хотел бы обновить индикатор выполнения, чтобы пользователь знал, что данные загружаются. как мне получить результат из этого объекта e?
Richard Deeming
Основываясь на опубликованном вами коде, вся работа закомментирована, поэтому будет невозможно увидеть, обновляется ли индикатор выполнения во время работы рабочего.
Member 7763261
Я раскомментировал testobj. ReadData (), а также использовал lblMessage из моего класса testobj для отображения сообщений, но progressbar запускается только после этого. теперь мне нужно объявить use progressBar1Value из моего класса testobj, чтобы также удерживать прогресс. потому что из того, что я прочитал, я не могу получить доступ к элементам управления пользовательским интерфейсом из dowork
Richard Deeming
Вы дважды проверили, что WorkerReportsProgress
свойство имеет значение true
?
Member 7763261
Да он установлен в true
Richard Deeming
Что ж, это странно. То ReportProgress
/ ProgressChanged
для меня это прекрасно работает.
И чтобы ответить на ваш другой вопрос, нет, вы не можете напрямую получить доступ или изменить элементы управления из DoWork
метод или любой метод, вызванный из него. Вы можете только вызвать ReportProgress
метод и обновление элементов управления из ProgressChanged
обработчик событий или используйте Invoke
метод для запуска небольшого метода в потоке пользовательского интерфейса для обновления элемента управления.
Member 7763261
Очень, но я закомментировал testobj.ReadData(); на событии btnlogin_Click и вызвал его на dowork, но я застрял внутри цикла. Есть идеи, что я делаю не так. и спасибо за статью о SQL-инъекции. очень информативный.
Richard Deeming
В коде, который вы опубликовали, нет ничего, что могло бы создать бесконечный цикл.
Member 7763261
Хорошо, MessageBox. show, который я показываю из своего класса testobj ? находятся ли они в нужном месте, если я хочу показать пользователю, что пошло не так, или они находятся не в том месте?
Richard Deeming
Они вероятно работа, но вы отображаете пользовательский интерфейс из потока, не являющегося пользовательским интерфейсом.
Я был бы склонен удалить try..catch
блок, и пусть исключение фильтруется до конца. RunWorkerCompleted
обработчик событий.
Я также был бы склонен изменить метод, чтобы вернуть a bool
указывает, был ли вход в систему успешным, а не отображает сообщение. Затем сохраните этот результат в e.Result
недвижимость в DoWork
метод, прочтите его в RunWorkerCompleted
метод, и, наконец, отобразить сообщение об успехе/неудаче там, как только вы вернетесь в поток пользовательского интерфейса.
Member 7763261
Привет Ричард,
Спасибо вам за всю вашу помощь. В конце концов мне удалось исправить код, но я возвращаю строку вместо bool. Пожалуйста, поделитесь, почему вы предпочитаете возвращать bool вместо string?
Richard Deeming
Потому что легче проверить bool
чтобы увидеть, удалось ли войти в систему, и отобразить соответствующее сообщение, чем проверить string
.
Помимо всего прочего, если вы изменили сообщение, но забыли обновить тест, каждый логин вдруг сработает, в том числе и недействительный.
Richard Deeming
Кроме того, ваш код уязвим для SQL-инъекция[^]. НИКОГДА используйте конкатенацию строк для построения SQL-запроса. ВСЕГДА используйте параметризованный запрос.
Все, что вы хотели знать о SQL-инъекции (но боялись спросить) | Трой Хант[^]
Как я могу объяснить SQL-инъекцию без технического жаргона? | Обмен Стеками Информационной Безопасности[^]
Шпаргалка по параметризации запросов / OWASP[^]