【问题标题】:Dispatcher Locking UI调度程序锁定 UI
【发布时间】:2012-08-28 16:11:56
【问题描述】:

我在 WPF 中使用 MVC 模型,但在锁定 UI 时遇到了困难。该应用程序正在两个端点之间进行通信,并且 UI 有一个 TextBox,我将详细的通信日志写入该文本框。代码可以一次发送单个文件或多个文件。

我有一个用于处理日志的特定日志记录类,因为它们需要创建、格式化和写入磁盘。我将 TextBox 传递给 Logging 类,然后使用 Dispatcher 对其进行写入,但是当我同时写入多个日志时,UI 会锁定。如果我只从一个发送的文件中写入日志,一切正常。

我尝试添加线程锁,但这似乎无法解决任何问题。我什至锁定了整个写入过程(处理信息、写入磁盘和写入 UI),但仍然遇到相同的锁定问题。

下面列出了我用来写入 UI 的代码:

    /// <summary>
    /// Post the message to the UI.
    /// </summary>
    /// <param name="message">Message to post.</param>
    /// <param name="scrollToEnd">Scroll to the end of the Text Box if true</param>
    private void PostMessage(String message, bool scrollToEnd)
    {
        LoggingBox.Dispatcher.BeginInvoke(
            System.Windows.Threading.DispatcherPriority.Normal,
            new Action(delegate()
                {
                    LoggingBox.AppendText(message);
                    if (scrollToEnd)
                        LoggingBox.ScrollToEnd();
                }
            ));
    }

LogBox 只是一个文本框:

    /// <summary>
    /// Location for logs to be displayed.
    /// </summary>
    public TextBox LoggingBox { get; set; }

这是我第一次使用 WPF,所以我确信我犯了一个简单的错误。任何见解将不胜感激。

【问题讨论】:

  • 你能添加你的 LoggingBox 代码吗?

标签: c# wpf dispatcher


【解决方案1】:

我要更改的第一件事是将调度程序调用中的优先级设置为后台,这意味着日志更改请求仅在 UI 完成所有其他杂务时才得到处理。否则,您可以尝试在 StringBuilder 中收集日志条目,并且每秒钟左右更新一次 UI,以节省昂贵的屏幕更新。

【讨论】:

    【解决方案2】:

    Dispatcher 只是主 UI 线程。它允许您在不同的DispatcherPriorities 安排进程以影响任务运行的时间,但是它仍然是一个线程,并且对其进行任何繁重的处理仍会锁定您的 UI。

    因此,所有繁重的处理都应该在另一个线程上完成,并且只有在 UI 线程上确实需要完成某些事情时才传递给调度程序线程。

    我实际上建议更新string 属性并将TextBox.Text 绑定到您的字符串,而不是直接更新TextBox。这将允许您在另一个线程中进行所有处理,而完全不用担心Dispatcher

    此外,默认情况下,TextBox 具有设置为 true 的 IsUndoEnabled 属性。这使它保留了对文本的所有更改的历史记录,因此您可以使用撤消/重做热键。如果您不想切换到绑定,至少在您的TextBox 上设置IsUndoEnabled=false

    最后,像 hbarck said 一样,将您的 DispatcherPriority 切换到更低的值,例如 DispatcherPriority.Background

    【讨论】:

    • 虽然我同意绑定通常是要走的路,但在日志可能会变得很长并且只会附加到的特殊情况下,我也在使用 AppendText,因为它是速度更快,并且不需要丢弃并重新渲染 TextBox 的完整内容。
    • @hbarck 好的,在这种情况下,我建议确保将 IsUndoEnabled 属性设置为 false。我曾经在similar situation 中作为OP 将日志事件写入TextBox,并且我的应用程序占用了大量内存,因为每次更改时该属性都会存储整个TextBox.Text 值制作。
    • 感谢您的宝贵建议。我确实将 IsUndoEnabled 明确更改为 false,但我认为它以前就在那里。我还将 DispatcherPriority 设置为 Background。但是,UI 仍然挂起。日志在进入时也被写入数据文件,但我还没有找到绑定到文件的方法。确实,有时我可能每秒写数百行,而日志在被裁剪之前会增长到数千行。再次感谢您的建议,我欢迎任何进一步的意见。
    • @Tim 出于好奇,如果您写信给string 而不是TextBox,您会遇到同样的问题吗?我想知道冻结是由TextBox 还是由过程中的其他原因引起的。
    • @Rachel 否。为了避免在处理其他问题时锁定,我注释掉了调用此方法的行,它运行良好。问题肯定出在 UI 更新上。
    【解决方案3】:

    通过代码并禁用各个部分后,我意识到发布到 UI 并不是导致 UI 冻结的原因。完成大部分工作的对象之一并没有被原始开发人员放在单独的线程上。创建线程后,UI 停止冻结。

    感谢所有提供帮助的人。这里的社区很棒!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-01-22
      • 1970-01-01
      • 2014-07-28
      • 2016-10-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多