-
October 31st, 2009, 11:49 AM
#1
Threading UI components
I'm building a WPF photo viewing application, and trying to get a handle on threading. I've asked about this before in this forum -- and although everyone's reading suggestions have been good, I'm still having a hard time putting everything together.
I have two listBoxes -- gallerySelector stores a the names of folders with which images are stored. PhotosListBox is populated with the photos in the directory specified by gallerySelector.
The program is based on Microsoft's Photo Viewer WPF demo app (http://msdn.microsoft.com/en-us/library/ms771331.aspx)
I want to make the gallerySelector more responsive (so you can arrow up and down through all the folders very quickly -- without having to wait for PhotosListBox to load alll the images), so I thought I'd try threading once again. But I'm failing miserably. Of course, I'm getting the following error message:
Code:
"The calling thread cannot access this object because a different thread owns it."
Code:
private void gallerySelector_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
ThreadStart gallerySelectionThread = new ThreadStart(new ThreadStart(delegate()
{
this.Photos.Path = Environment.CurrentDirectory + "\\images\\" + gallerySelector.SelectedItem;
PhotosListBox.SelectedIndex = 0;
}
));
Thread galleryThread = new Thread(gallerySelectionThread);
galleryThread.SetApartmentState(ApartmentState.STA);
galleryThread.Start();
}
where Photos is an ObservableCollection, described as:
Code:
public class PhotoCollection : ObservableCollection<Photo>
{
public PhotoCollection() { }
public PhotoCollection(string path) : this(new DirectoryInfo(path)) { }
public PhotoCollection(DirectoryInfo directory)
{
_directory = directory;
Update();
}
public string Path
{
set
{
_directory = new DirectoryInfo(value);
Update();
}
get { return _directory.FullName; }
}
public DirectoryInfo Directory
{
set
{
_directory = value;
Update();
}
get { return _directory; }
}
private void Update()
{
this.Clear();
try
{
foreach (FileInfo f in _directory.GetFiles("*.jpg"))
Add(new Photo(f.FullName));
}
catch (DirectoryNotFoundException)
{
System.Windows.MessageBox.Show("No Such Directory");
}
}
DirectoryInfo _directory;
}
Would it work better to move the threading code into the ObservableClass definition? In addition, it would be great to populate the PhotosListBox item-by-item, so they would be inserted into the PhotosListBox as they are loaded and rendered.
I'll be ecstatic if I can get this working -- I appreciate any help anyone can give me. Thanks!
-
November 3rd, 2009, 06:24 PM
#2
Re: Threading UI components
-
November 3rd, 2009, 06:52 PM
#3
Re: Threading UI components
http://hantou.blogspot.com/2009/04/c...perations.html
You can also search this Google and this forum for "Cross thread exception" to find more info.
-
November 3rd, 2009, 08:46 PM
#4
Re: Threading UI components
Thanks, that helped a bit -- I ended up finding this, which really got me going in the right direction. I modified my ObservablePhotoCollection class to this:
Code:
private void Update()
{
this.Clear();
new Thread(new ParameterizedThreadStart(AddPhoto)).Start(_directory as object);
}
void AddPhoto(object data)
{
foreach (FileInfo f in ((DirectoryInfo)data).GetFiles("*.jpg"))
try
{
Add(new Photo(f.FullName));
}
catch
{
MessageBox.Show("Cannot load image: " + f.FullName);
}
}
Everything works dandy, but if I switch between directories before the thread finishes executing, it will clear the list box, but the (not finished yet) thread continues to populate it with images from the LAST directory.
So, I tried to declare the thread (instead of just new Thread()) so I could manipulate it later using Start() and Abort(), like this:
Code:
Thread AddPhotoThread = new Thread(new ParameterizedThreadStart(AddPhoto));
private void Update()
{
AddPhotoThread.Abort();
Clear();
AddPhotoThread.Start(_directory as object);
}
But I keep getting this error:
Code:
A field initializer cannot reference the non-static field, method, or property
So, my next question: How do I setup my thread to start/stop later?
-
November 3rd, 2009, 10:46 PM
#5
Re: Threading UI components
OK, after a bit more work, I've got this to work:
Code:
Thread AddPhotoThread;
private void Update()
{
try
{
AddPhotoThread.Abort();
}
catch
{
}
Clear();
AddPhotoThread = new Thread(new ThreadStart(AddPhoto));
AddPhotoThread.Start();
}
It seems to work, but it'll tank if I take out the try... catch... statement (since, on first run, the thread hasn't been set). I tried doing:
Code:
if(AddPhotoThread.IsAlive)
{
AddPhotoThread.Abort();
}
but that didn't work either. Any suggestions?
-
November 4th, 2009, 12:08 AM
#6
Re: Threading UI components
It's not good to ABORT a thread, unless you have to. Just raise an event on the change event, and set a boolean in the loop. if threadRunning = True
-
November 4th, 2009, 12:42 AM
#7
Re: Threading UI components
Originally Posted by dglienna
It's not good to ABORT a thread, unless you have to. Just raise an event on the change event, and set a boolean in the loop. if threadRunning = True
*looks embarrassed* Yeah, I should have thought of that, shouldn't have I?
Haha, how obvious is it that I'm an Electrical Engineering student who hasn't taken a programming class since Freshman year?
Anyway, next question: if it's not a good idea to abort a thread, then how should I stop it? Can I send it a message to stop inserting images into the listbox if I switch directories? Looking at my code, what's the easiest way to implement that?
Thanks for the help!
Tags for this Thread
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|