Register to C# event from C++/CLI - events

I'm writing C++ code that calls C# code. The C# may need to invoke methods back in the C++ code. If both parts were C# I think I would use following mechanism. Please note I pass EventHandler from ShouldBCpp to Csharp instead of registering in ShouldBCpp since ShouldBCpp does not know what csharp points to (& can't change CsharpBase).
public abstract class CsharpBase
{
public abstract void SomeMethodDoingActionInB();
}
public class Csharp : CsharpBase
{
public Csharp(EventHandler f)
{
MySpecialHook += f;
}
public event EventHandler MySpecialHook;
public override void SomeMethodDoingActionInB()
{
if (MySpecialHook != null)
MySpecialHook(this, null);
}
}
public class ShouldBCpp
{
public CsharpBase csharp;
public ShouldBCpp()
{
csharp = new Csharp(NotificationFromClassB); // actually using Activator::CreateInstance
}
public void NotificationFromClassB(object sender, EventArgs e)
{
}
public void Go()
{
csharp.SomeMethodDoingActionInB();
}
}
class Program
{
static void Main(string[] args)
{
ShouldBCpp shouldBCpp = new ShouldBCpp();
shouldBCpp.Go();
}
}
Question is how to write ShouldBCpp in C++/CLI. Bonus points for using delegate :)
Thank you

A simple translation to C++/CLI would look like this:
public ref class IsCppCLI
{
public:
CsharpBase^ csharp;
IsCppCLI()
{
csharp = gcnew Csharp(gcnew EventHandler(this, &IsCppCLI::NotificationFromClassB));
// You didn't show your Activator code,
// but I believe it would translate to C++/CLI as this:
csharp = dynamic_cast<CsharpBase^>(
Activator::CreateInstance(
Csharp::typeid,
gcnew array<Object^> {
gcnew EventHandler(this, &IsCppCLI::NotificationFromClassB)}));
}
void NotificationFromClassB(Object^ sender, EventArgs^ e)
{
}
void Go()
{
csharp->SomeMethodDoingActionInB();
}
}

Related

How to migrate MVVMCross based Xamarin.android project into Intune managed one

