How does one make function calls or trigger events from a Native component into a C#/XAML component?

自作多情 提交于 2020-01-02 19:47:29

问题


I am developing a WP8 application with a Native (DirectX/D3D) component and a C#/XAML component.

The Native component draws to a UI element and the C#/XAML component has the controls of the app (and other things) surrounding it. Usually, I send information from the C#/XAML component down to the Native component. But there are certain times when I would like to trigger events in the C#/XAML component based on when processing is done in the Native component. In one planned feature, I envision a C#/XAML progress bar that is kept up to date by events triggered in the Native component.

Unfortunately, despite some mediocre attempts to get information passed from the Native component to the C#/XAML one, I haven't made much progress and I feel dead in the water.

I would greatly appreciate any guidance on this. Thanks for reading.


回答1:


After much poking around (and much help from some of the guys that answered in this thread!) I was able to find this solution: Calling C# method from C++ code in WP8

I will reproduce it here for simplicity's sake:

After a lot of headaches trying to figure out the required code, I think it's worth posting the final version here

C++/CX

//.h
[Windows::Foundation::Metadata::WebHostHidden]
public interface class ICallback
{
public:
    virtual void Exec( Platform::String ^Command, Platform::String ^Param);
};
//.cpp
ICallback ^CSCallback = nullptr;
void Direct3DInterop::SetCallback( ICallback ^Callback)
{
    CSCallback = Callback;
}
//...

if (CSCallback != nullptr)
    CSCallback->Exec( "Command", "Param" );

C#
public class CallbackImpl : ICallback
{
    public void Exec(String Command, String Param)
    {
        //Execute some C# code, if you call UI stuff you will need to call this too
        //Deployment.Current.Dispatcher.BeginInvoke(() => { 
        // //Lambda code
        //}
    }
}
//...
CallbackImpl CI = new CallbackImpl();
D3DComponent.SetCallback( CI);



回答2:


This is because your not able to have your C++ code call into C#. You can only have C# call (and return) into C++.

http://social.msdn.microsoft.com/Forums/wpapps/en-us/a850b680-6052-41c5-825a-d764d3369fe9/calling-c-code-from-c-in-windows-phone-8




回答3:


Something you can do is keep a function pointer to a function in C#. You can from C# call the native C++ to store the function pointer then you can call it whenever you want. The function as to be static.

for instance in C#

[DllImport( @"SomeDLL.dll" )]
static extern void SetAchievementUnlocked( AchievementUnlockCallBack callback );

public delegate int AchievementUnlockCallBack( AchievementsType id, IntPtr message );
static AchievementUnlockCallBack mAchievementUnlockCallBack = AchievementUnlocked;

static int AchievementUnlocked( AchievementsType id, IntPtr pMessage )
{
    string achievementName = Marshal.PtrToStringAnsi( pMessage );
    DisplayAchievement( achievementName );
    MainWindowHandler.Context.Focus();
    return 1;
}

and have in the constructor maybe

SetAchievementUnlocked( mAchievementUnlockCallBack );

then in C++

typedef int (*AchievementUnlockCallBack)(AchievementsType pType, char* pMessage);
AchievementUnlockCallBack globalCallback = NULL;
__declspec(dllexport) void SetAchievementUnlocked( AchievementUnlockCallBack callback )
{
    globalCallback = callback
}

Then anywhere you have access to that variable you can do

void Achievement::Unlock()
{
    if(globalCallback)
    {
         globalCallback(this->getType(), this->getName().c_str());
    }
}

Hopefully this can help you. If you are not using dll and interops services, it probably would work, but I haven't tested and don't have examples unfortunatly.




回答4:


The other way around is what works. You can call native code from C# (managed code) through COM interops: http://msdn.microsoft.com/en-us/library/aa645736%28v=VS.71%29.aspx

I don't think it is possible to call managed code from native. What are you trying to do?




回答5:


You can pass a delegate from your C# to the C++ Component.

In your C++ Component you'll define a delegate and a method call to set that delegate, like this:

public delegate void SomeDelegate(Platform::String^ args);

public ref class Component sealed
{
  public:
  void SetDelegate(SomeDelegate^);

  private:
  Platform::Agile<SomeDelegate> m_delegate;
}

Then in your C# you can create a function that matches the delegate signature, and pass it down to your component:

public void DelegateFunction(string args)
{
   // run C# code that was invoked from C++
}

// elsewhere in your C# code
component.SetDelegate(DelegateFunction);

Then in your C++ you can just invoke the delegate method whenever you need to.

Edit: I wrote a blog post about this topic - http://robwirving.com/2014/07/21/calling-c-methods-c-winrt-components/



来源:https://stackoverflow.com/questions/17304386/how-does-one-make-function-calls-or-trigger-events-from-a-native-component-into

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!