2011-10-07 25 views
-1

我有一個包含文件名的列表視圖。我有另一個列表視圖,其中包含可能的操作來重命名這些文件。最後,我有一個顯示結果預覽的標籤。當我想要顯示預覽的每個列表中選擇一個對象時。您只能選擇一個文件,但只能選擇一個或多個操作。我使用WPF/Xaml作爲我的UI。我選擇用線程執行預覽。線程問題「調用線程不能訪問此對象,因爲不同的線程擁有它」。任何解決方案

這裏是我的代碼的一部分:「因爲不同的線程擁有它調用線程不能訪問該對象」

private Thread _thread; 

    public MainWindow() 
    { 
     InitializeComponent(); 
     _thread = new Thread(DoWork); 
    } 

    public void DoWork() 
    { 
     while (true) 
     { 
      FileData fileData = listViewFiles.SelectedItem as FileData; // ERROR HERE 
      if (fileData != null) 
      { 
       string name = fileData.FileName; 
       foreach (var action in _actionCollection) 
       { 
        name = action.Rename(name); 
       } 
       previewLabel.Content = name; 
      } 
      Thread.Sleep(1000); 
     } 
    } 

    private void listViewFiles_SelectionChanged(object sender, SelectionChangedEventArgs e) 
    { 
     _thread.Start(); 
    } 

在運行時出現錯誤對FileData fileData = listViewFiles.SelectedItem作爲FileData;線。你知道我該怎麼做?

+0

http://stackoverflow.com/search?q=The+calling+thread+cannot+access+this+object+because+a+different+thread+owns+it –

回答

4

您無法從nonUI線程修改或訪問UI。所以,如果你仍然想要使用不同的線程,你需要做的第一件事是添加某種模型(關於綁定和模型的更多信息,請嘗試搜索「wpf mvvm」),然後綁定你listViewFiles.SelectedItem這個模型的某些屬性將允許您跨線程訪問SelectedValue。其次,你需要單獨改變用戶界面的方法的所有邏輯或最終使用拉姆達所以它可以是這樣的:

public void DoWork() 
{ 
    while (true) 
    { 
     FileData fileData = Model.SelectedValue; 
     if (fileData != null) 
     { 
      string name = fileData.FileName; 
      foreach (var action in _actionCollection) 
      { 
       name = action.Rename(name); 
      } 
      this.Dispatcher.Invoke((Action)()=> //use Window.Dispatcher 
      { 
       label3.Content = fileData.FileName; 
       label4.Content = name; 
      }); 
     } 
     Thread.Sleep(1000); 
    } 
} 

UPD。有關與UI同步的其他一些詞語:在WPF中,每個UI對象都繼承自DispatcherObject類。因此,只有從創建該對象的線程才能訪問此類型的對象,如果您想從另一個線程訪問DispatcherObject(DO),您需要使用DO.Dispatcher.Invoke(Delegate)方法,這會將您的代碼排隊到DO線程。因此,最後要在UI線程中運行代碼,您需要使用任何UI元素的Dipatcher,在這種情況下,我們使用窗口分派器(假設窗口代碼中的代碼在後面)。

+0

我認爲你的代碼有一個小錯誤,這個Dispatcher.Invoke但它幫助了我。我用這個:this.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal, 新動作(委託(){ label3.Content = fileData.FileName; label4.Content =名稱; })); –

+0

@Dran Dane hhmm ..我想我搞砸了大括號=)'調用((行動)*(*()=> {..} *)*);'應該工作 – Alexander

-1

簡單的答案是你不能這樣做:線程A不能直接訪問線程B創建的winforms對象(控件)。

在實踐中,你可以使用委託來對其他線程ALA安全運行這一點:

form.Invoke(new MethodInvoker(() => { 
     FileData fileData = listViewFiles.SelectedItem as FileData; // ERROR HERE 
     if (fileData != null) 
     { 
      string name = fileData.FileName; 
      foreach (var action in _actionCollection) 
      { 
       name = action.Rename(name); 
      } 
      previewLabel.Content = name; 
     } 
    })); 

但是,您可能希望只 使用背景工人:http://msdn.microsoft.com/en-us/library/8xs8549b.aspx

更詳細at:http://weblogs.asp.net/justin_rogers/pages/126345.aspx

+0

我的問題是在這一行上:FileData fileData = listViewFiles.SelectedItem作爲FileData; –

+0

原因是相同的 - 我已經更新了我的答案,以包裝整個Winforms對象「碰觸」 –

+1

我認爲我們討論的技術是WPF =) – Alexander

相關問題