Question

I've implemented this custom DialogPreference in C# with Xamarin however I'm having issues adding it to my xml file.

namespace Client.Android
{
public class TimePreference : DialogPreference
{
    private int lastHour = 0;
    private int lastMinute = 0;
    private TimePicker picker = null;

    public static int GetHour(string time)
    {
        string[] pieces = time.Split (':');
        return Convert.ToInt32 (pieces [0]);
    }

    public static int GetMinute(string time)
    {
        string[] pieces = time.Split (':');
        return Convert.ToInt32 (pieces [1]);
    }

    public TimePreference(Context context, IAttributeSet attSet) : base(context, attSet)
    {
        SetPositiveButtonText (Resource.String.time_preference_set);
        SetNegativeButtonText (Resource.String.time_preference_cancel);
    }

    protected override View OnCreateDialogView ()
    {
        picker = new TimePicker (Context);
        return picker;
    }

    protected override void OnBindDialogView (View view)
    {
        base.OnBindDialogView (view);
        picker.CurrentHour = (Java.Lang.Integer) lastHour;
        picker.CurrentMinute = (Java.Lang.Integer) lastMinute;
    }

    protected override void OnDialogClosed (bool positiveResult)
    {
        base.OnDialogClosed (positiveResult);

        if (positiveResult) {
            lastHour = (int) picker.CurrentHour;
            lastMinute = (int) picker.CurrentMinute;

            string time = lastHour + ":" + lastMinute;

            if (CallChangeListener (time)) {
                PersistString (time);
            }
        }
    }

    protected override Java.Lang.Object OnGetDefaultValue (TypedArray a, int index)
    {
        return a.GetString (index);
    }

    protected override void OnSetInitialValue (bool restorePersistedValue, Java.Lang.Object defaultValue)
    {
        string time = string.Empty;

        if (restorePersistedValue) {
            if (defaultValue == null) {
                time = GetPersistedString ("00:00");
            } else {
                time = GetPersistedString (defaultValue.ToString ());
            }
        } else {
            time = defaultValue.ToString ();
        }

        lastHour = GetHour (time);
        lastMinute = GetMinute (time);
    }
}
}

My projects name/default namespace is "Client.Android" and I've tried adding it to my xml file like so:

<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" >
    <PreferenceCategory android:title="@string/pref_foo" >
    ...

    <Client.Android.TimePreference
         android:title="@string/pref_bar"
         android:key="@string/prefkey_bar"
         android:defaultValue="12:00" />
    ...
    </PreferenceCategory>
</PreferenceScreen>

