SeekBar on Mono for Android - c#

I would like to create a seekbar for a Mono for Android app that allows the user to select and i want to implement the SeekBar Widget, how can i use a SeekBarChangeListener() on Mono for Android?

To write a change listener you need a class that implements SeekBar.IOnSeekBarChangeListener:
public class SeekBarListener : Java.Lang.Object, SeekBar.IOnSeekBarChangeListener
{
public void OnProgressChanged(SeekBar seekBar, int progress, bool fromUser)
{
}
public void OnStartTrackingTouch(SeekBar seekBar)
{
}
public void OnStopTrackingTouch(SeekBar seekBar)
{
}
}
Then you can assign that to the seek bar:
seekBar.SetOnSeekBarChangeListener(new SeekBarListener());

Well i resolve this in the same class implementing SeekBar.IOnSeekBarChangeListener on another way here is my code:
private void CreateDialogSeek()
{
dialogSeek = new Dialog(this);
dialogSeek.SetContentView(Resource.Layout.seekbar_dialog);
dialogSeek.SetTitle("Change your configuration");
dialogSeek.SetCancelable(true);
//Ok
btnOk = (Button)(dialogSeek.FindViewById(Resource.Id.btnSettingsOKSeekBar));
btnCancel = (Button)(dialogSeek.FindViewById(Resource.Id.btnSettingsCancelSeekBar));
SeekBar mSeekBar = (SeekBar)(dialogSeek.FindViewById(Resource.Id.seekbar));
mSeekBar.Progress = cache;
mSeekBar.SetOnSeekBarChangeListener(this);
dialogSeek.Show();
btnOk.Click += delegate {OKSeek();};
btnCancel.Click += delegate {dialogSeek.Dismiss();;};
}
public void OnProgressChanged(SeekBar seekBar, int progress, bool fromUser)
{
cache = progress;
}
public void OnStartTrackingTouch(SeekBar seekBar)
{
}
public void OnStopTrackingTouch(SeekBar seekBar)
{
}

Related

Is there a way to be notified of whenever the volume setting is changed in Xamarin C#? [duplicate]

