如何从本机组件向C#/XAML组件进行函数调用或触发事件

本文关键字:组件 函数调用 事件 本机 XAML | 更新日期: 2023-09-27 18:19:56

我正在开发一个带有Native(DirectX/D3D)组件和C#/XAML组件的WP8应用程序。

Native组件绘制到一个UI元素,而C#/XAML组件拥有围绕它的应用程序(和其他东西)的控件。通常,我会将信息从C#/XXAML组件发送到Native组件。但是,有时我希望根据在Native组件中完成处理的时间来触发C#/XAML组件中的事件。在一个计划中的特性中,我设想了一个C#/XAML进度条,它由Native组件中触发的事件保持最新。

不幸的是,尽管在将信息从Native组件传递到C#/XAML组件方面做了一些平庸的尝试,但我没有取得太大进展,我觉得自己已经陷入了困境。

如果能就此提供任何指导,我将不胜感激。感谢阅读。

如何从本机组件向C#/XAML组件进行函数调用或触发事件

经过大量的探索(以及在这个线程中回答的一些人的大量帮助!)我找到了这个解决方案:从WP8 中的C++代码调用C#方法

为了简单起见,我将在这里复制它:

在试图找出所需的代码时遇到了很多麻烦,我认为值得在这里发布最终版本

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);

这是因为您无法将C++代码调用到C#中。您只能让C#调用(并返回)到C++中。

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

您可以做的事情是在C#中保留一个指向函数的函数指针。您可以从C#调用本机C++来存储函数指针,然后您可以随时调用它。函数是静态的。

例如在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;
}

并且在构造函数中可能有

SetAchievementUnlocked( mAchievementUnlockCallBack );

然后在C++中

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

然后,在任何你可以访问该变量的地方,你都可以进行

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

希望这能对你有所帮助。如果你不使用dll和interops服务,它可能会起作用,但我还没有测试过,不幸的是没有示例。

另一种方法是有效的。您可以通过COM互操作从C#(托管代码)调用本机代码:http://msdn.microsoft.com/en-us/library/aa645736%28v=VS.71%29.aspx

我认为从本机调用托管代码是不可能的。你想干什么?

您可以将委托从C#传递到C++组件。

在C++组件中,您将定义一个委托和一个方法调用来设置该委托,如下所示:

public delegate void SomeDelegate(Platform::String^ args);
public ref class Component sealed
{
  public:
  void SetDelegate(SomeDelegate^);
  private:
  Platform::Agile<SomeDelegate> m_delegate;
}

然后在C#中,您可以创建一个与委托签名匹配的函数,并将其传递给您的组件:

public void DelegateFunction(string args)
{
   // run C# code that was invoked from C++
}
// elsewhere in your C# code
component.SetDelegate(DelegateFunction);

然后在您的C++中,您可以随时调用委托方法。

编辑:我写了一篇关于这个主题的博客文章-http://robwirving.com/2014/07/21/calling-c-methods-c-winrt-components/