如何从本机组件向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组件方面做了一些平庸的尝试,但我没有取得太大进展,我觉得自己已经陷入了困境。
如果能就此提供任何指导,我将不胜感激。感谢阅读。
经过大量的探索(以及在这个线程中回答的一些人的大量帮助!)我找到了这个解决方案:从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/