Xamarin android OnSharedPreferenceChangeListener - c#

I've got this activity and have a problem with OnSharedPreferenceChanged not being called.
My use case is that i want to show preference value in preference description. Code below translated is translated from java where works perfectly fine.
[Activity]
public class PrefActivity : PreferenceActivity, ISharedPreferencesOnSharedPreferenceChangeListener
{
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
AddPreferencesFromResource(Resource.Xml.preferences);
}
protected override void OnResume()
{
base.OnResume();
PreferenceScreen.SharedPreferences.
RegisterOnSharedPreferenceChangeListener(this);
}
protected override void OnPause()
{
base.OnPause();
PreferenceScreen.SharedPreferences.
UnregisterOnSharedPreferenceChangeListener(this);
}
#region ISharedPreferencesOnSharedPreferenceChangeListener implementation
public void OnSharedPreferenceChanged(ISharedPreferences sharedPreferences, string key)
{
Preference pref = FindPreference(key);
if (pref is ListPreference)
{
ListPreference listPref = (ListPreference)pref;
listPref.Summary = listPref.Entry;
}
}
#endregion
}
Iam using Xamarin.Android v4.6.8 code above is my last attempt to make this working ive also tried using PreferenceScreen.PreferenceChange event for handling preference changes but with no results.
Tahnks for help.

Ive found solution! changing
PreferenceScreen.SharedPreferences.
RegisterOnSharedPreferenceChangeListener(this);
to
PreferenceManager.GetDefaultSharedPreferences(this).
RegisterOnSharedPreferenceChangeListener(this);
will do the trick.
I hope that it will help somebody.

Related

Xamarin Android Listview ClickEvent doesn't work

I am pretty new here, but I have problem and hope that you can help me to solve it. I've created a ListView in Xamarin Android, VS 2017. After configuring it I tried to add a click Event in the MainActivity. Unfortunately, after many tries, I recognized that this is not working. So it doesn't recognize if the ListView is clicked. I know that this is a very basic question, so may there is a simple answer or some basic mistakes I#ve made? Thank you very much!
public class MainActivity : Activity
{
private ListView Lenseslv;
private TextView textView1;
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
SetContentView(Resource.Layout.Main);
Lenseslv = FindViewById<ListView>(Resource.Id.Lenseslv);
textView1 = FindViewById<TextView>(Resource.Id.textView1);
Lenseslv.Adapter = new MyCustomListAdapter(UserData.Users);
}
public void Lenseslv_ItemClick(object sender, AdapterView.ItemClickEventArgs e)
{
textView1.Text = ("ClickEvent");
}
you have to assign the event handler to your ListView
Lenseslv.ItemClick += Lenseslv_ItemClick

If OnAppearing in Xamarin forms is a lifecycle event then why do people add in a base.OnAppearing?

