locked
Not able to use ApplicationData::DataChanged event

    Question

  • Hi,

     I am trying to use the DataChanged event from ApplicationData. Its signature is

    public:
    event TypedEventHandler<applicationdata, object="">^ DataChanged {
       Windows::Foundation::EventRegistrationToken add(TypedEventHandler<applicationdata, object="">^ value);
       void remove(Windows::Foundation::EventRegistrationToken token);
    }</applicationdata,></applicationdata,>


    So I created a method like:

    void SOMECLASS::SettingChanged(Windows::Storage::ApplicationData^ data, Platform::Object^ obj)
    {
        // do something
    }


    And add it like:

    appData->DataChanged += ref new TypedEventHandler<windows::storage::applicationdata^, platform::object^="">(this, &SOMECLASS::SettingChanged);</windows::storage::applicationdata^,>


    But the compiler is giving me the following error:

    1>c:\file.cpp(36): error C2664: 'Windows::Foundation::TypedEventHandler<tsender,tresult>::TypedEventHandler<someclass*>(TFunction,Platform::CallbackContext)' : cannot convert parameter 2 from 'void (__cdecl SOMECLASS::* )(Windows::Storage::ApplicationData ^,Platform::Object ^)' to 'Platform::CallbackContext'
    1>          with
    1>          [
    1>              TSender=Windows::Storage::ApplicationData ^,
    1>              TResult=Platform::Object ^,
    1>              TFunction = SOMECLASS*
    1>          ]
    1>          There is no context in which this conversion is possible</someclass*></tsender,tresult>

    I don't understand what should be the signature of the callback, or if there is another thing wrong.

    Thanks for your help.



    Tuesday, February 07, 2012 7:32 PM

Answers

  • Hi George,

    I see we haven't had an answer from a Metro guru (I'm on the C++/Tooling side of things).

    I was reviewing the Application data sample - http://code.msdn.microsoft.com/windowsapps/ApplicationData-sample-fb043eb2

    In this code, the only usage of the DataChanged event uses a call to SignalDataChanged after the insert in order to fire the DataChanged event

    void MainPage::Scenario4SimulateRoaming_Click(Object^ sender, RoutedEventArgs^ e)
    {
        ApplicationData::Current->RoamingSettings->Values->Insert(scenario4SettingName, Scenario4UserName->Text);
    
        // Simulate roaming by intentionally signaling a data changed event.
        ApplicationData::Current->SignalDataChanged();
    }
    I added that call to your scenario as well and the event fires.
    Tuesday, February 14, 2012 12:33 AM
    Moderator

All replies

  • Hi George, I'm not sure what the problem might be. This compiles cleanly for me:

    using namespace Windows::Storage;
    using namespace Windows::Foundation;
    public ref class SOMECLASS sealed
    {
    public:
    	void SettingChanged(ApplicationData^ data, Platform::Object^ obj){}
    	void Test(ApplicationData^ ad)
    	{
    		ad->DataChanged += ref new TypedEventHandler<applicationdata^, Object^="">(this, &SOMECLASS::SettingChanged );
    	}
    };</applicationdata^,>

    It looks pretty close to what you wrote. Can you condense the error case down to a minimal sample class?

    -Steve


    Wednesday, February 08, 2012 12:41 AM
    Moderator
  • Thanks for your help, you made me realize that the class containing the callback needed to be declared as a "ref class". The question now is, ¿can a method of a non ref class be use as the callback? (the class is being inherited from a non ref class, and that cannot be changed).

    The simplest solution is to have another ref class with the callback and have a member on the non ref class of the ref class type.

    Bonus Question: I did an small project to test the code. I change the value of a setting, but the DataChanged is never called. Why?


    ref class OTHERCLASS
    {
    public:
    	void SettingChanged(Windows::Storage::ApplicationData^ data, Platform::Object^ obj)	{ 
    		OutputDebugStringW(L"CALLBACK CALLED");
    	}
    };
    
    class SOMECLASS
    {
    	OTHERCLASS^ oc;
    public:
    	SOMECLASS() { oc = ref new OTHERCLASS(); }
    	void Test()
    	{
    		ApplicationData^ appData =  Windows::Storage::ApplicationData::Current;
    		ApplicationDataContainer^ settingContainer = appData->RoamingSettings;
    		StorageFolder^ roamingFolder = appData->RoamingFolder;
    
    		appData->DataChanged += ref new TypedEventHandler<Windows::Storage::ApplicationData^, Platform::Object^>(oc, &OTHERCLASS::SettingChanged);
    
    		IPropertySet^ settings = settingContainer->Values;
    		settings->Insert("hello", "world!");
    	}
    };

    Wednesday, February 08, 2012 2:01 PM
  • Regarding the non-ref class -- I don't think so, you can only cross the ABI boundary with WinRT/ref class types.

    I'm not sure why the event is not fired -- It also isn't fired if you make SOMECLASS a ref class too. I also tried adding the SettingChanged handler into the ref class SOMECLASS and it still wasnt' fired.

    Let me loop in someone more familiar in this area.

    Thursday, February 09, 2012 1:51 AM
    Moderator
  • Thanks Steve. Speaking of strange things, there is another bug where 

    settings->Insert("hello", "world!");

    always returns true, no matter if there was already a value with a "hello" key before. According the documentation, "Insert" should return

    "True if an item with the specified key is an existing item and was replaced; otherwise, false."

    BTW: do you know where I should report this? I tried searching in the categories of MS Connect, but I dind't find something related to Metro o Windows Runtime.

    Thursday, February 09, 2012 1:00 PM
  • Hi George,

    I see we haven't had an answer from a Metro guru (I'm on the C++/Tooling side of things).

    I was reviewing the Application data sample - http://code.msdn.microsoft.com/windowsapps/ApplicationData-sample-fb043eb2

    In this code, the only usage of the DataChanged event uses a call to SignalDataChanged after the insert in order to fire the DataChanged event

    void MainPage::Scenario4SimulateRoaming_Click(Object^ sender, RoutedEventArgs^ e)
    {
        ApplicationData::Current->RoamingSettings->Values->Insert(scenario4SettingName, Scenario4UserName->Text);
    
        // Simulate roaming by intentionally signaling a data changed event.
        ApplicationData::Current->SignalDataChanged();
    }
    I added that call to your scenario as well and the event fires.
    Tuesday, February 14, 2012 12:33 AM
    Moderator
  • This worked for me to get settings callbacks in an app port that is mostly written in native. I am not sure if it opens Pandora's box, but it is running...
    Thursday, February 14, 2013 7:00 AM