CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 7 of 7

Hybrid View

  1. #1
    Join Date
    Oct 2009
    Posts
    8

    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!

  2. #2
    Join Date
    Oct 2009
    Posts
    8

    Re: Threading UI components

    Anyone?

  3. #3
    Join Date
    Jun 2008
    Posts
    2,477

    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.

  4. #4
    Join Date
    Oct 2009
    Posts
    8

    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?

  5. #5
    Join Date
    Oct 2009
    Posts
    8

    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?

  6. #6
    Join Date
    Jan 2006
    Location
    Fox Lake, IL
    Posts
    15,007

    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
    David

    CodeGuru Article: Bound Controls are Evil-VB6
    2013 Samples: MS CODE Samples

    CodeGuru Reviewer
    2006 Dell CSP
    2006, 2007 & 2008 MVP Visual Basic
    If your question has been answered satisfactorily, and it has been helpful, then, please, Rate this Post!

  7. #7
    Join Date
    Oct 2009
    Posts
    8

    Re: Threading UI components

    Quote Originally Posted by dglienna View Post
    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
  •  





Click Here to Expand Forum to Full Width

Featured