2

I have this function in my Windows Form and now I'm trying to transfer my work to WPF, After transferring I notice that InvokeRequired and BeginInvoke are not supported by WPF. I'm looking for the correct way to translate my function into 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
}

Here is my Thread Loop in my main class :

    while (bWaiting == true)
        {

            //System.Windows.Forms.Application.DoEvents();  // i comment it because i cant find equivalent in WPF
            System.Threading.Thread.Sleep(15);
        }
  • I have edited your title. Please see, "[Should questions include “tags” in their titles?](http://meta.stackexchange.com/questions/19190/)", where the consensus is "no, they should not". – John Saunders Jan 23 '13 at 01:45
  • Note that you should virtually never need `InvokeRequired` in a UI environment. You should always know whether some code is in the UI thread or not. If you know you're in a background thread, use `Invoke` (or `BeginInvoke`) if you're not, don't. If you're really unsure (which should be rare) then just `Invoke` anyway, because the method works just fine if you're already in the UI thread. – Servy Jan 23 '13 at 05:11

2 Answers2

3

The equivelents in WPF are Dispatcher.CheckAccess and Dispatcher.BeginInvoke:

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

Edit:

The reason your RichTextBox never updates is that you're blocking the UI thread:

    while (bWaiting == true)
    {

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

This will prevent anything from ever updating in the UI, as you're blocking it and never providing a means for it to update properly. In your old Win Forms code, you called DoEvents(), which processed the messages (but is a very bad idea for many reasons). Without that call, this will not work properly.

You should try to avoid blocking and looping in the UI thread - instead, do your work in a background thread, and let the UI thread run normally. BackgroundWorker makes this far simpler, as does many of the options in the TPL.

Reed Copsey
  • 554,122
  • 78
  • 1,158
  • 1,373
  • @AlexanderaMacQueen Have you checked to make sure this is getting called via the debugger? – Reed Copsey Jan 23 '13 at 01:49
  • yes i check it and seems its work exactly same as Windows form how ever in WPF doesnt show me any text – Alexandera MacQueen Jan 23 '13 at 01:51
  • @AlexanderaMacQueen Can you edit your question to show your current verion's exact code? – Reed Copsey Jan 23 '13 at 01:54
  • @AlexanderaMacQueen Edited to explain why this is broken. – Reed Copsey Jan 23 '13 at 02:18
  • Thanks Reed i do understand this was not a good idea , however now in WPF i dont really know how o convert this into background work :( – Alexandera MacQueen Jan 23 '13 at 02:54
  • @AlexanderaMacQueen The same way you should have done it in a winform application. There are tens of thousands of articles online showing how to process a long running task in a background thread. Look some examples up, try them out, experiment, and if you have problems, then come to SO and show the code that you're using and describe the problem(s) you're seeing. – Servy Jan 23 '13 at 05:12
0

Reed Copsey Gave you the complete answer to you question. However, I just want to point out that actually you don't need this in WPF. Usually it is automatically handled when you use MVVM pattern via INotifyPropertyChanged and xaml databinding. In case of synchronizing the collections you could use Multithreaded observable collection. This is the source code I use myself.

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);
        }
    }
}

(It comes somewhere from here, stackoverflow.com but couldn't find the source, by now)

Then you simply define your ViewModels and start changing the values. This is the most suitable, right and fast way of developing WPF applications.

Oybek
  • 7,016
  • 5
  • 29
  • 49
  • Oybek im not gonna use MVVM for now... but the problem is i change it to what Reed told me Still not text showing in my Richbox! – Alexandera MacQueen Jan 23 '13 at 01:48
  • Does it throw exception like `Cannot modify because it was created in different thread than in UI thread`? – Oybek Jan 23 '13 at 01:49
  • No exception, it goes inside the function and seems all flow are alright! how ever i have one sleep thread that i comment it because i can find equivalent for in in WPF : while (bWaiting == true) { //System.Windows.Forms.Application.DoEvents(); System.Threading.Thread.Sleep(15); } Is that anything to do with this? – Alexandera MacQueen Jan 23 '13 at 01:52
  • Let's put it this way. Does `DisplayinRichbox` get called? – Oybek Jan 23 '13 at 01:56
  • Furthermore, I tried to use this construct: `private void AddText() { Dispatcher.Invoke(new Action(() => rtbTest.AppendText("Hello world"))); }`. Works out perfectly in both, async and sync methods. No need to check weather it should be dispatched or called directly – Oybek Jan 23 '13 at 01:58