2015-01-17 5 views
0

imagelist 및 listview를로드하면 UI가 조금씩 중단됩니다. 그래서 UI를로드하고 사용자가 작업하고 있다는 것을 알려주고 backgroundWorker가 그 일을하도록하십시오. formLoad를 호출하여 "backgroundWorker1.RunWorkerAsync();"를 호출했습니다.backgroundWorker를 사용하는 동안 ListView 및 ImageList로드 중

하지만 "크로스 스레드 작업이 유효하지 않습니다 : 컨트롤 'listView1'이 (가) 만들어진 스레드가 아닌 다른 스레드에서 액세스했습니다."

나는 조금 찌르고 코드를 조금 바꿔야한다는 것을 알았습니다. 그래서 내가 무엇을 가지고 :

(listView1.InvokeRequired)을 만족하고, listView1.invoke를 실행하는 경우
private void WatermarkPicker_Load(object sender, EventArgs e) 
    { 
     backgroundWorker1.RunWorkerAsync(); 
    } 


private void GetImages() 
    { 
     DirectoryInfo dir = new DirectoryInfo(@"c:\pics"); 
     this.listView1.View = View.LargeIcon; 
     this.imageList1.ImageSize = new Size(100, 100); 
     if (listView1.InvokeRequired) 
     { 
      listView1.Invoke(new MethodInvoker(
       () => this.listView1.LargeImageList = this.imageList1)); 
     } 
     else 
     { 
      this.listView1.LargeImageList = this.imageList1; 
     } 
     int j = 0; 
     foreach (FileInfo file in dir.GetFiles()) 
     { 
      try 
      { 
       //this.imageList1.Images.Add(Image.FromFile(file.FullName)); 
       imageList1.Images.Add(file.Name, Image.FromFile(file.FullName)); 
       ListViewItem item = new ListViewItem(file.Name); 
       item.Tag = file.Name; 
       item.ImageIndex = j; 
       this.listView1.Items.Add(item); 
       j++; 
      } 
      catch 
      { 
       Console.WriteLine("This is not an image file"); 
      } 
     } 
    } 

    private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) 
    { 
     GetCurrentLogos(); 
     GetImages(); 
    } 

. 그러나 UI의 listView에는 아무 것도 표시되지 않습니다. 오류는 없습니다.

답변

2

당신은 DoWork 이벤트 외부 목록보기과의 ImageList에 액세스하고 DoWork 코드 내부에서 제기 된 ProgressChanged 이벤트를 사용하려고 모든 코드를 이동해야합니다.

이렇게하면 ProgressChanged 이벤트의 코드가 올바른 UI 스레드에서 실행됩니다 (BackgroundWorker가 UI 스레드에서 만들어진 것으로 가정). 예를 들어

는 :

private void WatermarkPicker_Load(object sender, EventArgs e) 
{ 
    listView1.View = View.LargeIcon; 
    listView1.LargeImageList = imageList1; 

    backgroundWorker1.WorkerReportsProgress = true; 
    backgroundWorker1.ProgressChanged += backgroundWorker1_ProgressChanged; 
    backgroundWorker1.DoWork += backgroundWorker1_DoWork; 
    backgroundWorker1.RunWorkerAsync(); 
} 

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) 
{ 
    // Do not try to use in any way an object derived from Control 
    // like the ListView when you are inside the DoWork method..... 
    BackgroundWorker worker = sender as BackgroundWorker; 
    DirectoryInfo dir = new DirectoryInfo(@"c:\pics"); 
    foreach (FileInfo file in dir.GetFiles()) 
    { 
     // You can't use imageList here 
     // imageList1.Images.Add(file.Name, Image.FromFile(file.FullName)); 

     // Raise the ProgressChanged event. 
     // The code there will execute in the UI Thread 
     worker.ReportProgress(1, file);   
    } 
} 

private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e) 
{ 
    // This code executes in the UI thread, no problem to 
    // work with Controls like the ListView 
    try 
    { 
     FileInfo file = e.UserState as FileInfo; 
     imageList1.Images.Add(file.Name, Image.FromFile(file.FullName)); 
     ListViewItem item = new ListViewItem(file.Name); 
     item.Tag = file.Name; 
     item.ImageIndex = imageList1.Images.Count - 1; 
     listView1.Items.Add(item); 
    } 
    catch(Exception ex) 
    { 
     .... 
    } 
} 
+1

나는 UI를 업데이트 할 ProgressChange를 사용하는 접근 방식을 좋아한다. 그러나 UI 스레드에서 Image.FromFile을 사용하면 최종 사용자의 작업 속도가 느려질 수 있습니다. –

+0

"크로스 스레드 작업이 유효하지 않습니다 : 컨트롤 'listView1'이 (가) 만들어진 스레드 이외의 스레드에서 액세스되었습니다." ImageList.Image.Add가 DoWork에있을 때 추가 ... –

+0

이제 Visual Studio에서 확인했습니다. 효과적으로 많은 수의 이미지 세트에서 크로스 스레드 예외가 발생합니다. 따라서 가능한 유일한 해결 방법은 ProgressChanged 이벤트에서 ImageList.Add를 이동하는 것입니다. 이 문제를 해결할 수 있지만 파일 목록 위에 루프를 끝낼 때까지 ListView 업데이트되지 않습니다. – Steve

0

기본 스레드에서해야하는 것처럼 백그라운드 작업자가 원하는대로 실행할 수 있습니다. 그러나 UI 구성 요소에 액세스 할 때마다 주 스레드 (UI 스레드라고도 함)에서 수행해야합니다.

Application.Current.Dispatcher.Invoke(new Action(() => { /* Your code here */ })); 
0

당신 해야 UI 스레드에서 액세스 ListViewImageList : 당신이 등 WPF와

WPF, 윈도우 폰, 자 마린, 아래에서 작업하는 경우 구문은 따라, 다음과 같은 식으로되어 있어야한다 배경 작업자 스레드가 아닙니다.

UI 스레드에서 실행되는 WatermarkPicker_Load으로 초기화 논리를 옮기고 Control.Invoke을 사용하도록 foreach 루프를 변경하는 것이 좋습니다.

foreach (var file in dir.GetFiles()) 
{ 
    var image = Image.FromFile(file.FullName); 
    var item = new ListViewItem(file.Name) 
    { 
     Tag = file.Name; 
    } 
    listView1.Invoke(() => 
    { 
     imageList1.Images.Add(file.Name, image); 
     listView1.Items.Add(item); 
    }); 
} 
관련 문제