调用线程无法访问此对象,因为另一个线程拥有它(在 v4.5 中)
The calling thread cannot access this object because a different thread owns it (in v4.5)
我知道已经有很多人问了这个问题。但是提供的关于委托的解决方案并不是我要使用我的代码的解决方案,因为我正在使用 4.5 版本并且看起来 Dispatcher 方法略有变化。除此之外,我在将近十年后第一次接触 dotnet 和 c#。
我在我的 WPF 项目中实际要做的是在主 window 中附加文本框的文本以显示 status/log。这是在名为 Logger
的单例 class 中 这个 class 的主要静态函数是 log() ,它接受一个字符串,需要用一个简单的行
txt.AppendText(msg);
经过一番研究后,我将其更改为
Dispatcher.CurrentDispatcher.Invoke(() =>
{
txt.AppendText(msg);
});
但我仍然得到同样的错误。这里出了什么问题?还有什么事可做吗?因为我从 FileSystemEventHandler
内部另一个单身人士 class.
调用这个 Logger.log()
private void somethingChanged(object sender, FileSystemEventArgs e)
{
Logger.log("File: " + e.FullPath + " " + e.ChangeType);
}
下面是我的Logger
class
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);
});
}
}
}
这是我的主要 window,只有一个名为 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 class,它有 FileSystemWatcher 对象来继续监视其中一个文件夹,每当该文件夹内发生某些事情时,如 adding/deleting 文件和重命名文件都需要记录在其中文本框。
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,这不是你想要的。
我知道已经有很多人问了这个问题。但是提供的关于委托的解决方案并不是我要使用我的代码的解决方案,因为我正在使用 4.5 版本并且看起来 Dispatcher 方法略有变化。除此之外,我在将近十年后第一次接触 dotnet 和 c#。
我在我的 WPF 项目中实际要做的是在主 window 中附加文本框的文本以显示 status/log。这是在名为 Logger
的单例 class 中 这个 class 的主要静态函数是 log() ,它接受一个字符串,需要用一个简单的行
txt.AppendText(msg);
经过一番研究后,我将其更改为
Dispatcher.CurrentDispatcher.Invoke(() =>
{
txt.AppendText(msg);
});
但我仍然得到同样的错误。这里出了什么问题?还有什么事可做吗?因为我从 FileSystemEventHandler
内部另一个单身人士 class.
Logger.log()
private void somethingChanged(object sender, FileSystemEventArgs e)
{
Logger.log("File: " + e.FullPath + " " + e.ChangeType);
}
下面是我的Logger
class
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);
});
}
}
}
这是我的主要 window,只有一个名为 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 class,它有 FileSystemWatcher 对象来继续监视其中一个文件夹,每当该文件夹内发生某些事情时,如 adding/deleting 文件和重命名文件都需要记录在其中文本框。
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,这不是你想要的。