I'm programming a small widget that needs to be updated whenever the user changes the ringer volume or the vibrate settings.
Capturing android.media.VIBRATE_SETTING_CHANGED works just fine for the vibrate settings, but I haven't found any way of getting notified when the ringer volume changes and although I could try to capture when the user presses the volume up/volume down physical keys, there are many other options for changing the volume without using these keys.
Do you know if there's any broadcast action defined for this or any way to create one or to solve the problem without it?
There is no broadcast action, but I did find you can hook up a content observer to get notified when the settings change, volume of streams being some of those settings. Register for the android.provider.Settings.System.CONTENT_URI to be notified of all settings changes:
mSettingsContentObserver = new SettingsContentObserver( new Handler() );
this.getApplicationContext().getContentResolver().registerContentObserver(
android.provider.Settings.System.CONTENT_URI, true,
mSettingsContentObserver );
The content observer might look something like this:
public class SettingsContentObserver extends ContentObserver {
public SettingsContentObserver(Handler handler) {
super(handler);
}
#Override
public boolean deliverSelfNotifications() {
return super.deliverSelfNotifications();
}
#Override
public void onChange(boolean selfChange) {
super.onChange(selfChange);
Log.v(LOG_TAG, "Settings change detected");
updateStuff();
}
}
And be sure to unregister the content observer at some point.
Nathan's code works but gives two notifications for each change system settings. To avoid that, use the following
public class SettingsContentObserver extends ContentObserver {
int previousVolume;
Context context;
public SettingsContentObserver(Context c, Handler handler) {
super(handler);
context=c;
AudioManager audio = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
previousVolume = audio.getStreamVolume(AudioManager.STREAM_MUSIC);
}
#Override
public boolean deliverSelfNotifications() {
return super.deliverSelfNotifications();
}
#Override
public void onChange(boolean selfChange) {
super.onChange(selfChange);
AudioManager audio = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
int currentVolume = audio.getStreamVolume(AudioManager.STREAM_MUSIC);
int delta=previousVolume-currentVolume;
if(delta>0)
{
Logger.d("Decreased");
previousVolume=currentVolume;
}
else if(delta<0)
{
Logger.d("Increased");
previousVolume=currentVolume;
}
}
}
Then in your service onCreate register it with:
mSettingsContentObserver = new SettingsContentObserver(this,new Handler());
getApplicationContext().getContentResolver().registerContentObserver(android.provider.Settings.System.CONTENT_URI, true, mSettingsContentObserver );
Then unregister in onDestroy:
getApplicationContext().getContentResolver().unregisterContentObserver(mSettingsContentObserver);
Yes, you can register a receiver for a volume change(this is kind of a hack, but works), I managed to do it this way (does not involve a ContentObserver):
In manifest xml file:
<receiver android:name="com.example.myproject.receivers.MyReceiver" >
<intent-filter>
<action android:name="android.media.VOLUME_CHANGED_ACTION" />
</intent-filter>
</receiver>
BroadcastReceiver:
public class MyReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals("android.media.VOLUME_CHANGED_ACTION")) {
Log.d("Music Stream", "has changed");
}
}
}
hope it helps!
Based into Nathan's, adi's and swooby's code I created a full working example with some minor improvements.
Looking to the AudioFragment class we can see how easy is to listen for volume changes with our custom ContentObserver.
public class AudioFragment extends Fragment implements OnAudioVolumeChangedListener {
private AudioVolumeObserver mAudioVolumeObserver;
#Override
public void onResume() {
super.onResume();
// initialize audio observer
if (mAudioVolumeObserver == null) {
mAudioVolumeObserver = new AudioVolumeObserver(getActivity());
}
/*
* register audio observer to identify the volume changes
* of audio streams for music playback.
*
* It is also possible to listen for changes in other audio stream types:
* STREAM_RING: phone ring, STREAM_ALARM: alarms, STREAM_SYSTEM: system sounds, etc.
*/
mAudioVolumeObserver.register(AudioManager.STREAM_MUSIC, this);
}
#Override
public void onPause() {
super.onPause();
// release audio observer
if (mAudioVolumeObserver != null) {
mAudioVolumeObserver.unregister();
}
}
#Override
public void onAudioVolumeChanged(int currentVolume, int maxVolume) {
Log.d("Audio", "Volume: " + currentVolume + "/" + maxVolume);
Log.d("Audio", "Volume: " + (int) ((float) currentVolume / maxVolume) * 100 + "%");
}
}
public class AudioVolumeContentObserver extends ContentObserver {
private final OnAudioVolumeChangedListener mListener;
private final AudioManager mAudioManager;
private final int mAudioStreamType;
private int mLastVolume;
public AudioVolumeContentObserver(
#NonNull Handler handler,
#NonNull AudioManager audioManager,
int audioStreamType,
#NonNull OnAudioVolumeChangedListener listener) {
super(handler);
mAudioManager = audioManager;
mAudioStreamType = audioStreamType;
mListener = listener;
mLastVolume = audioManager.getStreamVolume(mAudioStreamType);
}
/**
* Depending on the handler this method may be executed on the UI thread
*/
#Override
public void onChange(boolean selfChange, Uri uri) {
if (mAudioManager != null && mListener != null) {
int maxVolume = mAudioManager.getStreamMaxVolume(mAudioStreamType);
int currentVolume = mAudioManager.getStreamVolume(mAudioStreamType);
if (currentVolume != mLastVolume) {
mLastVolume = currentVolume;
mListener.onAudioVolumeChanged(currentVolume, maxVolume);
}
}
}
#Override
public boolean deliverSelfNotifications() {
return super.deliverSelfNotifications();
}
}
public class AudioVolumeObserver {
private final Context mContext;
private final AudioManager mAudioManager;
private AudioVolumeContentObserver mAudioVolumeContentObserver;
public AudioVolumeObserver(#NonNull Context context) {
mContext = context;
mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
}
public void register(int audioStreamType,
#NonNull OnAudioVolumeChangedListener listener) {
Handler handler = new Handler();
// with this handler AudioVolumeContentObserver#onChange()
// will be executed in the main thread
// To execute in another thread you can use a Looper
// +info: https://stackoverflow.com/a/35261443/904907
mAudioVolumeContentObserver = new AudioVolumeContentObserver(
handler,
mAudioManager,
audioStreamType,
listener);
mContext.getContentResolver().registerContentObserver(
android.provider.Settings.System.CONTENT_URI,
true,
mAudioVolumeContentObserver);
}
public void unregister() {
if (mAudioVolumeContentObserver != null) {
mContext.getContentResolver().unregisterContentObserver(mAudioVolumeContentObserver);
mAudioVolumeContentObserver = null;
}
}
}
public interface OnAudioVolumeChangedListener {
void onAudioVolumeChanged(int currentVolume, int maxVolume);
}
Hope it's still useful for someone! :)
Nathan's and adi's code works, but can be cleaned up and self-contained to:
public class AudioStreamVolumeObserver
{
public interface OnAudioStreamVolumeChangedListener
{
void onAudioStreamVolumeChanged(int audioStreamType, int volume);
}
private static class AudioStreamVolumeContentObserver
extends ContentObserver
{
private final AudioManager mAudioManager;
private final int mAudioStreamType;
private final OnAudioStreamVolumeChangedListener mListener;
private int mLastVolume;
public AudioStreamVolumeContentObserver(
#NonNull
Handler handler,
#NonNull
AudioManager audioManager, int audioStreamType,
#NonNull
OnAudioStreamVolumeChangedListener listener)
{
super(handler);
mAudioManager = audioManager;
mAudioStreamType = audioStreamType;
mListener = listener;
mLastVolume = mAudioManager.getStreamVolume(mAudioStreamType);
}
#Override
public void onChange(boolean selfChange)
{
int currentVolume = mAudioManager.getStreamVolume(mAudioStreamType);
if (currentVolume != mLastVolume)
{
mLastVolume = currentVolume;
mListener.onAudioStreamVolumeChanged(mAudioStreamType, currentVolume);
}
}
}
private final Context mContext;
private AudioStreamVolumeContentObserver mAudioStreamVolumeContentObserver;
public AudioStreamVolumeObserver(
#NonNull
Context context)
{
mContext = context;
}
public void start(int audioStreamType,
#NonNull
OnAudioStreamVolumeChangedListener listener)
{
stop();
Handler handler = new Handler();
AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
mAudioStreamVolumeContentObserver = new AudioStreamVolumeContentObserver(handler, audioManager, audioStreamType, listener);
mContext.getContentResolver()
.registerContentObserver(System.CONTENT_URI, true, mAudioStreamVolumeContentObserver);
}
public void stop()
{
if (mAudioStreamVolumeContentObserver == null)
{
return;
}
mContext.getContentResolver()
.unregisterContentObserver(mAudioStreamVolumeContentObserver);
mAudioStreamVolumeContentObserver = null;
}
}
If its only ringer mode change you can use Brodcast receiver with "android.media.RINGER_MODE_CHANGED" as the action. It will easy to implement
Hi i tried the code above and it did not work for me. But when i tried to add this line
getActivity().setVolumeControlStream(AudioManager.STREAM_MUSIC);
and put
mSettingsContentObserver = new SettingsContentObserver(this,new Handler());
getApplicationContext().getContentResolver().registerContentObserver(android.provider.Settings.System.CONTENT_URI, true, mSettingsContentObserver );
It works now. My concern is how to hide the volume dialog onchange. See this image.
private const val EXTRA_VOLUME_STREAM_TYPE = "android.media.EXTRA_VOLUME_STREAM_TYPE"
private const val VOLUME_CHANGED_ACTION = "android.media.VOLUME_CHANGED_ACTION"
val filter = IntentFilter(VOLUME_CHANGED_ACTION)
filter.addAction(RINGER_MODE_CHANGED_ACTION)
val receiver = object : BroadcastReceiver() {
override fun onReceive(context1: Context, intent: Intent) {
val stream = intent.getIntExtra(EXTRA_VOLUME_STREAM_TYPE, UNKNOWN)
val mode = intent.getIntExtra(EXTRA_RINGER_MODE, UNKNOWN)
val volumeLevel = audioManager.getStreamVolume(stream)
}
}
100% working way in all cases
public class SettingsContentObserver extends ContentObserver {
SettingsContentObserver(Handler handler) {
super(handler);
}
#Override
public boolean deliverSelfNotifications() {
return super.deliverSelfNotifications();
}
#Override
public void onChange(boolean selfChange) {
super.onChange(selfChange);
volumeDialogContract.updateMediaVolume(getMediaVolume());
}
int getMediaVolume() {
return audioManager.getStreamVolume(AudioManager.STREAM_MUSIC);
}
void unRegisterVolumeChangeListener() {
volumeDialogContract.getAppContext().getApplicationContext().getContentResolver().
unregisterContentObserver(settingsContentObserver);
}
void registerVolumeChangeListener() {
settingsContentObserver = new VolumeDialogPresenter.SettingsContentObserver(new Handler());
volumeDialogContract.getAppContext().getApplicationContext().getContentResolver().registerContentObserver(
android.provider.Settings.System.CONTENT_URI, true,
settingsContentObserver);
}

How implement a delegation pattern in c# using delegates?

I want to implement delegation pattern using delegates
public class Cat {
private delegate void SoundDelegate();
private SoundDelegate sound;
public Cat() {
sound = new SoundDelegate(SomeClass.DoSound1);
}
public void DoSound() {
sound();
}
}
public class PussyCat {
private delegate void SoundDelegate();
private SoundDelegate sound;
public PussyCat() {
sound = new SoundDelegate(SomeClass.DoSound2);
}
public void DoSound() {
sound();
}
}
public class SomeClass {
public static void DoSound1() {
Console.WriteLine("Sound 1");
}
public static void DoSound2() {
Console.WriteLine("Sound 2");
}
}
Does this code impelement the delegation pattern? I mean can I use delegates for implement delegation pattern or this way is incorrect.
And if the previous example is correct and I can use delegates to implement the delegation pattern and implement the observer pattern, then what is the difference between the observer pattern and the delegation pattern and what is similar?
The difference between delegation and observer patterns is a level of control your class has over the delegate/observer.
In case of delegate, it's assumed that your class has full control over how delegated class should be used. The observable class has no idea of how exactly it would be used by other classes.
It's also often assumed that observable class could have any number of observers while delegate is usually one.
I also simplified the code provided trying to avoid unnecessarily class PussyCat, so the original class could be configured to use any delegate in runtime.
You can also find CatObservable class to understand the idea of observable-observer implementation.
class Program
{
static void Main(string[] args)
{
Cat cat1 = new Cat(SomeClass.DoSound1);
Cat cat2 = new Cat(SomeClass.DoSound2);
CatObservable cat3 = new CatObservable();
cat3.Sound += Cat3_Sound;
cat3.Sound += (object sender, EventArgs e) => { SomeClass.DoSound1(); } ;
cat3.Sound += (object sender, EventArgs e) => { SomeClass.DoSound2(); };
}
private static void Cat3_Sound(object sender, EventArgs e)
{
throw new NotImplementedException();
}
}
public class Cat
{
public delegate void SoundDelegate();
public SoundDelegate Sound { get; set; }
public Cat(SoundDelegate soundDelagate)
{
Sound = soundDelagate;
}
protected void DoSound()
{
if (Sound!=null)
Sound();
}
}
public class CatObservable
{
public event EventHandler Sound;
public CatObservable()
{
}
protected void DoSound()
{
if (Sound != null)
Sound(this, EventArgs.Empty);
}
}
public class SomeClass
{
public static void DoSound1()
{
Console.WriteLine("Sound 1");
}
public static void DoSound2()
{
Console.WriteLine("Sound 2");
}
}

Showing Google Admob Interstitial ad in Xamarin Forms without delay

I'm working on Xamarin forms project and i have implemented Interstitial ad on all three platforms (Google admob doesn't support UWP). Ads are working fine but they are showing with a delay of 4 to 5 seconds. All i want is to finish that delay so they can show immediately.
PCL class.
public interface IAdmobInterstitial
{
void Show(string adUnit);
}
Droid Code.
public class InterstitialAdListener : AdListener
{
readonly InterstitialAd _ad;
public InterstitialAdListener(InterstitialAd ad)
{
_ad = ad;
}
public override void OnAdLoaded()
{
base.OnAdLoaded();
if (_ad.IsLoaded)
_ad.Show();
}
}
public class AdmobInterstitial : Controls.IAdmobInterstitial
{
InterstitialAd _ad;
public void Show(string adUnit)
{
var context = Android.App.Application.Context;
_ad = new InterstitialAd(context);
_ad.AdUnitId = adUnit;
var intlistener = new InterstitialAdListener(_ad);
intlistener.OnAdLoaded();
_ad.AdListener = intlistener;
var requestbuilder = new AdRequest.Builder().AddTestDevice("302E90D530B2193F59FDD7F22A11B45A");
_ad.LoadAd(requestbuilder.Build());
}
}
iOS Code.
public class AdmobInterstitial : IAdmobInterstitial
{
Interstitial _adInterstitial;
public void Show(string adUnit)
{
_adInterstitial = new Interstitial(adUnit);
var request = Request.GetDefaultRequest();
_adInterstitial.AdReceived += (sender, args) =>
{
if (_adInterstitial.IsReady)
{
var window = UIApplication.SharedApplication.KeyWindow;
var vc = window.RootViewController;
while (vc.PresentedViewController != null)
{
vc = vc.PresentedViewController;
}
_adInterstitial.PresentFromRootViewController(vc);
}
};
_adInterstitial.LoadRequest(request);
}
}
Calling interstitial ad on PCL page.
DependencyService.Get<IAdmobInterstitial>().Show("(id will come here)");
Navigation.PushAsync(new Page());
Ad is showing perfectly but with a delay. I want to show the ad first and then the page.
So i just solved this.
Here is the code.
PCL Class. Add another function to your interface.
public interface IAdmobInterstitial
{
void Show(string adUnit);
void Give();
}
Droid code. Put _ad.Show() in the new function.
public class InterstitialAdListener : AdListener
{
readonly InterstitialAd _ad;
public InterstitialAdListener(InterstitialAd ad)
{
_ad = ad;
}
public override void OnAdLoaded()
{
base.OnAdLoaded();
//if (_ad.IsLoaded)
// _ad.Show();
}
}
public class AdmobInterstitial : Controls.IAdmobInterstitial
{
InterstitialAd _ad;
public void Show(string adUnit)
{
var context = Android.App.Application.Context;
_ad = new InterstitialAd(context);
_ad.AdUnitId = adUnit;
var intlistener = new InterstitialAdListener(_ad);
intlistener.OnAdLoaded();
_ad.AdListener = intlistener;
var requestbuilder = new AdRequest.Builder().AddTestDevice("302E90D530B2193F59FDD7F22A11B45A");
_ad.LoadAd(requestbuilder.Build());
}
public void Give()
{
if (_ad.IsLoaded)
_ad.Show();
}
}
Now, call the function Show() in the constructor of your MainPage in PCL and call the function Give() when you press the button for the next page.
public MainPage()
{
InitializeComponent();
DependencyService.Get<IAdmobInterstitial>().Show("ca-app-pub-3940256099942544/1033173712");
}
private void button_Clicked(object sender, EventArgs e)
{
DependencyService.Get<IAdmobInterstitial>().Give();
Navigation.PushAsync(new Percentage());
}
This is only for Android. Same goes for iOS as well.
I hope it helps the other programmers. :)