But I get the following exception on AddPreferencesFromResource(Resource.Xml.settings); of my OnCreate method:

    Android.Views.InflateException: Binary XML file line #32: Error inflating class Client.Android.TimePreference
  at Android.Runtime.JNIEnv.CallNonvirtualVoidMethod (intptr,intptr,intptr,Android.Runtime.JValue[]) [0x00084] in /Users/builder/data/lanes/monodroid-mlion-monodroid-4.12-series/7f0e3d3c/source/monodroid/src/Mono.Android/src/Runtime/JNIEnv.g.cs:895
  at Android.Preferences.PreferenceActivity.AddPreferencesFromResource (int) [0x00070] in /Users/builder/data/lanes/monodroid-mlion-monodroid-4.12-series/7f0e3d3c/source/monodroid/src/Mono.Android/platforms/android-19/src/generated/Android.Preferences.PreferenceActivity.cs:729
  at Client.Android.SettingsActivity.OnCreate (Android.OS.Bundle) [0x00015] in c:\pushtotalk\Client.Android\SettingsActivity.cs:45
  at Android.App.Activity.n_OnCreate_Landroid_os_Bundle_ (intptr,intptr,intptr) [0x00011] in /Users/builder/data/lanes/monodroid-mlion-monodroid-4.12-series/7f0e3d3c/source/monodroid/src/Mono.Android/platforms/android-19/src/generated/Android.App.Activity.cs:2178
  at at (wrapper dynamic-method) object.7c9f4d4d-9496-4803-b019-cd453beeee8b (intptr,intptr,intptr) <IL 0x00017, 0x00043>
  at --- End of managed exception stack trace ---
  at android.view.InflateException: Binary XML file line #32: Error inflating class Client.Android.TimePreference
  at at android.preference.GenericInflater.createItemFromTag(GenericInflater.java:441)
  at at android.preference.GenericInflater.rInflate(GenericInflater.java:481)
  at at android.preference.GenericInflater.rInflate(GenericInflater.java:493)
  at at android.preference.GenericInflater.inflate(GenericInflater.java:326)
  at at android.preference.GenericInflater.inflate(GenericInflater.java:263)
  at at android.preference.PreferenceManager.inflateFromResource(PreferenceManager.java:272)
  at at android.preference.PreferenceActivity.addPreferencesFromResource(PreferenceActivity.java:1472)
  at at client.android.SettingsActivity.n_onCreate(Native Method)
  at at client.android.SettingsActivity.onCreate(SettingsActivity.java:32)
  at at android.app.Activity.performCreate(Activity.java:5231)
  at at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1087)
  at at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2159)
  at at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2245)
  at at android.app.ActivityThread.access$800(ActivityThread.java:135)
  at at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1196)
  at at android.os.Handler.dispatchMessage(Handler.java:102)
  at at android.os.Looper.loop(Looper.java:136)
  at at android.app.ActivityThread.main(ActivityThread.java:5017)
  at at java.lang.reflect.Method.invokeNative(Native Method)
  at at java.lang.reflect.Method.invoke(Method.java:515)
  at at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:779)
  at at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:595)
  at at dalvik.system.NativeStart.main(Native Method)
  at Caused by: java.lang.ClassNotFoundException: Didn't find class "Client.Android.TimePreference" on path: DexPathList[[zip file "/data/app/Client.Android-1.apk"],nativeLibraryDirectories=[/data/app-lib/Client.Android-1, /vendor/lib, /system/lib]]
  at at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:56)
  at at java.lang.ClassLoader.loadClass(ClassLoader.java:497)
  at at java.lang.ClassLoader.loadClass(ClassLoader.java:457)
  at at android.preference.GenericInflater.createItem(GenericInflater.java:375)
  at at android.preference.GenericInflater.createItemFromTag(GenericInflater.java:430)
  at ... 22 more
Was it helpful?

Solution

These are the default attributes available (You can also view inherited attributes by expanding the Inherited XML Attributes block in the android docs for DialogPreference):

android:dialogIcon - The icon for the dialog. 
android:dialogLayout - A layout to be used as the content View for the dialog. 
android:dialogMessage - The message in the dialog. 
android:dialogTitle - The title in the dialog. 
android:negativeButtonText - The negative button text for the dialog. 
android:positiveButtonText - The positive button text for the dialog. 

So in order to use your own attributes you need to create your own Resource file where you define Stylables for your DialogPreference like:

Resource\Values\MyTimePreferenceAttrs.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="MyTimePreference">
        <attr name="defaultValue" format="string"/>
    </declare-styleable>
</resources>

Then in your AXML layout where you create your TimePreference view you need to add a namespace so that they can be resolved:

<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:my="http://schemas.android.com/apk/res-auto" >
    <PreferenceCategory android:title="@string/pref_foo" >
    ...

    <Client.Android.TimePreference
         my:defaultValue="12:00" />
    ...
    </PreferenceCategory>
</PreferenceScreen>

Then in your constructor of TimePreference you can get the value with something like:

var ta = context.ObtainStyledAttributes(attrs, Resource.Styleable.MyTimePreference);
var defaultValue = ta.GetString(Resource.Styleable.MyTimePreference_defaultValue);
ta.Recycle();

You also might have a problem with using capitalized namespace in your XML layout. However the classname stays Capitalized, so:

<client.android.TimePreference
    ...
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top