0

Let's say I have this class with the RaiseProperyChanged attribute from PostSharp:

[NotifyPropertyChanged]
public class MainViewModel
{
    public int RandInt { get; set; }

    public MainViewModel()
    {
        RandInt = 10;
        new Task(TaskStart).Start();
    }

    private void TaskStart()
    {
        Random rand = new Random();
        while (true)
        {
            RandInt = rand.Next(9999);
        }
    }
}

Binding RandInt to a label or other control wil result in no change of the label. This means that the value of the label will be 10 all the time because the property is changed from another thread. How to handle this strange behaviour? Doing this with MVVM Light with RaisePropertyChanged() in the setter of the property works fine.

Christian Klemm
  • 1,455
  • 5
  • 28
  • 49
  • This may be a duplicate of http://stackoverflow.com/questions/17065810/asynchronous-ui-update-from-viewmodel-in-wpf – joncloud Apr 18 '16 at 00:52
  • Please let us know if the (possible) duplicate gives you the answer. – Antonín Procházka Apr 18 '16 at 14:04
  • Of course not because this question has nothing to do with mine. Mine is explicit about PostSharp... However I already did a bug report and I'm waiting for the result – Christian Klemm Apr 18 '16 at 14:10
  • I reported this as a bug over here: http://support.sharpcrafters.com/discussions/problems/3137-raisepropertychanged-on-porperty-updated-in-another-thread-is-not-called – Christian Klemm Apr 19 '16 at 05:19

1 Answers1

1

This is a design consequence of PostSharp. The problem is that the method TaskStartinstrumented by the aspect [NotifyPropertyChanged] flushes the event queue in the end, but this method does not ever end.

This will be addressed in a future version of PostSharp. In the meanwhile, you can use method NotifyPropertyChangedServices.RaiseEventsImmediate(). See the example:

[NotifyPropertyChanged]
public class MainViewModel
{
    public int RandInt { get; set; }

    public MainViewModel()
    {
        RandInt = 10;
        new Task(TaskStart).Start();
    }

    private void TaskStart()
    {
        Random rand = new Random();
        while (true)
        {
            AsyncRandomNumber = random.Next( 9999 );

            // Raise the events now, because the method TaskStart never ends.
            NotifyPropertyChangedServices.RaiseEventsImmediate( this );
        }
    }
}
Antonín Procházka
  • 1,388
  • 8
  • 16
  • I would be careful with that, you are going to flood the message queue if you don't await the the `InvokeAsync` It would be probably a better idea to do `dispatcher.Invoke(` instead. Also, you probibly will want to pass in a `DispatcherPriority.Input` too so it is the same priority as inputs (5) instead of the default (9), higher numbers go first. – Scott Chamberlain Apr 19 '16 at 16:19
  • It's basically not true that WPF doesn't reacts to changes done in a different thread. Doing this with the common (non AOP) implementation with RaisePropertyChanged (using MVVM Light or even self written) would work. It's an issue related to PostSharp and not to WPF. As it was already reported in the past I think it is still not fixed, – Christian Klemm Apr 19 '16 at 16:28
  • @chris579: You are right. We have investigated more and found the real reason why this code does not work. Sorry for that, I have updated my answer. – Antonín Procházka Apr 20 '16 at 08:52
  • @ScottChamberlain: That's true, but due to the fact mentioned in my previous comment, this is no longer an issue of this answer. – Antonín Procházka Apr 20 '16 at 08:54
  • @AntonínProcházka Could you notify me or update the reported issue of this was fixed? – Christian Klemm Apr 20 '16 at 09:09
  • @chris579: Definitely. We will update this thread as well as your report on our support forum. – Antonín Procházka Apr 20 '16 at 09:45