【问题标题】:InvalidOperationException when assigning text to a TextField将文本分配给 TextField 时出现 InvalidOperationException
【发布时间】:2010-06-25 17:46:06
【问题描述】:

我在使用 C# 时遇到了一个奇怪的问题,我还无法解释。我实际上计划创建一个简单的文件查看器,它会在文件更改后自动更新显示的文本,但结果比我想象的要复杂。

我有以下基本代码:

public partial class Main : Window
{
    private FileSystemWatcher watcher;
    private String filePath = "C:\\";
    private String fileName = "example.txt";

    public Main()
    {
        InitializeComponent();

        this.txtFile.Text = File.ReadAllText(filePath + fileName);

        this.watcher = new FileSystemWatcher(filePath);
        this.watcher.Changed += new FileSystemEventHandler(watcher_Changed);
        this.watcher.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite;
        this.watcher.Filter = fileName;
        this.watcher.EnableRaisingEvents = true;
    }

    void watcher_Changed(object sender, FileSystemEventArgs e)
    {
        String text = File.ReadAllText(e.FullPath);
        this.txtFile.Text = text; // <-- here comes the exception (line 42)
    }
}

现在在更改的处理程序中对 (WPF) TextField 的赋值引发了System.InvalidOperationException 异常,告诉我该对象已在不同的线程中使用。那么为什么我会得到这个异常,更重要的是,我必须做什么才能使其正常工作?

编辑

顺便说一句,无论我分配什么字符串,我都会遇到异常。

编辑2

异常的全文,但用德语:

System.InvalidOperationException wurde nicht behandelt。 Message="Der aufrufende Thread kann nicht auf dieses Objekt zugreifen, da sich das Objekt im Besitz eines anderen Threads befindet。" 来源="WindowsBase" 堆栈跟踪: 北 System.Windows.Threading.Dispatcher.VerifyAccess() bei System.Windows.DependencyObject.SetValue(DependencyProperty dp,对象值) bei System.Windows.Controls.TextBox.set_Text(字符串值) bei LiveTextViewer.Main.watcher_Changed(Object sender, FileSystemEventArgs e) in ...\Main.xaml.cs:Zeile 42。 北 System.IO.FileSystemWatcher.CompletionStatusChanged(UInt32 errorCode,UInt32 numBytes,NativeOverlapped* 重叠指针) 北 System.Threading._IOCompletionCallback.PerformIOCompletionCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* pOVERLAP) 内部异常:

【问题讨论】:

  • 您不能从单独的线程分配 UI 对象的 Text 属性,至少不能直接分配。我会避免回答,因为我推荐的方法是 WPF 之前的方法,但我相信你会得到答案。

标签: c# wpf


【解决方案1】:

FileSystemWatcher 正在另一个线程上引发此事件。您不能从与创建它的线程不同的线程访问用户界面元素。

您需要使用 Dispatcher 将设置文本的调用推送回 UI 线程:

void watcher_Changed(object sender, FileSystemEventArgs e)
{
    String text = File.ReadAllText(e.FullPath);

    this.Dispatcher.Invoke(DispatcherPriority.Normal, new Action(() => 
        {
             this.txtFile.Text = text;
             // Do all UI related work here...
        }));
}

【讨论】:

  • 感谢您的回答;也许只是我(或另一个缺少的导入?这至少可以解释 Invoke 缺少的所有 IntelliSense 详细信息),但这不起作用:它表示 lambda 表达式无法转换为 System.Delegate。
  • @poke:对不起 - 我忘了把演员表放到(Action)。 Dispatcher.Invoke 采用“System.Delegate”,因此您必须指定一些具体的委托类型。以上应该现在可以工作了。
  • 在 lambda 周围加上另一对括号后,它确实可以编译和工作,而且完全有意义。非常感谢:)
  • 现在 .NET 4 已经发布了一段时间,我认为是时候开始温和地将人们推向 Task 并远离 DispatcherISynchronizeInvoke。我最近在这个主题上wrote a blog post(它使用嵌套的Task 来更新用户界面)。你怎么看?
  • @Stephen:在大多数情况下,我同意 - 但是,为了在这里使用任务,您必须在类中存储任务调度程序或同步上下文的副本。否则,需要重构上面的代码以使用 lambda 作为处理程序(这只会改变编译器的存储负担)。我非常喜欢使用 Tasks 进行新开发,但与遗留组件交互并不总是那么容易,尤其是那些已经使用回调或事件的组件。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-05-06
  • 1970-01-01
  • 2017-03-08
  • 1970-01-01
  • 2013-03-21
  • 2018-10-22
  • 2013-01-29
相关资源
最近更新 更多