I have a android project running smoothly, it uses MVVMCross at its core.
The problem came when I was asked manage the app protection policies with Intune.
Now Intune is forcing me to use their managed activity and all other managed namespaces provided by Intune SDK.
In that case, how I can proceed with it?
I tried changing activities base class to Intune's one, in hope to use general things provided by Mvvmcross, such as IOC, dependency injections.
I customised App startup as Intune wants that means there will not be any setup/app.cs class calls involvement.
So I launch Splash activity -> and it launches MainActivity, in MainActivity I am manually injecting all the Dependencies which I require.
Because all these syntaxes are throwing exception under Intune managed activities
example: Mvx.RegisterType<IDeviceInformation, DeviceInformation>();
Above throws exception.
How do I proceed with this migration keeping MVVMcross basic functionality intact?
There is a couple of solutions to that matter that I can think of.
If you only need the DI you can add another DI manager package and handle it from there which will be simpler than configuring Mvx to do that only.
If you need other capabilities of Mvx then you will have to do what Mvx does in its base classes and implement them taking into consideration setting the appropiate interfaces to your base classes.
In Android, in order to get the Setup and Activities working you'll have to:
Register your setup in your android Application file as done here
this.RegisterSetupType<TMvxAndroidSetup>();
Implement your own base activity that takes into consideration the implementation of IMvxEventSourceActivity such as here and also the MvxActivity like here in order to have the events and the data context / viewmodel handling
[Register("mvvmcross.platforms.android.views.base.MvxEventSourceActivity")]
public abstract class MvxEventSourceActivity
: Activity, IMvxEventSourceActivity
{
protected MvxEventSourceActivity()
{
}
protected MvxEventSourceActivity(IntPtr javaReference, JniHandleOwnership transfer)
: base(javaReference, transfer)
{
}
protected override void OnCreate(Bundle bundle)
{
CreateWillBeCalled.Raise(this, bundle);
base.OnCreate(bundle);
CreateCalled.Raise(this, bundle);
}
protected override void OnDestroy()
{
DestroyCalled.Raise(this);
base.OnDestroy();
}
protected override void OnNewIntent(Intent intent)
{
base.OnNewIntent(intent);
NewIntentCalled.Raise(this, intent);
}
protected override void OnResume()
{
base.OnResume();
ResumeCalled.Raise(this);
}
protected override void OnPause()
{
PauseCalled.Raise(this);
base.OnPause();
}
protected override void OnStart()
{
base.OnStart();
StartCalled.Raise(this);
}
protected override void OnRestart()
{
base.OnRestart();
RestartCalled.Raise(this);
}
protected override void OnStop()
{
StopCalled.Raise(this);
base.OnStop();
}
public override void StartActivityForResult(Intent intent, int requestCode)
{
StartActivityForResultCalled.Raise(this, new MvxStartActivityForResultParameters(intent, requestCode));
base.StartActivityForResult(intent, requestCode);
}
protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
{
ActivityResultCalled.Raise(this, new MvxActivityResultParameters(requestCode, resultCode, data));
base.OnActivityResult(requestCode, resultCode, data);
}
protected override void OnSaveInstanceState(Bundle outState)
{
SaveInstanceStateCalled.Raise(this, outState);
base.OnSaveInstanceState(outState);
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
DisposeCalled.Raise(this);
}
base.Dispose(disposing);
}
public event EventHandler DisposeCalled;
public event EventHandler<MvxValueEventArgs<Bundle>> CreateWillBeCalled;
public event EventHandler<MvxValueEventArgs<Bundle>> CreateCalled;
public event EventHandler DestroyCalled;
public event EventHandler<MvxValueEventArgs<Intent>> NewIntentCalled;
public event EventHandler ResumeCalled;
public event EventHandler PauseCalled;
public event EventHandler StartCalled;
public event EventHandler RestartCalled;
public event EventHandler StopCalled;
public event EventHandler<MvxValueEventArgs<Bundle>> SaveInstanceStateCalled;
public event EventHandler<MvxValueEventArgs<MvxStartActivityForResultParameters>> StartActivityForResultCalled;
public event EventHandler<MvxValueEventArgs<MvxActivityResultParameters>> ActivityResultCalled;
}
[Register("mvvmcross.platforms.android.views.MvxActivity")]
public abstract class MvxActivity
: MvxEventSourceActivity
, IMvxAndroidView
{
protected View _view;
protected MvxActivity(IntPtr javaReference, JniHandleOwnership transfer)
: base(javaReference, transfer)
{
}
protected MvxActivity()
{
BindingContext = new MvxAndroidBindingContext(this, this);
this.AddEventListeners();
}
public object DataContext
{
get { return BindingContext.DataContext; }
set { BindingContext.DataContext = value; }
}
public IMvxViewModel ViewModel
{
get
{
return DataContext as IMvxViewModel;
}
set
{
DataContext = value;
OnViewModelSet();
}
}
public void MvxInternalStartActivityForResult(Intent intent, int requestCode)
{
StartActivityForResult(intent, requestCode);
}
public IMvxBindingContext BindingContext { get; set; }
public override void SetContentView(int layoutResId)
{
_view = this.BindingInflate(layoutResId, null);
SetContentView(_view);
}
protected virtual void OnViewModelSet()
{
}
protected override void AttachBaseContext(Context #base)
{
if (this is IMvxSetupMonitor)
{
// Do not attach our inflater to splash screens.
base.AttachBaseContext(#base);
return;
}
base.AttachBaseContext(MvxContextWrapper.Wrap(#base, this));
}
private readonly List<WeakReference<Fragment>> _fragList = new List<WeakReference<Fragment>>();
public override void OnAttachFragment(Fragment fragment)
{
base.OnAttachFragment(fragment);
_fragList.Add(new WeakReference<Fragment>(fragment));
}
public List<Fragment> Fragments
{
get
{
var fragments = new List<Fragment>();
foreach (var weakReference in _fragList)
{
if (weakReference.TryGetTarget(out Fragment f))
{
if (f.IsVisible)
fragments.Add(f);
}
}
return fragments;
}
}
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
ViewModel?.ViewCreated();
}
protected override void OnDestroy()
{
base.OnDestroy();
ViewModel?.ViewDestroy(IsFinishing);
}
protected override void OnStart()
{
base.OnStart();
ViewModel?.ViewAppearing();
}
protected override void OnResume()
{
base.OnResume();
ViewModel?.ViewAppeared();
}
protected override void OnPause()
{
base.OnPause();
ViewModel?.ViewDisappearing();
}
protected override void OnStop()
{
base.OnStop();
ViewModel?.ViewDisappeared();
}
}
public abstract class MvxActivity<TViewModel>
: MvxActivity
, IMvxAndroidView<TViewModel> where TViewModel : class, IMvxViewModel
{
public new TViewModel ViewModel
{
get { return (TViewModel)base.ViewModel; }
set { base.ViewModel = value; }
}
}
Also you'll have to implement your own splash activity like here which implements the IMvxSetupMonitor and is the one who ends up calling the setup here by calling MvxAndroidSetupSingleton.EnsureSingletonAvailable(ApplicationContext); and initializing a monitor.
[Register("mvvmcross.platforms.android.views.MvxSplashScreenActivity")]
public abstract class MvxSplashScreenActivity
: MvxActivity, IMvxSetupMonitor
{
protected const int NoContent = 0;
private readonly int _resourceId;
private Bundle _bundle;
public new MvxNullViewModel ViewModel
{
get { return base.ViewModel as MvxNullViewModel; }
set { base.ViewModel = value; }
}
protected MvxSplashScreenActivity(int resourceId = NoContent)
{
RegisterSetup();
_resourceId = resourceId;
}
protected MvxSplashScreenActivity(IntPtr javaReference, JniHandleOwnership transfer)
: base(javaReference, transfer)
{
}
protected virtual void RequestWindowFeatures()
{
RequestWindowFeature(WindowFeatures.NoTitle);
}
protected override void OnCreate(Bundle bundle)
{
RequestWindowFeatures();
_bundle = bundle;
var setup = MvxAndroidSetupSingleton.EnsureSingletonAvailable(ApplicationContext);
setup.InitializeAndMonitor(this);
base.OnCreate(bundle);
if (_resourceId != NoContent)
{
// Set our view from the "splash" layout resource
// Be careful to use non-binding inflation
var content = LayoutInflater.Inflate(_resourceId, null);
SetContentView(content);
}
}
private bool _isResumed;
protected override void OnResume()
{
base.OnResume();
_isResumed = true;
var setup = MvxAndroidSetupSingleton.EnsureSingletonAvailable(ApplicationContext);
setup.InitializeAndMonitor(this);
}
protected override void OnPause()
{
_isResumed = false;
var setup = MvxAndroidSetupSingleton.EnsureSingletonAvailable(ApplicationContext);
setup.CancelMonitor(this);
base.OnPause();
}
public virtual async Task InitializationComplete()
{
if (!_isResumed)
return;
await RunAppStartAsync(_bundle);
}
protected virtual async Task RunAppStartAsync(Bundle bundle)
{
if (Mvx.IoCProvider.TryResolve(out IMvxAppStart startup))
{
if(!startup.IsStarted)
{
await startup.StartAsync(GetAppStartHint(bundle));
}
else
{
Finish();
}
}
}
protected virtual object GetAppStartHint(object hint = null)
{
return hint;
}
protected virtual void RegisterSetup()
{
}
}
public abstract class MvxSplashScreenActivity<TMvxAndroidSetup, TApplication> : MvxSplashScreenActivity
where TMvxAndroidSetup : MvxAndroidSetup<TApplication>, new()
where TApplication : class, IMvxApplication, new()
{
protected MvxSplashScreenActivity(int resourceId = NoContent) : base(resourceId)
{
}
protected override void RegisterSetup()
{
this.RegisterSetupType<TMvxAndroidSetup>();
}
}
This will cover the basics I think.
Hope it helps you to get you to the right direction

Xamarin support for AdMob Rewarded Interstitial

Today I noticed AdMob is offering rewarded interstitial option. I'd like to integrate it in my game. Does the current Xamarin.GooglePlayServices.Ads support the integration?
Has anyone tried it? Love to hear from your experience.
Thanks!
I have just attempted to integrate them and they work fine for me in debug (yet to try in release mode - will update once I've tried it)
Simply create an interstitial ad as you normally would but use the Reward Video ad unit ID instead of the usual interstitial ad ID.
If you want to try it yourself, the sample Reward Video ad unit ID provided by Google for testing is:
ca-app-pub-3940256099942544/5224354917
#region RewardedViewAd
private IRewardedVideoAd rewardedVideoAd;
private void InitialRewardVideo()
{
rewardedVideoAd = MobileAds.GetRewardedVideoAdInstance(this);
rewardedVideoAd.RewardedVideoAdListener = this;
this.LoadRewardAd();
}
private void LoadRewardAd()
{
if (!rewardedVideoAd.IsLoaded)
{
#if DEBUG
rewardedVideoAd.LoadAd(" ca-app-pub-3940256099942544/5224354917", new AdRequest.Builder().Build());
#else
rewardedVideoAd.LoadAd("ca-app-pub-9045308343519031/327467645", new AdRequest.Builder().Build());
#endif
}
}
private void StartRewardedVideoAd()
{
if (rewardedVideoAd.IsLoaded)
{
rewardedVideoAd.Show();
}
}
public void OnRewarded(IRewardItem reward)
{
var coins = reward.Amount;
}
public void OnRewardedVideoAdClosed()
{
this.LoadRewardAd();
}
public void OnRewardedVideoAdFailedToLoad(int errorCode)
{
}
public void OnRewardedVideoAdLeftApplication()
{
}
public void OnRewardedVideoAdLoaded()
{
}
public void OnRewardedVideoAdOpened()
{
}
public void OnRewardedVideoCompleted()
{
}
public void OnRewardedVideoStarted()
{
}
protected override void OnPause()
{
this.rewardedVideoAd.Pause(this);
base.OnPause();
}
protected override void OnResume()
{
this.rewardedVideoAd.Resume(this);
base.OnResume();
}
protected override void OnDestroy()
{
this.rewardedVideoAd.Destroy(this);
base.OnDestroy();
}
#endregion;

Code reuse in PostSharp's OnMethodBoundaryAspect leads to StackOverflowException

I have written a custom OnMethodBoundaryAspect called TraceAspect. This aspect checks within the OnEntry, OnExit, and OnException methods whether tracing is enabled or not. I have a central class for reading and writing settings. Both of the two methods Settings.GetLoggingEnabled() and Settings.GetLogLevel() are called from the TraceAspect. They are there, so I reuse them which results in a StackOverflowException.
[assembly: MyCompany.MyProduct.TraceAspect]
[Serializable]
public class TraceAspect : OnMethodBoundaryAspect
{
public override void OnEntry(MethodExecutionArgs args)
{
if (Settings.GetLogginEnabled() && Settings.GetLogLevel() == LogLevel.Trace)
{
// Log the message
}
}
}
Applying the [TraceAspect(AttributeExclude = true)] attribute to the TraceAspect class leads to the same behaviour.
I could write something like this. But this is code duplication.
[assembly: MyCompany.MyProduct.TraceAspect]
[Serializable]
public class TraceAspect : OnMethodBoundaryAspect
{
public override void OnEntry(MethodExecutionArgs args)
{
if (this.GetLogginEnabled() && this.GetLogLevel() == LogLevel.Trace)
{
// Log the message
}
}
private bool GetLoggingEnabled()
{
// copy code from Settings.GetLogginEnabled()
}
private bool GetLogLevel()
{
// copy code from Settings.GetLogLevel()
}
}
How can I tell that the Settings.GetLoggingEnabled() and Settings.GetLogTrace() methods should not be traced, when they are called by the aspect?
You can break the recursion during logging by introducing a thread static flag to indicate that you're currently inside the logging call.
[Serializable]
public class TraceAspect : OnMethodBoundaryAspect
{
[ThreadStatic]
private static bool isLogging;
public override void OnEntry(MethodExecutionArgs args)
{
if (isLogging) return;
isLogging = true;
try
{
if (Settings.GetLogginEnabled() && Settings.GetLogLevel() == LogLevel.Trace)
{
// Log the message
}
}
finally
{
isLogging = false;
}
}
}

Overriding the method and subscribing to the event is the same?

class A
{
public event EventHanler MyEvent;
protected virtual void OnMyEvent(EventArgs e)
{
if (MyEvent!=null)
MyEvent(this, e);
}
public void DoEvent()
{
//................
MyEvent(this, new EventArgs());
}
}
class B: A
{
private A a = new A();
public B ()
{
a.MyEvent += MyMethod;
}
public void MyMethod(object sender, EventArgs e)
{
Console.WriteLine("Event handler");
}
}
class C : A
{
private A a = new A();
protected override void OnMyEvent(EventArgs e)
{
base.OnMyEvent(e);
Console.WriteLine("OnMyEvent overriding");
}
}
I subscribe to the event and override the method OnMyEvent() in the classes B and C. Pay attension calling the method base.OnMyEvent(e) is in the beginning of the method C.OnMyEvent(...).
As far as I'm concerned there are no differences here. In other words if I call base.OnMyEvent(e) in the beginning of the overriding method, it would mean the same as I just subscribe to the event?
Are there actually no differences?
There is a difference:
Invoking C.OnMyEvent() raises MyEvent. (Conversely, raising MyEvent will not invoke C.OnMyEvent().)
B.MyMethod handles MyEvent. Thus, raising MyEvent will invoke B.MyMethod. (Conversely, invoking B.MyMethod will not raise MyEvent.)

raising events in chaining classes

say I have three classes: class1, control1 and form1; form1 instantiate contorl. and control1 instantiate class1, the later produces some event that I need to 'bypass' to form1, to achieve that I have made an intermediate function as shown below:
public delegate void TestHandler(String^ str);
public ref Class class1
{
event TestHandler^ TestHappen;
void someFunction()
{
TestHappen("test string");
}
};
public ref Class control1
{
event TestHandler^ TestHappen;
class1^ class1Obj;
control1()
{
class1Obj= gcnew class1();
class1Obj->TestHappen+= gcnew TestHandler(this,&control1::onTest);
}
void onTest(String^ str)
{
TestHappen(str);
}
};
public ref Class form1
{
control1^ control1Obj;
form1()
{
control1Obj= gcenw control1();
control1Obj->TestHappen+= gcnew TestHandler(this,&form1::onTest);
}
void onTest(String^ str)
{
//do something with the string...
}
};
I don't want to use class1 in form1, are there a way to remove the intermediate onTest() function.
Yes, if you use a custom event, you can write its add-handler and remove-handler functions so that they add and remove the delegate directly from another object's event.
For example:
public ref class control1 // in "ref class", class is lowercase!
{
class1 class1Obj; // stack-semantics syntax, locks class1Obj lifetime to be same as the containing control1 instance
public:
event TestHandler^ TestHappen {
void add(TestHandler^ handler) { class1Obj.TestHappen += handler; }
void remove(TestHandler^ handler) { class1Obj.TestHappen -= handler; }
}
};

Resources