MVVMCross Messenger - Subscribing to messages in static class

I am just looking into implementing an MVVMCross Messenger solution that will enable me to upload information to Google Analytics when published from either the iOS application or the PCL.
The problem I have the is that the subscription delgates are not fired after I publish. Can you subscribe to MVVMCross Messenger subscriptions from a static class?
Subscriptions in static class
public static class GoogleAnalyticsWrapper //: IDisposable
{
private const string TrackingId = "xxxxxxxxxxx";
private static readonly IMvxMessenger messenger;
private static readonly MvxSubscriptionToken screenNameToken;
private static readonly MvxSubscriptionToken eventToken;
private static readonly MvxSubscriptionToken exceptionToken;
private static readonly MvxSubscriptionToken performanceToken;
private static readonly MvxSubscriptionToken publishToken;
private static bool disposed = false;
private static SafeHandle handle;
static GoogleAnalyticsWrapper()
{
Gai.SharedInstance.DispatchInterval = 60;
Gai.SharedInstance.TrackUncaughtExceptions = true;
Gai.SharedInstance.GetTracker(TrackingId);
messenger = new MvxMessengerHub();// Mvx.Resolve<IMvxMessenger>();
screenNameToken = messenger.Subscribe<GaScreenNameMessage>((m) => SetScreenName(m));
int count = messenger.CountSubscriptionsFor<GaScreenNameMessage>();
eventToken = messenger.Subscribe<GaEventMessage>(CreateEvent);
exceptionToken = messenger.Subscribe<GaExceptionMessage>(CreateException);
performanceToken = messenger.Subscribe<GaPerformanceTimingMessage>(CreatePerformanceMetric);
publishToken = messenger.Subscribe<GaPublishMessage>(PublishAll);
}
public static string Dummy { get; set; }
public static void SetScreenName(GaScreenNameMessage message)
{
System.Diagnostics.Debugger.Break();
Gai.SharedInstance.DefaultTracker.Set(GaiConstants.ScreenName, message.ScreenName);
Gai.SharedInstance.DefaultTracker.Send(DictionaryBuilder.CreateScreenView().Build());
}
public static void CreateEvent(GaEventMessage message)
=> Gai.SharedInstance.DefaultTracker.Send(DictionaryBuilder.CreateEvent(message.Category, message.Action, message.Label, message.Number).Build());
private static void CreateException(GaExceptionMessage message)
=> Gai.SharedInstance.DefaultTracker.Send(DictionaryBuilder.CreateException(message.ExceptionMessage, message.IsFatal).Build());
private static void CreatePerformanceMetric(GaPerformanceTimingMessage message)
=> Gai.SharedInstance.DefaultTracker.Send(DictionaryBuilder.CreateTiming(message.Category, message.Milliseconds, message.Name, message.Label).Build());
private static void PublishAll(GaPublishMessage message)
=> Gai.SharedInstance.Dispatch();
public static void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
private void Dispose(bool disposing)
{
if (!disposed)
{
if (disposing)
{
// Dispose managed resources.
if (handle != null)
{
handle.Dispose();
}
}
// Dispose unmanaged managed resources.
disposed = true;
}
}
}
Publication
messengerService.Publish<GaEventMessage>(new GaEventMessage(this, "Event", "Publish Event", "Publish Event From First View Model", 123));
The problem is, that you are creating a new MvxMessengerHub in your static class, but (I guess) inject IMvxMessenger in your consuming classes, which is created by MvvMCross during the initialization lifecycle and so a different instance.
The easy solution would be to initialize it in your App.cs like
public class App : Cirrious.MvvmCross.ViewModels.MvxApplication
{
public override void Initialize()
{
// ...
var m = Cirrious.CrossCore.Mvx.Resolve<IMvxMessenger>();
GoogleAnalyticsWrapper.Initialize(m);
// ...
}
}
With a wrapper like this
public static class GoogleAnalyticsWrapper
{
static void Initialize(IMvxMessenger messenger)
{
Gai.SharedInstance.DispatchInterval = 60;
Gai.SharedInstance.TrackUncaughtExceptions = true;
Gai.SharedInstance.GetTracker(TrackingId);
screenNameToken = messenger.Subscribe<GaScreenNameMessage>((m) => SetScreenName(m));
int count = messenger.CountSubscriptionsFor<GaScreenNameMessage>();
eventToken = messenger.Subscribe<GaEventMessage>(CreateEvent);
exceptionToken = messenger.Subscribe<GaExceptionMessage>(CreateException);
performanceToken = messenger.Subscribe<GaPerformanceTimingMessage>(CreatePerformanceMetric);
publishToken = messenger.Subscribe<GaPublishMessage>(PublishAll);
}
// ...
}
Advanced Hint
But as far as I see, you don't even need messaging for this case, because it's one to one "communication". I think it would be nice, if you move the functionality of your GoogleAnalyticsWrapper into a well defined Service like:
interface ITrackingService
{
void SetScreenName(GaScreenNameMessage message);
void CreateEvent(GaEventMessage message);
void CreateException(GaExceptionMessage message);
void CreatePerformanceMetric(GaPerformanceTimingMessage message);
void PublishAll(GaPublishMessage message);
}
public class GoogleAnalyticsTrackingService : ITrackingService
{
private const string TrackingId = "xxxxxxxxxxx";
public GoogleAnalyticsTrackingService()
{
Gai.SharedInstance.DispatchInterval = 60;
Gai.SharedInstance.TrackUncaughtExceptions = true;
Gai.SharedInstance.GetTracker(TrackingId);
}
public void SetScreenName(GaScreenNameMessage message)
{
Gai.SharedInstance.DefaultTracker.Set(GaiConstants.ScreenName, message.ScreenName);
Gai.SharedInstance.DefaultTracker.Send(DictionaryBuilder.CreateScreenView().Build());
}
public void CreateEvent(GaEventMessage message)
{
Gai.SharedInstance.DefaultTracker.Send(DictionaryBuilder.CreateEvent(message.Category, message.Action, message.Label, message.Number).Build());
}
private void CreateException(GaExceptionMessage message)
{
Gai.SharedInstance.DefaultTracker.Send(DictionaryBuilder.CreateException(message.ExceptionMessage, message.IsFatal).Build());
}
private void CreatePerformanceMetric(GaPerformanceTimingMessage message)
{
Gai.SharedInstance.DefaultTracker.Send(DictionaryBuilder.CreateTiming(message.Category, message.Milliseconds, message.Name, message.Label).Build());
}
private void PublishAll(GaPublishMessage message)
{
Gai.SharedInstance.Dispatch();
}
}
That has to be registered in your App
Mvx.LazyConstructAndRegisterSingleton<ITrackingService, GoogleAnalyticsTrackingService>();
And can be consumed with constructor injection or manual resolves
class MyViewModel : MvxViewModel
{
public MyViewModel(ITrackingService tracking)
{
tracking.CreateEvent(new GaEventMessage(this, "Event", "Publish Event", "Publish Event From First View Model", 123));
}
}
// or
class MyViewModel : MvxViewModel
{
public MyViewModel()
{
var tracking = Mvx.Resolve<ITrackingService>();
tracking.CreateEvent(new GaEventMessage(this, "Event", "Publish Event", "Publish Event From First View Model", 123));
}
}
There is still one Problem: The interface has still a dependency to google analytics. But the dependency can be easily removed by using multiple parameters instead of a parameter object.
interface ITrackingService
{
void CreateEvent(string eventName, string title, string message, params object[] additionalParams);
// ...
}
// call:
tracking.CreateEvent("Event", "Publish Event", "Publish Event From First View Model", 123);
With this, you are able to unit test it and exchange the tracking service with litte effort, if your stakeholders decide to switch to adobe omniture or whatever.