I see this often:
protected override void OnAppearing()
{
base.OnAppearing();
Why do people add base.OnAppearing()
Also:
protected override void OnStart()
{
base.OnStart();
Is it needed to override OnStart and is that also a similar lifecycle event?
OnAppearing is a virtual method defined in the Xamarin.Forms.Page class
namespace Xamarin.Forms
{
[RenderWith(typeof(_PageRenderer))]
public class Page : VisualElement, ILayout, IPageController, IElementConfiguration<Page>, IPaddingElement
{
// ...
protected virtual void OnAppearing()
{
}
// ...
}
}
and gets also called from the base class
[EditorBrowsable(EditorBrowsableState.Never)]
public void SendAppearing()
{
if (_hasAppeared)
return;
_hasAppeared = true;
if (IsBusy)
{
if (IsPlatformEnabled)
MessagingCenter.Send(this, BusySetSignalName, true);
else
_pendingActions.Add(() => MessagingCenter.Send(this, BusySetSignalName, true));
}
OnAppearing(); // <--- here
Appearing?.Invoke(this, EventArgs.Empty);
var pageContainer = this as IPageContainer<Page>;
pageContainer?.CurrentPage?.SendAppearing();
FindApplication(this)?.OnPageAppearing(this);
}
It is very common to call the base method within an overridden method.

Xamarin FOrms iOS: ImageRenderer CreateNativeControl error

I am trying to implement a custom ImageRenderer in iOS subclassing the native UIImageView, but I am having some problems with CreateNativeControl.
In the older Xamarin.Forms version (like 4.2) the custom native class that I initialized with protected override UIImageView CreateNativeControl() { return new NativeImage(); } looks like it never get called (the message I log in the constructor is not shown). The Custom Renderer is correctly initialized (the right message is logged).
In the latest stable version (like 4.4) in overriding of CreateNativeControl the return type it is said that has to be a FormsUIImageView, never heard of it, anyway I also tried to subclass that but same problem as before, it seems it never get called as the constructor message is not logged. The Custom Renderer is correctly initialized (the right message is logged).
Here the code I used:
public class IOSImageView : ImageRenderer
{
public IOSImageView()
{
}
protected override void OnElementChanged(ElementChangedEventArgs<Image> e)
{
base.OnElementChanged(e);
if(Control == null)
{
return;
}
Console.WriteLine("PIPPO created from Custom Renderer"); //this message is correctly logged
}
protected override UIImageView CreateNativeControl() //FormsUIImageView in XF 4.4
{
return new NativeImage();
}
}
public class NativeImage : UIImageView //FormsUIImageView in XF 4.4
{
public NativeImage() : base()
{
Console.WriteLine("PIPPO created from native IOS"); //this message is NOT logged
}
public override void TouchesBegan(NSSet touches, UIEvent evt)
{
base.TouchesBegan(touches, evt);
Console.WriteLine("PIPPO touched"); //this (of course because no NativeImage is shown and there is no image to touch) is NOT logged
}
}
FormsUIImageView is new after XF 4.4 which you can check Xamarin.Forms release notes
In your case , you seems want to set the Image Renderer as your custom ImageView, right?
You should invoked SetNativeControl()
protected override void OnElementChanged(ElementChangedEventArgs<Image> e)
{
base.OnElementChanged(e);
if(Control!=null)
{
SetNativeControl(new NativeImage());
}
}
public class NativeImage : FormsUIImageView
{
public NativeImage() : base()
{
this.UserInteractionEnabled = true;
}
public override void TouchesBegan(NSSet touches, UIEvent evt)
{
base.TouchesBegan(touches, evt);
Console.WriteLine("PIPPO touched"); //this (of course because no NativeImage is shown and there is no image to touch) is NOT logged
}
}

OnBackButtonPressed Not Firing Xamarin Forms

I am trying to prevent the user of my app from pressing the hardware back button.
I have found this code snippet that is in the code behind the xaml file:
protected override bool OnBackButtonPressed()
{
return true;
}
I have tried variations of this including using Boolean instead of Bool and returning base.functionname nothing seems to fire this method.
Here is the bigger context:
Code behind:
namespace Watson.Views
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class StartScan : ContentPage
{
public StartScan()
{
InitializeComponent();
}
protected override bool OnBackButtonPressed()
{
return true;
}
}
}
This is the second page in the stack and disabling the button only needs to happen on this page only, no where else.
Any help would be appreciated.
This is working for me, I tried in Android and iOS platforms using Xamarin.Forms.
Hope you can resolve with this piece of code.
namespace Test
{
public partial class TestPage2 : ContentPage
{
public TestPage2()
{
NavigationPage.SetHasBackButton(this, false);
InitializeComponent();
}
protected override bool OnBackButtonPressed()
{
//return base.OnBackButtonPressed();
return true;
}
}
}
Thanks,
You can also add NavigationPage.SetHasBackButton property in the XAML
NavigationPage.HasBackButton="True"
In the Content Page
You can do this way:
namespace Watson.Views
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class StartScan : ContentPage
{
public StartScan()
{
NavigationPage.SetHasBackButton(this, false);
InitializeComponent();
}
protected override bool OnBackButtonPressed()
{
// you can put some actions here (for example, an dialog prompt, ...)
return true;
}
}
}
For me it is working with the following code (Samsung Android)
protected override bool OnBackButtonPressed()
{
//base.OnBackButtonPressed();
browser.GoBack();
return true;
}
OnBackButtonPressed firing when you click the back button on your device, not from your navigation page, do your logic in OnDisappearing!

MVVMCross - BaseActivity and OnViewModelSet()

