locked
Event handler cannot access object within C++ class (Threading).

    Question

  • Certain event handlers throw errors when trying to access objects within their C++ class.  The errors seem to indicate that it is due to the code not being executed in the main thread.  In this case, I want to update the displayed data when a 3D object is selected in a scene.  It works fine until the event handler tries to access and modify a XAML data bound object.  This throws one of two exceptions depending on which object is modified.

    Attempting to construct a PropertyItem^ object:
    Platform::WrongThreadException ^ at memory location 0x06D3CA20. HRESULT:0x8001010E The application called an
    interface that was marshalled for a different thread.

    Attempting to Clear() the properties object (Vector<PropertyItem^>^):
    Platform::InvalidCastException ^ at memory location 0x05E0CA18. HRESULT:0x80004002 No such interface supported

    I made sure that neither of these errors occur when the code is running on the main thread, in a different event handler.  I think that if I can force it to run on the main thread this issue would vanish, but I have not been able to figure out how to switch threads in C++.

    The relevant code is:
    DirectXPage.xaml.h, PropertyItem object

    //represents a single property
    	[Windows::UI::Xaml::Data::Bindable]
    	public ref class PropertyItem sealed : Windows::UI::Xaml::Data::INotifyPropertyChanged
    	{
    	public:
    		PropertyItem(void);
    
    		property Platform::String^ Name {
    			Platform::String^ get();
    			void set(Platform::String^ value);
    		}
    		property Platform::String^ Value{
    			Platform::String^ get();
    			void set(Platform::String^ value);
    		}
    
    		virtual event Windows::UI::Xaml::Data::PropertyChangedEventHandler^ PropertyChanged;
    	private:
    		void NotifyPropertyChanged(Platform::String^ prop);
    		Platform::String^ m_Name;
    		Platform::String^ m_Value;
    	};
    DirectXPage.xaml.cpp, OnTapped event handler
    void DirectXPage::OnTapped(GestureRecognizer^ sender, TappedEventArgs^ e)
    {
    	//double tap
    	if (e->TapCount == 1)
    	{
    		m_main->Select(e->Position);
    
    		GestureRecognizer^ b = safe_cast<GestureRecognizer^>(sender);
    		if (b != nullptr)
    		{
    			DirectXPage::Current->SetProperties();
    		}
    
    		//run_async_non_interactive(&RadiationX::DirectXPage::SetProperties);
    	}
    	if (e->TapCount == 2)
    	{
    		m_main->Zoom(0);
    		m_main->UpdateView();
    	}
    }
    DirectXPage.xaml.cpp, SetProperties function
    void RadiationX::DirectXPage::SetProperties()
    {
    	std::vector<std::string> propNames = m_main->GetSelectedProperties();
    	properties->Clear();
    	
    	for (int i = 0; i < propNames.size(); i++)
    	{
    		PropertyItem^ item = ref new PropertyItem();
    		//item->Name->Data = propNames[i];   //std::string
    		item->Name = "testName1";
    		//item->Value->Data = GetPropertyValue(propNames[i]);   //std::string
    		item->Value = "testValue1";
    		properties->Append(item);
    	}
    }
    DirectXPage.xaml.cpp, run_async_non_interactive function (attempt to run on main thread)
    void RadiationX::DirectXPage::run_async_non_interactive(std::function<void()>&& action)
    {
    	Windows::UI::Core::CoreWindow^ wnd = Windows::ApplicationModel::Core::CoreApplication::MainView->CoreWindow;
    	assert(wnd != nullptr);
    
    	wnd->Dispatcher->RunAsync(
    		Windows::UI::Core::CoreDispatcherPriority::Low,
    		ref new Windows::UI::Core::DispatchedHandler([action]()
    	{
    		action();
    	}));
    }
    • Edited by C_Moe Wednesday, May 21, 2014 10:14 AM
    Wednesday, May 21, 2014 10:11 AM

Answers

  • Found the fix.  It did involve making the code run on the main thread:

    DirectXPage class

    public ref class DirectXPage sealed
    	{
    		//...
    
    	internal:
    		Windows::UI::Core::CoreDispatcher^ _dispatcher;
    	};

    DirectXPage.xaml.ccp, OnTapped event handle

    void DirectXPage::OnTapped(GestureRecognizer^ sender, TappedEventArgs^ e)
    {
    	//single tap
    	if (e->TapCount == 1)
    	{
    		m_main->Select(e->Position);
    
    		_dispatcher->RunAsync(Windows::UI::Core::CoreDispatcherPriority::Normal,
    			ref new Windows::UI::Core::DispatchedHandler([this]()
    		{
    			SetProperties();
    		}));
    	}
    }

    Wednesday, May 21, 2014 8:54 PM