2

Windowsフォームにこの機能があり、作業をWPFに転送しようとしています。転送後、WPFでサポートされていないInvokeRequiredことに気付きました。BeginInvoke関数を 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をブロックし、適切に更新する手段を提供しないため、UIで何かが更新されるのを防ぐことができます。古いWinFormsコードではDoEvents()、メッセージを処理するを呼び出しました(ただし、多くの理由から非常に悪い考えです)。その呼び出しがないと、これは正しく機能しません。

UIスレッドでのブロックやループを回避するようにしてください。代わりに、バックグラウンドスレッドで作業を行い、UIスレッドを正常に実行させてください。 BackgroundWorkerTPLのオプションの多くがそうであるように、これははるかに簡単になります。

于 2013-01-23T01:35:39.387 に答える
0

Reed Copsey が質問に対する完全な回答を提供しました。ただし、実際には WPF ではこれは必要ないことを指摘しておきます。通常、MVVMパターンを介しINotifyPropertyChangedてxamlデータバインディングを使用すると、自動的に処理されます。コレクションを同期する場合は、マルチスレッドの観察可能なコレクションを使用できます。これは私が自分で使用するソースコードです。

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 に答える