I have a little problem, which I can't solve..
Well, I built a BaseActivity.cs Class:
public class BaseActivity<T> : MvxBindingTabActivityView<T> where T : class, IMvxViewModel
{
protected override void OnViewModelSet()
{ }
public override bool OnCreateOptionsMenu(IMenu menu)
{
// GroupId, ItemId, OrderId
menu.Add(0, 0, 0, "Einstellungen").SetIcon(Android.Resource.Drawable.IcMenuManage);
menu.Add(0, 1, 1, "Info").SetIcon(Android.Resource.Drawable.IcMenuInfoDetails);
return true;
}
public override bool OnOptionsItemSelected(IMenuItem item)
{
var id = item.ItemId + 1; // (Id is zero-based :)
if (id == 1) // First Item
{
StartActivity(typeof(SettingsShowActivity));
}
else if (id == 2) // Second Item
{
Android.App.AlertDialog.Builder builder = new AlertDialog.Builder(this);
AlertDialog ad = builder.Create();
ad.SetTitle("Information");
ad.SetIcon(Android.Resource.Drawable.IcDialogAlert);
ad.SetMessage("Version: 0.1");
ad.SetButton("OK", (s, e) => { Console.WriteLine("OK Button clicked, alert dismissed"); });
ad.Show();
}
return true;
}
}
The goal of this class is, that I can put things in that I will use in every other Activity, just like here, the OptionsMenu, which is more or less on all Activities..
Then my other two Activities which are inheriting from BaseActivity.cs:
the MainScreenActivity.cs:
[Activity]
public class MainScreenActivity : BaseActivity<MainScreenViewModel>
{
protected override void OnViewModelSet()
{
SetContentView(Resource.Layout.MainScreenLayout);
TabHost.TabSpec spec;
Intent intent;
intent = base.CreateIntentFor<AddressesSearchViewModel>();
intent.AddFlags(ActivityFlags.NewTask);
spec = TabHost.NewTabSpec("adressen");
spec.SetIndicator("Adressen");
spec.SetContent(intent);
TabHost.AddTab(spec);
intent = base.CreateIntentFor<ContactsSearchViewModel>();
intent.AddFlags(ActivityFlags.NewTask);
spec = TabHost.NewTabSpec("kontaktpersonen");
spec.SetIndicator("Kontaktpersonen");
spec.SetContent(intent);
TabHost.AddTab(spec);
}
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
}
}
and the LoginActivity.cs:
[Activity]
public class LoginActivity : BaseActivity<LoginViewModel>
{
protected override void OnResume()
{
base.OnResume();
App.IsLoggedIn = false;
}
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
}
protected override void OnViewModelSet()
{
SetContentView(Resource.Layout.Login);
//App.MessageHub.Subscribe<ErrorMessage>((m) => { ErrorMessageAlert(m.Message, m.Title); });
}
}
Its compiling fine, but the app crashes when I start it, and thats the errormessage I get: Your content must have a TabHost whose id attribute is 'android.R.id.tabhost' . I suggest, that it is because I "needed" to implement the abstract interface into the BaseActivity.cs :
protected override void OnViewModelSet()
{ }
So maybe he walks into the 'false' OnViewModelSet(), (In the empty one instead of the one which is building the Tabhost).. but I'm actually not sure.. btw this comes from: MvxBindingTabActivityView..
Hmm any help would be appreciated
I think this is a quite simple problem...
MvxBindingTabActivityView inherits from TabActivity (see source) and it's this class that requires the content - Your content must have a TabHost whose id attribute is 'android.R.id.tabhost'
If you don't want to use Tabs, then just inherit from MvxBindingActivityView instead - this is what the conference sample does - https://github.com/slodge/MvvmCross/blob/vnext/Sample%20-%20CirriousConference/Cirrious.Conference.UI.Droid/Views/BaseView.cs
If one of your activities needs to do tabs, but the other doesn't then they need to inherit using different inheritance trees. If you want to share code between the two base classes, then the best way to do this in C# seems to be using extension methods - e.g. see BaseViewExtensionMethods.cs shared between BaseView.cs, BaseTabbedView.cs and BaseMapView.cs in the conference sample.

Categories