Access from my main form class into specific class method

This is my main form class and inside i have Stop button click event:
public partial class MainWin : Form
{
private Job job = new...
private void btnStop_Click(object sender, EventArgs e)
{
job.state = true;
}
}
When my stop button clicked i change my job class member from false to true and what i want to do is when this variable changed to true i want to access to specific method inside job class and do something.
public class Job
{
public bool state { get; set; }
private void processFile() // i want access to this method in order to change other class state
{
// do work
}
}
how can i do it ?
It's really hard to tell what you exactly mean, but one way to invoke a method when the property is set would be to expand the auto property out and do exactly that.
public class Job
{
private bool state;
public bool State
{
get { return this.state; }
set
{
this.state = value;
processFile();
}
private void processFile()
{
// do work
}
}
However, just guessing and seeing this little bit of code, you might want to redesign how you're doing things.
If really don't want to expose you private method, you can do something like this:
public class Job
{
private bool state;
public bool State
{
get
{
return state;
}
set
{
if (state != value)
{
state = value;
OnStateChanged();
}
}
}
private void OnStateChanged()
{
if (state) // or you could use enum for state
Run();
else
Stop();
}
private void Run()
{
// run
}
private void Stop()
{
// stop
}
}
But you should really consider creating public Job.Run method and leaving Job.State readonly. If you want the object to perform some operations, the methods will be more suitable for this.
Create the Job class like this:
public class Job
{
private bool _isRunning = false;
public bool IsRunning { get { return _isRunning; } }
public void StartProcessing()
{
if (_isRunning)
{
// TODO: warn?
return;
}
ProcessFile();
}
public void StopProcessing()
{
if (!_isRunning)
{
// TODO: warn?
return;
}
// TODO: stop processing
}
private void ProcessFile()
{
_isRunning = true;
// do your thing
_isRunning = false;
}
}
Then consume it like this:
public partial class MainWin : For
{
private Job _job = new Job();
private void StartButton_Click(object sender, EventArgs e)
{
if(!_job.IsRunning)
{
_job.StartProcessing();
}
}
private void StopButton_Click(object sender, EventArgs e)
{
if(_job.IsRunning)
{
_job.StopProcessing();
}
}
}
Thread safety left out as exercise.

Categories