2014-02-08 25 views
0

我想使用Mutli線程保存所有UserControl作爲圖像在同一時間想要顯示動畫視圖屏幕上,但有一個錯誤:使用多線程保存UserControls作爲圖像的錯誤是:調用線程不能訪問這個對象,因爲不同的線程擁有它

The calling thread cannot access this object because a different thread owns it.

這是我的代碼:

private void OnScreenShotAllCommandExecuted(object parameter) 
{ 
    string filePath = @"D:\ScreenShot\"; 
    IList<UserControl> userControls = LayoutRoot.Children.OfType<UserControl>().ToList(); 
    List<Thread> tasks = new List<Thread>(); 
    AnimationView animationView = new AnimationView(); 
    animationView.Show(); 

    foreach (UserControl userControl in userControls) 
    { 
     string viewName = userControl.Name; 
     string fileName = userControl.Name + ".png"; 
     if (viewName != null) 
     { 
      Thread thread = new Thread(() => 
      { 
       Thread.Sleep(1000); 
       SaveView(userControl, fileName, filePath); 
       ThreadHasFinished(); 
      }); 
      tasks.Add(thread); 
      thread.SetApartmentState(ApartmentState.STA); 
      thread.Start(); 
     } 
    } 
} 

private void ThreadHasFinished() 
{ 
    Interlocked.Increment(ref finishedControls); 

    Dispatcher.BeginInvoke((Action)(() => 
    { 
     animationView.Close(); 

    })); 

} 

public static void SaveView(UserControl userControl, string fileName, string destFolder) 
{ 
    Rect bounds = VisualTreeHelper.GetDescendantBounds(userControl); 

    int width = (int)view.RenderSize.Width; 
    int height = (int)view.RenderSize.Height; 

    RenderTargetBitmap rtb = new RenderTargetBitmap(width, height, 96, 96, PixelFormats.Pbgra32); 

    DrawingVisual dv = new DrawingVisual(); 
    using (DrawingContext ctx = dv.RenderOpen()) 
    { 
     VisualBrush vb = new VisualBrush(userControl); 
     ctx.DrawRectangle(vb, new Pen(Brushes.Blue, 2), new Rect(new Point(0, 100), size)); 
    } 
    rtb.Render(dv); 
    PngBitmapEncoder png = new PngBitmapEncoder(); 
    png.Frames.Add(BitmapFrame.Create(rtb)); 

    using (Stream fileStream = new FileStream(string.Format("{0}\\{1}.png", destFolder, fileName), FileMode.Create)) 
    { 
     png.Save(fileStream); 
    }   
} 

錯誤

The calling thread cannot access this object because a different thread owns it.

在這一行

Rect bounds = VisualTreeHelper.GetDescendantBounds(userControl);

回答

3
Thread thread = new Thread(() => 
        { 
         Thread.Sleep(1000); 
         SaveView(userControl, fileName, filePath); 
         ThreadHasFinished(); 
        }); 

在您所呼叫SaveView(userControl, fileName, filePath)這是錯誤的,因爲在主線程WPF UI更新上面的代碼。

對於響應式UI,而不是直接創建線程,我建議您在這種情況下使用BackgroundWorker。您將有主要線程中的RunWorkerCompleted事件,因此您可以在其中更新任何UIElement。和昂貴的東西,你可以運行在DoWork事件。 DoWork在線程池的後臺線程上運行。

+0

嗨,Mukesh Rawat 我試圖使用BackgroundWorker,但我不知道如何使用BackgroundWorker,因爲我是WPF多線程中的新手。你能幫我做一個關於我的問題的演示嗎? 非常感謝提前。 – user3286132

1

您可以使用this作爲更好的示例。這是一個非常基礎的教程,您將在其中學習如何使用它。你也會在谷歌上獲得關於如何使用BW的樣本數量。

+0

你可以幫我使用BackgrounWorker基於我的代碼,我不知道如何用戶BackgroundWorker,我試圖使用BackgroundWorker但錯誤也顯示 – user3286132

0

許多UI框架(包括WPF和Windows窗體)的一般設計原則是線程關聯。具體而言,創建 UI元素的線程僅爲線程可以與其交互

如果您嘗試直接與具有多個不同線程的UI元素進行交互,那麼您的設計基本上存在缺陷。

請注意,任何不直接與用戶控件交互的可能運行在不同線程上的。磁盤I/O等,例如

要在您的工作線程和UI線程之間進行編組(99%的基本應用程序只有一個UI線程),請使用工作線程中的元素調度程序。 Dispatcher將允許您將請求排隊到ui線程並獲得結果。閱讀MSDN瞭解更多詳情。

相關問題