问题
I have one form with a search button and a progress bar to find photos on a network dir. It returns a error:
System.Reflection.TargetInvocationException
HResult=0x80131604
Message=O destino de uma invocação accionou uma excepção.
Source=mscorlib
StackTrace:
at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor)
at System.Reflection.RuntimeMethodInfo.UnsafeInvokeInternal(Object obj, Object[] parameters, Object[] arguments)
at System.Delegate.DynamicInvokeImpl(Object[] args)
at System.Windows.Forms.Control.InvokeMarshaledCallbackDo(ThreadMethodEntry tme)
at System.Windows.Forms.Control.InvokeMarshaledCallbackHelper(Object obj)
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Windows.Forms.Control.InvokeMarshaledCallback(ThreadMethodEntry tme)
at System.Windows.Forms.Control.InvokeMarshaledCallbacks()
at System.Windows.Forms.Control.WndProc(Message& m)
at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
at System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)
at System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(IntPtr dwComponentID, Int32 reason, Int32 pvLoopData)
at System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
at System.Windows.Forms.Application.Run(Form mainForm)
at _myprogram.Program.Main() in C:\Users\folder\Desktop\folder\folder\V10\folder\Program.cs:line 19
Inner Exception 1:
ArgumentOutOfRangeException: O índice estava fora do intervalo. Tem de ser não negativo e inferior ao tamanho da colecção.
Nome do parâmetro: índex
Here is the code:
public partial class FormProcuraFotos : Form
{
public FormProcuraFotos()
{
InitializeComponent();
}
// We create the DataTable here so we can create the new inside the Worker_DoWork and use it also on the Worker_RunWorkerCompleted
DataTable tableWithPhotos;
private void button1_Click(object sender, EventArgs e)
{
// Make the progressBar1 to look like its allways loading something
progressBar1.Style = ProgressBarStyle.Marquee;
// Make it here visible
progressBar1.Visible = true;
var worker = new BackgroundWorker();
// Event that runs on background
worker.DoWork += this.Worker_DoWork;
// Event that will run after the background event as finnished
worker.RunWorkerCompleted += this.Worker_RunWorkerCompleted;
worker.RunWorkerAsync();
}
// The reason for having this here was to work with the progress bar and to search for the photos and it will not block the UI Thread
// My advice is to have them here and pass them to the next form with a constructor
private void Worker_DoWork(object sender, DoWorkEventArgs e)
{
// We must create a list for all the files that the search it will find
List<string> filesList = new List<string>();
// Create the new DataTable to be used
tableWithPhotos = new DataTable();
tableWithPhotos.Columns.Add("Nome e formato do ficheiro (duplo clique para visualizar a imagem)");
tableWithPhotos.Columns.Add("Caminho ( pode ser copiado Ctrl+C )");
// What folders that we want to search for the files
var diretorios = new List<string>() { @"C:\Users\folder\Pictures" };
// What extensions that we want to search
var extensoes = new List<string>() { ".jpg", ".bmp", ".png", ".tiff", ".gif" };
// This 2 foreach are to search for the files with the extension that is on the extensoes and on all directories that are on diretorios
// In for foreach we go through all the extensions that we want to search
foreach (string entryExtensions in extensoes)
{
// Now we must go through all the directories to search for the extension that is on the entryExtensions
foreach (string entryDirectory in diretorios)
{
// SearchOption.AllDirectories search the directory and sub directorys if necessary
// SearchOption.TopDirectoryOnly search only the directory
filesList.AddRange(Directory.GetFiles(entryDirectory, entryExtensions, SearchOption.AllDirectories));
}
}
// And now here we will add all the files that it has found into the DataTable
foreach (string entryFiles in filesList)
{
DataRow row = tableWithPhotos.NewRow();
row[0] = Path.GetFileName(entryFiles);
row[1] = entryFiles;
tableWithPhotos.Rows.Add(row);
}
}
private void Worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
// With the new constructor on the FormResultadosFotos, we pass the table like this so the form can receive it
progressBar1.Visible = false;
var NovoForm = new FormResultadosFotos(tableWithPhotos);
NovoForm.Show();
}
}
} I have another form to display those results on a datagridview (this datagridview has a picturebox that shows the photo if a user double click) Here is the code:
public partial class FormResultadosFotos : Form
{
// This is the constructor that we have added to the FormResultadosFotos so it can receive the DataTable that was created on the previous form
public FormResultadosFotos(DataTable table)
{
InitializeComponent();
dataGridView1.DataSource = table;
dataGridView1.Columns[1].Visible = true;
// What can be done here to not block the UI thread if is being blocked while populating the dataGridView1, is to create another BackgroundWorker here and populate the dataGridView1 there
}
}
}
Is it possible to help me and show what is wrong? Thank you.
回答1:
I would change the ProgressBar to be continue like this progressBar1.Style = ProgressBarStyle.Marquee;
and don't have it on the Worker_DoWork since its there but doing nothing in some sorts.
The code that I advice is like this, the BackgroundWorker is doing its job, searching for the files and not blocking the UI Thread AKA not blocking the program while doing a task that can take a long time
On the click we can make it visable and then o the Worker_RunWorkerCompleted invisible after the work as been done.
I did change the Worker_DoWork here, remove the update on the progressBar1 since it was there just for the looks and doing nothing else and make it do its job, a process that can take a long time, that is what they are for
public partial class FormPesquisaFotos : Form
{
// We create the DataTable here so we can create the new inside the Worker_DoWork and use it also on the Worker_RunWorkerCompleted
DataTable tableWithPhotos;
private void button1_Click(object sender, EventArgs e)
{
// Make the progressBar1 to look like its allways loading something
progressBar1.Style = ProgressBarStyle.Marquee;
// Make it here visible
progressBar1.Visible = true;
var worker = new BackgroundWorker();
// Event that runs on background
worker.DoWork += this.Worker_DoWork;
// Event that will run after the background event as finnished
worker.RunWorkerCompleted += this.Worker_RunWorkerCompleted;
worker.RunWorkerAsync();
}
// The reason for having this here was to work with the progress bar and to search for the photos and it will not block the UI Thread
// My advice is to have them here and pass them to the next form with a constructor
private void Worker_DoWork(object sender, DoWorkEventArgs e)
{
// We must create a list for all the files that the search it will find
List<string> filesList = new List<string>();
// Create the new DataTable to be used
tableWithPhotos = new DataTable();
tableWithPhotos.Columns.Add("Nome e formato do ficheiro (duplo clique para visualizar a imagem)");
tableWithPhotos.Columns.Add("Caminho ( pode ser copiado Ctrl+C )");
// What folders that we want to search for the files
var diretorios = new List<string>() { @"\\Server\folder1\folder2" };
// What extensions that we want to search
var extensoes = new List<string>() {"*.jpg","*.bmp","*.png","*.tiff","*.gif"};
// This 2 foreach are to search for the files with the extension that is on the extensoes and on all directories that are on diretorios
// In for foreach we go through all the extensions that we want to search
foreach (string entryExtensions in extensoes)
{
// Now we must go through all the directories to search for the extension that is on the entryExtensions
foreach (string entryDirectory in diretorios)
{
// SearchOption.AllDirectories search the directory and sub directorys if necessary
// SearchOption.TopDirectoryOnly search only the directory
filesList.AddRange(Directory.GetFiles(entryDirectory, entryExtensions, SearchOption.AllDirectories));
}
}
// And now here we will add all the files that it has found into the DataTable
foreach (string entryFiles in filesList)
{
DataRow row = tableWithPhotos.NewRow();
row[0] = Path.GetFileName(entryFiles);
row[1] = entryFiles;
tableWithPhotos.Rows.Add(row);
}
}
private void Worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
// With the new constructor on the FormResultadosFotos, we pass the table like this so the form can receive it
progressBar1.Visable = false;
var NovoForm = new FormResultadosFotos(tableWithPhotos);
NovoForm.Show();
}
}
On the FormResultadosFotos we create a new constructor that will receive the DataTable and remove the need to search for the files here, since they are all ready on the on the table
public partial class FormResultadosFotos : Form
{
// This is the constructor that we have added to the FormResultadosFotos so it can receive the DataTable that was created on the previous form
Public FormResultadosFotos(DataTable table)
{
InitializeComponent();
dataGridView1.DataSource = table;
dataGridView1.Columns[1].Visible = true;
// What can be done here to not block the UI thread if is being blocked while populating the dataGridView1, is to create another BackgroundWorker here and populate the dataGridView1 there
}
private void dataGridView1_DoubleClick(object sender, EventArgs e)
{
var myForm = new FormPictureBox();
string imageName = dataGridView1.CurrentRow.Cells[1].Value.ToString();
var img = Image.FromFile(imageName);
myForm.pictureBox1.Image = img;
myForm.ShowDialog();
}
}
To have the progressBar1 to go from 1 to 100, it would require for you to know before the search how many files there was and such before the search, since we don't know that, having it to go from 1 to 100 its impossible, at least from my knowledge, if it is possible please create an anwser for this since I would like to know how
Having it like this (you must have other methods inside the Class FormResultadosFotos, at least the base constructor) it will do what you want, the search for the files that can take a long time is done on a new Thread AKA BackgroundWorker and if there are any "*.jpg","*.bmp","*.png","*.tiff","*.gif"
files inside the directories that are on the List diretorios
it will put them on the List filesList
so on is foreach
can be added to the DataTable
Edit:
Even being portuguese myself, just a little advice, when asking a question here, try not to put stuff in portuguese, use english, like comments and variables it makes more easy to read your code.
Edit 2:
With the code I provided you its working, as you can see from the picture :
Here is the link for the program download link
As you can see from the info that I shared with you should resolve the problem that you did have, see the source code of the program I did make with the example I provided for you
来源:https://stackoverflow.com/questions/51991134/search-photos-and-progressbar-display