locked
Why Dos NotifyProperytChanged Crash with I use a task?

    Question

  • I'm trying to update my App Store app's UI with a value that's created by a background task, and I don't get why this crashes my app. I've tried to boil this down to as simple an app as possible using the C++ BlankPage app template.
    To the BlankPage template project, I added a button and a text block on the main page. I also have a added a new data-model class to the project with a single property, type Platform::String^. The DataContext of MainPage is set to an instance of this class, and the text of the text block is bound to the string property...
    MainPage.xaml has this...

     <TextBlock HorizontalAlignment="Left" Margin="72,110,0,0" TextWrapping="Wrap" Text="{Binding Path=Message}" VerticalAlignment="Top" Height="265" Width="564"/>
     <Button Content="Change Text with Task" HorizontalAlignment="Left" Margin="204,51,0,0" VerticalAlignment="Top" Click="Button_Click_2"/>
    

    ...where fData is a private member variable.

    The Button_Click_2 event handler looks like this...

    void TaskExperiment::MainPage::Button_Click_2(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e)
    {
    	SomeData^ myData = fData;
    	task<void> createMessageTask([myData]()
    	{
    		Platform::String^ message = ref new Platform::String (L"Changed  by a task.");
    		myData->Message = message;
    	});
    
    	createMessageTask.wait();
    }

    The SomeData class looks like this:

    namespace TaskExperiment
    {
    	[Windows::UI::Xaml::Data::Bindable]
    	public ref class SomeData sealed  : Windows::UI::Xaml::Data::INotifyPropertyChanged
    	{
    	public:
    		SomeData(void) {
    			fMessage = ref new Platform::String (L"New Data");
    		};
    
    		virtual event Windows::UI::Xaml::Data::PropertyChangedEventHandler^ PropertyChanged;
    
    		property Platform::String^ Message
    		{
    			Platform::String^ get ()
    			{
    				return fMessage;
    			}
    			void set (Platform::String^ value)
    			{
    				fMessage = value;
    				NotifyPropertyChanged("Message");
    			}
    		}
    
    	private:
    		~SomeData(void){}
    
    		Platform::String^ fMessage;
    
    		void NotifyPropertyChanged(Platform::String^ prop)
    		{
    			Windows::UI::Xaml::Data::PropertyChangedEventArgs^ args = 
    			ref new Windows::UI::Xaml::Data::PropertyChangedEventArgs(prop);
    			PropertyChanged(this, args);
    		}
    	};
    }

    When I debug and click my button, everyting blows up when I hit the line NotifyPropertyChanged("Message") line. I get this unhandled exception from somehwere deep in the bowels of the Windows::Ui.Xamal dll.
    Unhandled exception at 0x50EB4E43 (msvcr110d.dll) in TaskExperiment.exe: An invalid parameter was passed to a function that considers invalid parameters fatal.




    • Edited by CrownHill Friday, November 30, 2012 10:51 PM
    Friday, November 30, 2012 1:24 AM

Answers

  • Thank you for the suggestions. I modified my button click event handler so it's now like this...

    void TaskExperiment::MainPage::Button_Click_2(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e)
    {
    	SomeData^ myData = fData;
    	Windows::UI::Core::CoreDispatcher^ dispatcher = Windows::UI::Core::CoreWindow::GetForCurrentThread ()->Dispatcher;
    
    	task<void> createMessageTask([dispatcher, myData]()
    	{
    		Platform::String^ message = ref new Platform::String (L"This string was created by a task.");	
    
    		dispatcher->RunAsync(Windows::UI::Core::CoreDispatcherPriority::Normal,ref new Windows::UI::Core::DispatchedHandler([myData,message]()
    			{
    				myData->Message = message;
    			}));
    	});
    
    }

    Idiomatically, this very much like what you do in an iOS with GCD. The equivalent in an iOS app would be something like this...

    - (IBAction) buttonClicked:(UIButton*)sender
    {
    	// Do something in the background
    	dispatch_async (dispatch_get_global_queue (DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    		
    		NSString* message = [NSString stringWithUTF8String:"This is a message from the background"];
    		
    		// Resync with the main thread to update the UI
    		dispatch_async(dispatch_get_main_queue(), ^{
    			// update your UI here
    			NSLog(@"The message is now: %@", message);
    		});
    		
    	});
    }

    I hope that helps any other iOS developers trying to wrap their heads around Windows RT.

    • Marked as answer by Jesse Jiang Thursday, December 6, 2012 2:51 AM
    Saturday, December 1, 2012 12:42 AM

All replies

  • May be you tried to update UI from a worker thread which is not allowed.

    You can use CoreDispatcher class


    Please post your code appropriately (using Insert Code Block).
    Friday, November 30, 2012 4:02 AM
  • Thank you for the suggestions. I modified my button click event handler so it's now like this...

    void TaskExperiment::MainPage::Button_Click_2(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e)
    {
    	SomeData^ myData = fData;
    	Windows::UI::Core::CoreDispatcher^ dispatcher = Windows::UI::Core::CoreWindow::GetForCurrentThread ()->Dispatcher;
    
    	task<void> createMessageTask([dispatcher, myData]()
    	{
    		Platform::String^ message = ref new Platform::String (L"This string was created by a task.");	
    
    		dispatcher->RunAsync(Windows::UI::Core::CoreDispatcherPriority::Normal,ref new Windows::UI::Core::DispatchedHandler([myData,message]()
    			{
    				myData->Message = message;
    			}));
    	});
    
    }

    Idiomatically, this very much like what you do in an iOS with GCD. The equivalent in an iOS app would be something like this...

    - (IBAction) buttonClicked:(UIButton*)sender
    {
    	// Do something in the background
    	dispatch_async (dispatch_get_global_queue (DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    		
    		NSString* message = [NSString stringWithUTF8String:"This is a message from the background"];
    		
    		// Resync with the main thread to update the UI
    		dispatch_async(dispatch_get_main_queue(), ^{
    			// update your UI here
    			NSLog(@"The message is now: %@", message);
    		});
    		
    	});
    }

    I hope that helps any other iOS developers trying to wrap their heads around Windows RT.

    • Marked as answer by Jesse Jiang Thursday, December 6, 2012 2:51 AM
    Saturday, December 1, 2012 12:42 AM