2

我在我的 Windows 窗体中有这个功能,现在我正在尝试将我的工作转移到 WPF,转移后我注意到InvokeRequired并且BeginInvokeWPF 不支持。我正在寻找将我的函数转换为 WPF 的正确方法:

delegate void DisplayInvoker(string text, MessageType type);

private void DisplayinRichbox(string text, MessageType type = MessageType.Normal)
{
    if (this.InvokeRequired)  // not support by WPF
    {
        this.BeginInvoke(new DisplayInvoker(DisplayinRichbox), text, type); // Not support by WPF
        return;
    }
    txt_Log.AppendText(String.Format("[{0}]   {1}{2}\r\n",
    DateTime.Now, type == MessageType.Incoming ? "<< " : type == MessageType.Outgoing ? ">> " : "", text));
    txt_Log.ScrollToCaret();   // not support by WPF
}

这是我的主课中的线程循环:

    while (bWaiting == true)
        {

            //System.Windows.Forms.Application.DoEvents();  // i comment it because i cant find equivalent in WPF
            System.Threading.Thread.Sleep(15);
        }
4

2 回答 2

3

WPF 中的等效项是Dispatcher.CheckAccessDispatcher.BeginInvoke

if (!this.Dispatcher.CheckAccess())
{
    this.Dispatcher.BeginInvoke(new Action(() => DisplayInRichbox(text, type)));
    return;
}

编辑:

RichTextBox从不更新的原因是您阻塞了 UI 线程:

    while (bWaiting == true)
    {

        //System.Windows.Forms.Application.DoEvents();  // i comment it because i cant find equivalent in WPF
        System.Threading.Thread.Sleep(15);
    }

这将阻止 UI 中的任何内容更新,因为您正在阻止它并且永远不会为其提供正确更新的方法。在旧的 Win Forms 代码中,您调用DoEvents()了 ,它处理了消息(但由于许多原因,这是一个非常糟糕的主意)。没有那个电话,这将无法正常工作。

您应该尽量避免 UI 线程中的阻塞和循环 - 相反,在后台线程中执行您的工作,并让 UI 线程正常运行。 BackgroundWorker与 TPL 中的许多选项一样,这使这变得简单得多。

于 2013-01-23T01:35:39.387 回答
0

Reed Copsey 为您的问题提供了完整的答案。但是,我只想指出,实际上您在 WPF 中不需要这个。通常,当您通过INotifyPropertyChanged和 xaml 数据绑定使用 MVVM 模式时,它会自动处理。如果要同步集合,您可以使用多线程可观察集合。这是我自己使用的源代码。

public class MultiThreadedObservableCollection<T> : ObservableCollection<T> {
    public override event NotifyCollectionChangedEventHandler CollectionChanged;
    public MultiThreadedObservableCollection() { }
    public MultiThreadedObservableCollection(IEnumerable<T> source) : base(source) { }
    public MultiThreadedObservableCollection(List<T> source) : base(source) { }

    protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e) {
        var handle = CollectionChanged;
        if (CollectionChanged == null)
            return;
        foreach (NotifyCollectionChangedEventHandler handler in handle.GetInvocationList()) {
            var dispatcherObj = handler.Target as DispatcherObject;
            if (dispatcherObj != null) {
                var dispatcher = dispatcherObj.Dispatcher;
                if (dispatcher != null && !dispatcher.CheckAccess()) {
                    dispatcher.BeginInvoke(
                        (Action)(() => handler.Invoke(
                            this,
                            new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset))
                        ), DispatcherPriority.DataBind);
                    continue;
                }
            }
            handler.Invoke(this, e);
        }
    }
}

(它来自这里的某个地方,stackoverflow.com,但现在找不到源)

然后,您只需定义您的 ViewModel 并开始更改值。这是开发 WPF 应用程序最合适、最正确、最快捷的方式。

于 2013-01-23T01:45:36.017 回答