2011-10-07 103 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

相关问题