C# .NET if image is loaded - c#

I need to find out if my pictureboxes have loaded images.
I create them and give them ImageLocation. Pictures DO load after some time but I need to check if it is loaded. I tried using
if(pb.ImageLocation != null){
Console.WriteLine("Loaded!");
}
But this shows that its loaded even if it actually isn't. Also I have a bunch of dynamic created pictureboxes:
void CreateBrick(int x,int y)
{
bricks[i] = new PictureBox();
bricks[i].Name = "pb_b" + i.ToString();
bricks[i].Location = new Point(y, x);
bricks[i].Size = new Size(60, 60);
bricks[i].ImageLocation = #"Images/brick_wall.jpg";
pb_bg.Controls.Add(bricks[i]);
brick.Add(bricks[i]);
i++;
}
And I have no idea how to check these...

The problem in your code is that you don't call the Load or LoadAsync method.
void CreateBrick(int x,int y)
{
bricks[i] = new PictureBox();
bricks[i].Name = "pb_b" + i.ToString();
bricks[i].Location = new Point(y, x);
bricks[i].Size = new Size(60, 60);
// You can pass the path directly to the Load method
// bricks[i].ImageLocation = #"Images/brick_wall.jpg";
bricks[i].Load(#"Images/brick_wall.jpg");
pb_bg.Controls.Add(bricks[i]);
brick.Add(bricks[i]);
i++;
}
If you use Load method then then the image is loaded after the call, if you use LoadAsync you could add the event handler for the LoadComplete event.
bricks[i].LoadCompleted += onLoadComplete;
bricks[i].LoadAsync(#"Images/brick_wall.jpg");
....
private void onLoadComplete(Object sender, AsyncCompletedEventArgs e)
{
// Don't forget to check if the image has been really loaded,
// this event fires also in case of errors.
if (e.Error == null && !e.Cancelled)
Console.WriteLine("Image loaded");
else if (e.Cancelled)
Console.WriteLine("Load cancelled");
else
Console.WriteLine("Error:" + e.Error.Message);
}
If you want to use the LoadAsync approach you still have to solve the problem how to match the complete load of a particular image to the related picture box. This could be solved using the sender parameter of the LoadAsync. This sender parameter is the PictureBox who has completed the load of the image.
You can use the Tag property and set it to "1" to mark your picturebox as loaded and to the error message in case of problems.
private void onLoadComplete(Object sender, AsyncCompletedEventArgs e)
{
PictureBox pic = sender as PictureBox;
// Don't forget to check if the image has been really loaded,
// this event fires also in case of errors.
if (e.Error == null && !e.Cancelled)
{
pic.Tag = "1";
Console.WriteLine("Image loaded");
}
else
{
pic.Tag = e.Error.Message;
Console.WriteLine("Cancelled:" + e.Error.Message);
}
}
After this the pictureboxes in your bricks arrays have their Tag property marked as "1" for the loaded ones and with an error message for the ones with an error.

Could you try using LoadCompleted event of PictureBox after you assign a ImageLocation as the way it is described here
You can make sure images are loaded asynchronously of course.
pb.WaitOnLoad = false;
Then load the image asynchronously:
pb.LoadAsync("some.gif");
For more from stackoverflow you can have a look here and here
Assign an event handler like the following:
pb.LoadCompleted += PictureBox1_LoadCompleted;
Sample event handler right from msdn:
private void PictureBox1_LoadCompleted(Object sender, AsyncCompletedEventArgs e) {
System.Text.StringBuilder messageBoxCS = new System.Text.StringBuilder();
messageBoxCS.AppendFormat("{0} = {1}", "Cancelled", e.Cancelled );
messageBoxCS.AppendLine();
messageBoxCS.AppendFormat("{0} = {1}", "Error", e.Error );
messageBoxCS.AppendLine();
messageBoxCS.AppendFormat("{0} = {1}", "UserState", e.UserState );
messageBoxCS.AppendLine();
MessageBox.Show(messageBoxCS.ToString(), "LoadCompleted Event" );
}

private stattic bool CheckUplodedImage()
{
bool return = false;
try
{
PictureBox imageControl = new PictureBox();
imageControl.Width = 60;
imageControl.Height = 60;
Bitmap image = new Bitmap("Images/brick_wall.jpg");
imageControl.Image = (Image)image;
Controls.Add(imageControl);
return true;
}
catch(Exception ex)
{
return false;
}
}
can check of its return
bool isUploded = CheckUplodedImage();
if(isUploded)
{
\\ ...uploaded
\\ Perform Operation
}
else
\\ not uploaded

Related

How can I load multiple images using LoadAsync() in C#?

I'm trying to update the GUI, and I have an asynchronous function that uses LoadAsyc(), when I load just one image, it works but when I try to load more than one, the second one doesn't display.
This my code:
public UserFriendlyInterface()
{
InitializeComponent();
locationFileH5 = "";
serverStatus = false;
ipAddress = getLocalIPAddress();
port = 5000;
watcher = new FileSystemWatcher(#"flask_server\cnn\_prepImages_");
watcher.EnableRaisingEvents = true;
watcher.Changed += watcher_Changed;
}
private void watcher_Changed(object sender, FileSystemEventArgs e)
{
updateImages();
}
async Task updateImages()
{
pictureBoxNormalImg.WaitOnLoad = false;
pictureBoxNormalImg.LoadAsync(#"flask_server\cnn\_prepImages_\normal.jpg");
pictureBoxSegmentation.WaitOnLoad = false;
pictureBoxSegmentation.LoadAsync(#"flask_server\cnn\_prepImages_\segmentation.jpg");
}
What you are trying to achieve can be achieved more robustly by querying the Name property of the FileSystemEventArgs object, and updating only the corresponding PictureBox.
private static void Watcher_Changed(object sender, FileSystemEventArgs e)
{
PictureBox pictureBox;
switch (e.Name.ToLowerInvariant())
{
case "normal.jpg": pictureBox = pictureBoxNormalImg; break;
case "segmentation.jpg": pictureBox = pictureBoxSegmentation; break;
default: pictureBox = null; break;
}
if (pictureBox != null)
{
Image image = null;
try
{
using (var temp = new Bitmap(e.FullPath))
{
image = new Bitmap(temp);
}
}
catch { } // Swallow exception
if (image != null)
{
pictureBox.Invoke((MethodInvoker)(delegate ()
{
pictureBox.Image = image;
}));
}
}
}
I would avoid the LoadAsync method because it is intended mainly for loading images from the internet, and because I don't totally trust it.
Update: There were two problems with my initial code:
1) Free file locked by new Bitmap(filePath)
2) FileSystemWatcher Changed event is raised twice
The updated code solves these problems (hopefully), but not in the most robust or efficient way possible.
Update: To make the code more efficient, by avoiding the repeated loading of the images caused by multiple firings of the Changed event, you could use the extension method OnChanged found in this answer. It suffices to replace the line below:
watcher.Changed += Watcher_Changed;
...with this one:
watcher.OnChanged(Watcher_Changed, 100);

How do I bypass code in the RunWorkerCompleted event if an error occurs?

I wrote a program that creates an XML file from the contents of an Excel spreadsheet. The program works and I am now making it more robust by adding error checking. For example, if the Excel spreadsheet does not contain a required XML tag, the program displays an error and returns from the main program. When an error occurs, the RunWorkerCompleted() event fires, and code executes that shouldn't execute because an error occurred. My question is how to determine if an error occurred so I can bypass certain code in the RunWorkerCompleted() event.
I tried calling bgw.CancelAsync() in the main program where the error is detected, but RunWorkerCompletedEventArgs e.Cancelled is false so it doesn't work.
Here are some excerpts from my code. The progress bar is started in the click event of a button. It works, but I had to declare cellsProcessed, rowCount, and colCount as global because I couldn't figure out how to pass them to bgw_DoWork().
private void button_create_Click(object sender, EventArgs e)
{
// Define the event that fires when the progress bar finishes
bgw.RunWorkerCompleted += bgw_Complete;
rowCount = xmlRange.Rows.Count; // Declared as global
colCount = xmlRange.Columns.Count; // Declared as global
// Start the progress bar thread
if (!bgw.IsBusy)
{
bgw.RunWorkerAsync();
}
// Read the header in row 1 and return an error if it isn't valid
for (colIdx = 1; colIdx <= colCount; colIdx++)
{
if ((xmlRange.Cells[1, colIdx] != null) && (xmlRange.Cells[1, colIdx].Value2 != null))
{
cellContents = xmlRange.Cells[1, colIdx].Value2.ToString();
switch (colIdx)
{
case 1:
if (cellContents != "Tag")
{
error = true;
errText = "Cell A1 must contain 'Tag'";
}
break;
case 2:
if (cellContents != "Type")
{
error = true;
errText = "Cell B1 must contain 'Type'";
}
break;
if (error)
{
bgw.CancelAsync();
MessageBox.Show(errText, "Error", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
// Close Excel resources
xmlWorkbook.Close();
xmlSpreadsheet.Quit();
Marshal.ReleaseComObject(xmlRange);
Marshal.ReleaseComObject(xmlWorksheet);
Marshal.ReleaseComObject(xmlWorkbook);
Marshal.ReleaseComObject(xmlSpreadsheet);
GC.Collect();
return;
}
private void bgw_DoWork(object sender, DoWorkEventArgs e)
{
if (bgw.CancellationPending)
{
e.Cancel = true;
}
else
{
label_pctComplete.Text = "Completed " + progressBar.Value.ToString() + "%";
bgw.ReportProgress((100 * ++cellsProcessed) / (rowCount * colCount));
}
}
private void bgw_Complete(object sender, RunWorkerCompletedEventArgs e)
{
if (!e.Cancelled)
{
label_pctComplete.Visible = false;
progressBar.Visible = false;
// Inform the user that the XML file was created
label_created.Visible = true;
label_created.Text = "Done!...Created " + textBox_outputFile.Text;
// Enable the button so the user can view the XML Limit File
button_openLimitFile.Enabled = true;
}
}
private void bgwProgressChanged(object sender, ProgressChangedEventArgs e)
{
progressBar.Value = e.ProgressPercentage;
}
Thank you for any help.

c# prevent screen capture of UserControl

The execs at my company would like a particular custom control of our ui to make a best-effort at preventing screen capture. I implemented a slick solution using SetWindowDisplayAffinity and DWMEnableComposition at the top Window level of our application to prevent screen capture of the entire app but the previously mentioned execs weren't happy with that. They want only the particular UserControl to prevent screen capture, not the entire app.
The custom control is a .NET 2.0 Windows.Forms.UserControl wrapped in a 4.5 WPF WindowsFormsHost contained by a 4.5 WPF Window control.
Before I tell the execs where to go, I want to be certain there isn't a reasonable way to implement this.
So, my question is: How do I implement screen capture prevention of a .NET 2.0 UserControl?
Thanks
i had an idea:
the user click "PrintScreen", a capture from my program is copy to ClipBoard.
So, all what i need it: to catch cliboard an check if he contains an image.
if yes: i delete the image from clipboard.
the code:
//definition a timer
public static Timer getImageTimer = new Timer();
[STAThread]
static void Main()
{
getImageTimer.Interval = 500;
getImageTimer.Tick += GetImageTimer_Tick;
getImageTimer.Start();
......
}
private static void GetImageTimer_Tick(object sender, EventArgs e)
{
if (Clipboard.ContainsImage())//if clipboard contains an image
Clipboard.Clear();//delete
}
*but it avoid any time program is running. (you need to know if your program is foreground, and then check clipboard);
You might be able to capture the key stroke.
Below is a method I used for that, but it had limited success:
protected override bool ProcessCmdKey(ref Message msg, Keys keyData) {
if ((m_parent != null) && m_parent.ScreenCapture(ref msg)) {
return true;
} else {
return base.ProcessCmdKey(ref msg, keyData);
}
}
protected override bool ProcessKeyEventArgs(ref Message msg) {
if ((m_parent != null) && m_parent.ScreenCapture(ref msg)) {
return true;
} else {
return base.ProcessKeyEventArgs(ref msg);
}
}
Returning "True" was supposed to tell the system that the PrintScreen routine was handled, but it often still found the data on the clipboard.
What I did instead, as you can see from the call to m_parent.ScreenCapture, was to save the capture to a file, then display it in my own custom image viewer.
If it helps, here is the wrapper I created for the custom image viewer in m_parent.ScreenCapture:
public bool ScreenCapture(ref Message msg) {
var WParam = (Keys)msg.WParam;
if ((WParam == Keys.PrintScreen) || (WParam == (Keys.PrintScreen & Keys.Alt))) {
ScreenCapture(Environment.GetFolderPath(Environment.SpecialFolder.Desktop));
msg = new Message(); // erases the data
return true;
}
return false;
}
public void ScreenCapture(string initialDirectory) {
this.Refresh();
var rect = new Rectangle(Location.X, Location.Y, Size.Width, Size.Height);
var imgFile = Global.ScreenCapture(rect);
//string fullName = null;
string filename = null;
string extension = null;
if ((imgFile != null) && imgFile.Exists) {
filename = Global.GetFilenameWithoutExt(imgFile.FullName);
extension = Path.GetExtension(imgFile.FullName);
} else {
using (var worker = new BackgroundWorker()) {
worker.DoWork += delegate(object sender, DoWorkEventArgs e) {
Thread.Sleep(300);
var bmp = new Bitmap(rect.Width, rect.Height);
using (var g = Graphics.FromImage(bmp)) {
g.CopyFromScreen(Location, Point.Empty, rect.Size); // WinForm Only
}
e.Result = bmp;
};
worker.RunWorkerCompleted += delegate(object sender, RunWorkerCompletedEventArgs e) {
if (e.Error != null) {
var err = e.Error;
while (err.InnerException != null) {
err = err.InnerException;
}
MessageBox.Show(err.Message, "Screen Capture", MessageBoxButtons.OK, MessageBoxIcon.Stop);
} else if (e.Cancelled) {
} else if (e.Result != null) {
if (e.Result is Bitmap) {
var bitmap = (Bitmap)e.Result;
imgFile = new FileInfo(Global.GetUniqueFilenameWithPath(m_screenShotPath, "Screenshot", ".jpg"));
filename = Global.GetFilenameWithoutExt(imgFile.FullName);
extension = Path.GetExtension(imgFile.FullName);
bitmap.Save(imgFile.FullName, ImageFormat.Jpeg);
}
}
};
worker.RunWorkerAsync();
}
}
if ((imgFile != null) && imgFile.Exists && !String.IsNullOrEmpty(filename) && !String.IsNullOrEmpty(extension)) {
bool ok = false;
using (SaveFileDialog dlg = new SaveFileDialog()) {
dlg.Title = "ACP Image Capture: Image Name, File Format, and Destination";
dlg.FileName = filename;
dlg.InitialDirectory = m_screenShotPath;
dlg.DefaultExt = extension;
dlg.AddExtension = true;
dlg.Filter = "PNG Image|*.png|Jpeg Image (JPG)|*.jpg|GIF Image (GIF)|*.gif|Bitmap (BMP)|*.bmp" +
"|EWM Image|*.emf|TIFF Image|*.tif|Windows Metafile (WMF)|*.wmf|Exchangable image file|*.exif";
dlg.FilterIndex = 0;
if (dlg.ShowDialog(this) == DialogResult.OK) {
imgFile = imgFile.CopyTo(dlg.FileName, true);
m_screenShotPath = imgFile.DirectoryName;
ImageFormat fmtStyle;
switch (dlg.FilterIndex) {
case 2: fmtStyle = ImageFormat.Jpeg; break;
case 3: fmtStyle = ImageFormat.Gif; break;
case 4: fmtStyle = ImageFormat.Bmp; break;
case 5: fmtStyle = ImageFormat.Emf; break;
case 6: fmtStyle = ImageFormat.Tiff; break;
case 7: fmtStyle = ImageFormat.Wmf; break;
case 8: fmtStyle = ImageFormat.Exif; break;
default: fmtStyle = ImageFormat.Png; break;
}
ok = true;
}
}
if (ok) {
string command = string.Format(#"{0}", imgFile.FullName);
try { // try default image viewer
var psi = new ProcessStartInfo(command);
Process.Start(psi);
} catch (Exception) {
try { // try IE
ProcessStartInfo psi = new ProcessStartInfo("iexplore.exe", command);
Process.Start(psi);
} catch (Exception) { }
}
}
}
}
I wrote that years ago, and I don't work there now. The source code is still in my Cloud drive so that I can leverage skills I learned once (and forgot).
That code isn't meant to get you completely done, but just to show you a way of doing it. If you need any help with something, let me know.
Not a silver bullet, but could form part of a strategy...
If you were worried about the windows snipping tool or other known snipping tools, you could subscribe to Windows events to capture a notification of when SnippingTool.exe was launched and then hide your application until it was closed:
var applicationStartWatcher = new ManagementEventWatcher(new WqlEventQuery("SELECT * FROM Win32_ProcessStartTrace"));
applicationStartWatcher.EventArrived += (sender, args) =>
{
if (args.NewEvent.Properties["ProcessName"].Value.ToString().StartsWith("SnippingTool"))
{
Dispatcher.Invoke(() => this.Visibility = Visibility.Hidden);
}
};
applicationStartWatcher.Start();
var applicationCloseWatcher = new ManagementEventWatcher(new WqlEventQuery("SELECT * FROM Win32_ProcessStopTrace"));
applicationCloseWatcher.EventArrived += (sender, args) =>
{
if (args.NewEvent.Properties["ProcessName"].Value.ToString().StartsWith("SnippingTool"))
{
Dispatcher.Invoke(() =>
{
this.Visibility = Visibility.Visible;
this.Activate();
});
}
};
applicationCloseWatcher.Start();
You will probably need to be running as an administrator for this code to work.
ManagementEventWatcher is in the System.Management assembly.
This coupled with some strategy for handling the print screen key: for example something like this may at least make it difficult to screen capture.

Add files to Listbox via Thread?

in my application i want to add files into my list box.
if my file isn't pcap extension i want to send the file path to my class and convet it to pcap extension and then add this file to my Listbox.
in case i am choose to add namy files the GUI not responding until my application finish to add or convert this file and i wonder how to add the option to do all this via threads.
private void btnAddfiles_Click(object sender, EventArgs e)
{
System.IO.Stream stream;
OpenFileDialog thisDialog = new OpenFileDialog();
thisDialog.InitialDirectory = (lastPath.Length > 0 ? lastPath : "c:\\");
thisDialog.Filter = "(*.snoop, *.pcap, *.cap, *.net, *.pcapng, *.5vw, *.bfr, *.erf, *.tr1)" +
"|*.snoop; *.pcap; *.cap; *.net; *.pcapng; *.5vw; *.bfr; *.erf; *.tr1|" + "All files (*.*)|*.*";
thisDialog.FilterIndex = 1;
thisDialog.RestoreDirectory = false;
thisDialog.Multiselect = true;
thisDialog.Title = "Please Select Source File";
if (thisDialog.ShowDialog() == DialogResult.OK)
{
if (thisDialog.FileNames.Length > 0)
{
lastPath = Path.GetDirectoryName(thisDialog.FileNames[0]);
}
foreach (String file in thisDialog.FileNames)
{
try
{
if ((stream = thisDialog.OpenFile()) != null)
{
using (stream)
{
string fileToAdd = string.Empty;
Editcap editcap = new Editcap();
BackgroundWorker backgroundWorker = new BackgroundWorker();
backgroundWorker.WorkerReportsProgress = true;
backgroundWorker.DoWork += new DoWorkEventHandler(
(s3, e3) =>
{
if (!editcap.isLibpcapFormat(file))
{
fileToAdd = editcap.getNewFileName(file);
}
else
{
listBoxFiles.Items.Add(file);
}
});
backgroundWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(
(s3, e3) =>
{
listBoxFiles.Items.Add(fileToAdd);
});
backgroundWorker.RunWorkerAsync();
lastPath = Path.GetDirectoryName(thisDialog.FileNames[0]);
}
}
}
catch (Exception ex)
{
MessageBox.Show("Error: Could not read file from disk. Original error: " + ex.Message);
}
}
}
}
Your application is freezing because you're doing a lot of work in the UI thread. You need to move the long running tasks to a background thread and then just update the UI in the UI thread.
The first thing that you need to do, in order to do that, is seperate out your long running task from your UI manipulation. Currently you're intermingliing the two, which is what's causing your confusion as to how to map it to a BackgroundWorker.
As long as you don't need to be updating the listbox iteratively and it's okay to just add all of the items at the end all at once (that's what I would expect out of a listbox) you can simply do your file IO in one place, adding the results into a collection of some sort (List is likely appropriate here) and then, separately, you can add all of the items in the list to your ListBox (or use data binding).
Once you make that change the move to using something like a BackgroundWorker is quite easy. The IO work that populates the List goes in the DoWork, runs in the background, and then sets the Result. The RunWorkerCompleted event then takes that lists and adds the items to the ListBox.
If you have a compelling need to add the items to the listbox as you go, so you see one item, then the next, etc. over time, then just think of it as "reporting progress" and use the relevant progress reporting functionality built into BackgroundWorker. Update the progress inside of the loop, and in the progress reported event handler take the value given to you and put it in the ListBox.
Here is an implementation:
private void btnAddfiles_Click(object sender, EventArgs e)
{
System.IO.Stream stream;
OpenFileDialog thisDialog = new OpenFileDialog();
thisDialog.InitialDirectory = (lastPath.Length > 0 ? lastPath : "c:\\");
thisDialog.Filter = "(*.snoop, *.pcap, *.cap, *.net, *.pcapng, *.5vw, *.bfr, *.erf, *.tr1)" +
"|*.snoop; *.pcap; *.cap; *.net; *.pcapng; *.5vw; *.bfr; *.erf; *.tr1|" + "All files (*.*)|*.*";
thisDialog.FilterIndex = 1;
thisDialog.RestoreDirectory = false;
thisDialog.Multiselect = true;
thisDialog.Title = "Please Select Source File";
if (thisDialog.ShowDialog() == DialogResult.OK)
{
if (thisDialog.FileNames.Length > 0)
{
lastPath = Path.GetDirectoryName(thisDialog.FileNames[0]);
}
BackgroundWorker backgroundWorker = new BackgroundWorker();
backgroundWorker.WorkerReportsProgress = true;
backgroundWorker.DoWork +=
(s3, e3) =>
{
//TODO consider moving everything inside of the `DoWork` handler to another method
//it's a bit long for an anonymous method
foreach (String file in thisDialog.FileNames)
{
try
{
if ((stream = thisDialog.OpenFile()) != null)
{
using (stream)
{
Editcap editcap = new Editcap();
if (!editcap.isLibpcapFormat(file))
{
string fileToAdd = editcap.getNewFileName(file);
backgroundWorker.ReportProgress(0, fileToAdd);
}
else
{
backgroundWorker.ReportProgress(0, file);
}
lastPath = Path.GetDirectoryName(thisDialog.FileNames[0]);
}
}
}
catch (Exception ex)
{
MessageBox.Show("Error: Could not read file from disk. Original error: " + ex.Message);
}
}
};
backgroundWorker.ProgressChanged +=
(s3, arguments) =>
{
listBoxFiles.Items.Add(arguments.UserState);
};
backgroundWorker.RunWorkerAsync();
}
}
You can do it with BackgroundWorker:
Add a backgroundWorker to your form via the Toolbox.
Start it with:
backgroundWorker.RunWorkerAsync(new string[] {parm1, parm2});
Add a events to backgroundWorker (Properties window)
Use DoWork to do your calculations. Then use RunWorkerCompleted to apply the settings.

C# Thread dataGridView and Loading

Im trying to load a dataGridView which takes some time, so ive come up with an idea of hiding the datagridview and put an image over the top which says Loading... when finished, the image goes away and the datagrid reappears. Ive tried to do this using threading but having no luck.
Can somebody tell me if i am approaching this in the right way?
Label loadingText = new Label();
PictureBox loadingPic = new PictureBox();
private void TelephoneDirectory_Load(object sender, EventArgs e)
{
dataGridView1.Visible = false;
Thread i = new Thread(LoadImage);
i.Start();
Thread t = new Thread(LoadData);
t.Start();
}
void LoadImage()
{
if (this.InvokeRequired)
{
this.Invoke(new MethodInvoker(LoadImage));
}
else
{
loadingPic.Image = Properties.Resources.ReportServer;
loadingPic.Location = new Point(0, 0);
loadingPic.Name = "loadingPic";
loadingPic.Dock = DockStyle.Fill;
loadingPic.SizeMode = PictureBoxSizeMode.CenterImage;
loadingText.Text = "Loading, please wait...";
loadingText.Name = "loadingText";
loadingText.TextAlign = ContentAlignment.MiddleCenter;
loadingText.Size = new Size(this.Size.Width, 30);
loadingText.Font = new System.Drawing.Font("Segoe UI", 9);
loadingText.Location = new Point(0, (this.Size.Height / 2 + 10));
this.Controls.AddRange(new Control[] { loadingPic, loadingText });
loadingText.BringToFront();
}
}
private void LoadData()
{
if (dataGridView1.InvokeRequired)
{
dataGridView1.Invoke(new MethodInvoker(this.LoadData));
}
else
{
DirectorySearcher sea = null;
DirectoryEntry dir = null;
DirectoryEntry d = null;
string domainname = System.DirectoryServices.ActiveDirectory.Domain.GetComputerDomain().Name;
domainname = domainname.Replace(".", ",DC=");
try
{
dir = new DirectoryEntry();
dir.Path = "LDAP://DC=" + domainname;
sea = new DirectorySearcher(dir);
sea.Filter = "(&(objectClass=user)(extensionAttribute1=1)(telephoneNumber=*))";
sea.PageSize = 2000;
SearchResultCollection res = sea.FindAll();
foreach (SearchResult result in res)
{
//DO ALL MY STUFF
dataGridView1.Rows.Add(row);
}
}
catch { }
LoadDataComplete();
}
}
void LoadDataComplete()
{
PictureBox loadingGraphic = this.Controls["loadingPic"] as PictureBox;
Label LoadingLabel = this.Controls["loadingText"] as Label;
DataGridView dataGrid = this.Controls["dataGridView1"] as DataGridView;
dataGrid.Visible = true;
LoadingLabel.Visible = false;
LoadingLabel.Dispose();
loadingGraphic.Visible = false;
loadingGraphic.Dispose();
dataGridView1.Sort(dataGridView1.Columns[0], ListSortDirection.Ascending);
dataGridView1.ClearSelection();
}
Spawning threads for this might not be the best idea, you could use ThreadPool or BackgroundWorker
Loading image should be fast enough that you could just do it synchronously, so make sure you actually need to do some operation on the other thread before you actually need it.
Ask yourself questions like: what if actually my image will load later then my dataTable? ("but it loads faster every time I checked" is not an valid argument when talking about threads)
At the beginning of your methods you are using .Invoke which basically means "wait for UI thread and invoke my code on it synchronously" which bombards your whole idea.
Try something like this:
Load image synchronously
Use ThreadPool to load your DataTable in it, but without using .Invoke
When it's loaded and you need to interact with UI -> then put your code in .Invoke()
Pseudocode coud look like this:
private void TelephoneDirectory_Load(object sender, EventArgs e)
{
dataGridView1.Visible = false;
LoadImage();
ThreadPool.QueueUserWorkItem(new WaitCallback(o => LoadData()));
}
void LoadData()
{
//...Do loading
//but don't add rows to dataGridView
if (dataGridView1.InvokeRequired)
{
//Invoke only the ui-interaction code
dataGridView1.Invoke(new MethodInvoker(this.LoadDataComplete));
}
}
void LoadDataComplete()
{
foreach (SearchResult result in res)
{
//DO ALL MY STUFF
//If do all my stuff is compute intensive and doesn't require UI,
//put it before Invoke() (like here)
dataGridView1.Rows.Add(row);
}
//Rest of code
}

Categories

Resources