0

I've got the following class:

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ImportDefinitieGenerator.LinkTypeDetail.Detail
{

    abstract class LinkTypeDetailBase : INotifyPropertyChanged
    {
        public string Property { get; set; }
        private string _Value;

        public event PropertyChangedEventHandler PropertyChanged;

        public string Value { get { return _Value; }
            set
            {
                _Value = value;
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Value"));
            }
        }
        public LinkTypeDetailBase(string Property)
        {
            this.Property = Property;
            this.Value = "";
        }

        internal abstract void Click();
    }
}

Nice and simple. This class works fine, when Value gets changed the PropertyChanged fires. But now I'm trying to set the Value from a dialog, so I use:

Value = await StringDialog.getString(Property, Value);

which in turn calls

public async static Task<string> getString(string title, string defaultText = "")
{
    StringDialog stringDialog = new StringDialog(title, defaultText);
    await stringDialog.ShowAsync();
    return stringDialog.TextBox.Text;
}

Now my problem arises. Everything works fine and dandy, apart from that the PropertyChanged event gets fired the moment the StringDialog shows up, not after the await and return. As a result, the value has not yet been changed at the moment it fires.

Is this intended behavior? If so, what would be the correct way of handling this? And if not, how would I work around this properly? (I'm sure I could hack my way around it, so I'm specifically asking about how to do it properly.)


Edit:

Okay, after trying to create a Minimal, Complete and Verifyable example, it seems that I'm in the wrong here. I'll attach the code for future reference. The bug is not where I expected it to be, and as such this has become a hunt for a bug in my code turning this question off-topic. When I find the cause, I will post it would it be useful for future reference.

using System;
using System.ComponentModel;
using System.Threading.Tasks;
using Windows.ApplicationModel;
using Windows.ApplicationModel.Activation;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Navigation;

namespace MCV
{
    sealed partial class App : Application
    {
        private static VerifyMyBug verifyMyBug;

        public App()
        {
            this.InitializeComponent();
            this.Suspending += OnSuspending;
        }

        protected override void OnLaunched(LaunchActivatedEventArgs e)
        {
            Frame rootFrame = Window.Current.Content as Frame;
            if (rootFrame == null)
            {
                rootFrame = new Frame();
                rootFrame.NavigationFailed += OnNavigationFailed;
                Window.Current.Content = rootFrame;
            }
            if (e.PrelaunchActivated == false)
            {
                if (rootFrame.Content == null)
                {
                    rootFrame.Navigate(typeof(MainPage), e.Arguments);
                }
                Window.Current.Activate();
            }

            verifyMyBug = new VerifyMyBug();
            verifyMyBug.PropertyChanged += (o, e1) =>
            {
                throw new NotImplementedException("Property changed");
            };
            verifyMyBug.DelayedSet();
        }
        void OnNavigationFailed(object sender, NavigationFailedEventArgs e)
        {
            throw new Exception("Failed to load Page " + e.SourcePageType.FullName);
        }
        private void OnSuspending(object sender, SuspendingEventArgs e)
        {
            var deferral = e.SuspendingOperation.GetDeferral();
            deferral.Complete();
        }
    }

    class VerifyMyBug : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        private string _Value;
        public string Value
        {
            get { return _Value; }
            set
            {
                _Value = value;
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Value"));
            }
        }

        public async void DelayedSet()
        {
            Value = await GetStringDelayed();
            throw new NotImplementedException("Done setting variable");
        }

        public async Task<string> GetStringDelayed()
        {
            await Task.Delay(TimeSpan.FromSeconds(5));
            return "Hello";
        }
    }
}

Edit 2: Okay, the event did fire, it just got lost somewhere along the way. My apologies for wasting your time.

Daniël van den Berg
  • 2,197
  • 1
  • 20
  • 45
  • 3
    That seems unlikely to me - I suspect you're misdiagnosing it somehow. Could you provide a [mcve] demonstrating the problem? – Jon Skeet Dec 08 '16 at 14:00
  • 3
    This is raising an alarm for me. You seem to be doing UI stuff on a thread other than the main/UI thread. For instance: `stringDialog.ShowAsync()`. Performing UI operations on non-UI threads breaks a golden rule for interface design and can lead to many hard-to-diagnose issues. – rory.ap Dec 08 '16 at 14:04
  • What class is this code in? `Value = await StringDialog.getString(Property, Value);` Is it in `LinkTypeDetailBase`? Can you explain exactly what the dialog has to do with `LinkTypeDetailBase`? I'd just put a breakpoint in the `Value` setter and see who calls it when. – 15ee8f99-57ff-4f92-890c-b56153 Dec 08 '16 at 14:06
  • Have you data-bound your object? Maybe your form sets the vallue through data binding and causes the event to fire? – Sefe Dec 08 '16 at 14:15
  • @rory.ap `async` does not imply threading. It is perfectly possible for UI methods to be both `async` and single-threaded. – piedar Dec 08 '16 at 14:54
  • @piedar -- You're going to need to back that up with some proof. "Async" or "asynchronous" a priori requires multiple threads. – rory.ap Dec 08 '16 at 15:00
  • @rory.ap No, [it](http://stackoverflow.com/a/33222386/1925996) [does](https://stackoverflow.com/questions/37419572/if-async-await-doesnt-create-any-additional-threads-then-how-does-it-make-appl) [not](http://blog.stephencleary.com/2013/11/there-is-no-thread.html). – piedar Dec 08 '16 at 15:04
  • @piedar -- *Very* interesting. So if `ShowAsync` internally awaits a built-in I/O or other non-CPU-bound operation, then its doing so without another thread. – rory.ap Dec 08 '16 at 15:47
  • @rory.ap from what I remember from Android programming tasks get put on a stack, from which the main thread executes them when it's not busy. – Daniël van den Berg Dec 08 '16 at 15:53

0 Answers0