线程问题"调用线程无法访问此对象,因为不同的线程拥有它".有解决方案吗

Bas*_*mme 0 c# xaml multithreading

我有一个包含文件名的列表视图.我有另一个列表视图,其中包含重命名这些文件的可能操作.最后,我有一个标签,显示结果的预览.当在每个列表中选择一个对象时,我想显示预览.您只能选择一个文件,但只能选择一个或多个操作.我使用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();
    }
Run Code Online (Sandbox Code Playgroud)

在运行时我收到错误"调用线程无法访问此对象,因为另一个线程拥有它." 在FileData fileData = listViewFiles.SelectedItem上作为FileData; 线.你知道我该怎么办?

Ale*_*der 5

您无法从nonUI线程修改或访问UI.因此,如果您仍然想要使用不同的线程,您需要做的是添加某种模型(有关绑定和模型的更多信息,请尝试搜索"wpf mvvm"),然后将您绑定listViewFiles.SelectedItem到此模型的某些属性,这将允许您跨线程访问SelectedValue.其次,您需要将所有更改UI的逻辑分离到方法或使用lambda,最后它看起来像这样:

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); 
    } 
} 
Run Code Online (Sandbox Code Playgroud)

UPD.关于与UI同步的一些附加信息:在WPF中,每个UI对象都继承自DispatcherObject类.因此,只能从创建此对象的线程进行对此类对象的所有访问,如果要从另一个需要使用DO.Dispatcher.Invoke(Delegate)方法的线程访问DispatcherObject(DO),则会将代码排入DO线程.因此,总而言之,在UI线程中运行代码需要使用任何UI元素的Dipatcher,在这种情况下我们使用Window的Dispatcher(假设后面的窗口代码中的代码).