调用线程无法访问此对象,因为其他线程拥有它(在v4.5中)



我知道已经有很多问题被问到了。但是,提供的有关委派的解决方案并不是我要使用代码的内容,因为我正在使用4.5版本,而且Dispatcher方法似乎略有更改。除此之外,近十年后,我第一次接触到了互联网。

在我的WPF项目中,我实际要做的是将文本框的文本附加到主窗口中,以显示状态/日志。这是在名为Logger的singleton类中。这个类的主要静态函数是log((,它接受一个字符串,该字符串需要用一行添加到文本框中

txt.AppendText(msg);

做了一些研究后,我把它改成了

       Dispatcher.CurrentDispatcher.Invoke(() =>
        {
                txt.AppendText(msg);
        });

但我还是犯了同样的错误。这里出了什么问题?还有别的事要做吗?因为我在另一个singleton类内部从FileSystemEventHandler调用这个Logger.log()

private void somethingChanged(object sender, FileSystemEventArgs e)
{
    Logger.log("File: " + e.FullPath + " " + e.ChangeType);
}

下面是我的Logger

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Controls;
using System.Windows.Threading;
using System.Threading;
namespace httpclientui.comps
{
    class Logger
    {
        private static TextBox txt;
        private Logger() { }
        public static void setup(TextBox t){
            txt = t;
        }
        public static void clear()
        {
            if (txt == null)
            {
                return;
            }
            txt.Clear();
        }
        public static void log(String msg, bool addNewLineChar = true)
        {
            if (txt == null)
            {
                return;
            }
            Dispatcher.CurrentDispatcher.Invoke(() => {
                txt.AppendText(msg);
            });
        }
    }
}

这是我的主窗口,只有一个名为txtMessage的文本框控件。

    public partial class MainWindow : Window
    {
        private String folderToWatch;
        public MainWindow()
        {
            InitializeComponent();
            initialize();
        }
        private void initialize()
        {
            Logger.setup(txtMessage);
            Logger.clear();
            Logger.log("Launched");
            folderToWatch = "E:\folder\subfolder";
            Watcher.Instance.setup(folderToWatch);
            Watcher.Instance.start();
        }
    }
}

下面是我的Watcher类,它有FileSystemWatcher对象来监视其中一个文件夹,每当该文件夹内发生诸如添加/删除文件和重命名文件之类的事情时,都需要记录在该文本框中。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
namespace httpclientui.comps
{
    class Watcher
    {
        private String path;
        //https://msdn.microsoft.com/en-us/library/system.io.filesystemwatcher(v=vs.110).aspx
        private FileSystemWatcher dog;
        private static Watcher instance;
        private Watcher()
        {
            //dog = new FileSystemWatcher()
        }
        public static Watcher Instance
        {
            get
            {
                if (instance == null)
                {
                    instance = new Watcher();
                }
                return instance;
            }
        }
        public void setup(String folderPath)
        {
            path = folderPath;
            dog = new FileSystemWatcher(folderPath);
            Logger.log("setting up to watch folder: " + folderPath);
            dog.Changed += new FileSystemEventHandler(somethingChanged);
            dog.Created += new FileSystemEventHandler(somethingChanged);
            dog.Deleted += new FileSystemEventHandler(somethingChanged);
            dog.Renamed += new RenamedEventHandler(somethingRenamed);
        }
        public void start()
        {
            Logger.log("starting to watch folder");
            dog.EnableRaisingEvents = true;
        }
        public void pause()
        {
            dog.EnableRaisingEvents = false;
        }
        public void stop()
        {
            dog.EnableRaisingEvents = false;
        }
        private void somethingChanged(object sender, FileSystemEventArgs e)
        {
            Logger.log("File: " + e.FullPath + " " + e.ChangeType);
        }
        private void somethingRenamed(object sender, RenamedEventArgs e)
        {
            Logger.log("File: " + e.OldFullPath + " renamed to " + e.FullPath);
        }
    }
}

乍一看,您似乎没有将Clear()方法调用编组到Dispatcher。这就是可能引发异常的原因-对DispatcherObjects(包括所有控件(的所有访问都必须由Dispatcher线程完成。

此外,您希望使用Application.Current.Dispatcher,而不是Dispatcher.CurrentDispatcher。后者只是在当前(后台(线程上启动一个新的Dispatcher,这不是您想要的。

最新更新