I am trying to override the default behavior of the Android button renderer in Xamarin Forms. I have leveraged (not stolen;) the source code from https://learn.microsoft.com/en-us/xamarin/xamarin-forms/user-interface/visual/create and have created this:
namespace Patron.Droid.Renderers
{
public class MixedCaseButtonRenderer : Xamarin.Forms.Platform.Android.AppCompat.ButtonRenderer
{
public MixedCaseButtonRenderer(Context context) : base(context)
{
}
protected override void OnElementChanged(ElementChangedEventArgs<Button> el)
{
base.OnElementChanged(el);
if (el.OldElement != null)
{
// Cleanup
}
if (el.NewElement != null)
{
var button = (Button)this.Control;
button.SetAllCaps(false);
}
}
}
}
But when I build it, I get the following errors
Severity Code Description Project File Line Suppression State
Error CS0115 'MixedCaseButtonRenderer.OnElementChanged(ElementChangedEventArgs<Button>)': no suitable method found to override Patron.Android C:\Users\ThomH\workspace\patron\Patron\Patron\Patron.Android\Renderers\MixedCaseButtonRenderer.cs 22 Active
Error CS0311 The type 'Android.Widget.Button' cannot be used as type parameter 'TElement' in the generic type or method 'ElementChangedEventArgs<TElement>'. There is no implicit reference conversion from 'Android.Widget.Button' to 'Xamarin.Forms.Element'. Patron.Android C:\Users\ThomH\workspace\patron\Patron\Patron\Patron.Android\Renderers\MixedCaseButtonRenderer.cs 22 Active
Error CS1503 Argument 1: cannot convert from 'Xamarin.Forms.Platform.Android.ElementChangedEventArgs<Android.Widget.Button>' to 'Xamarin.Forms.Platform.Android.ElementChangedEventArgs<Xamarin.Forms.Button>' Patron.Android C:\Users\ThomH\workspace\patron\Patron\Patron\Patron.Android\Renderers\MixedCaseButtonRenderer.cs
Button exists in both Android.Widget and Xamarin.Forms. You need to specify which namespace you mean to use
Related
I'm trying to create a custom Debug Tree class to get the same result as the following:
I have followed this Stackoverflow answer:
Log method name and line number in Timber
But using that answer gives me two problems:
Implementing the custom Debug Tree class does not log anything when I use more than one method.
public class MyDebugTree extends Timber.DebugTree {
#Override
protected String createStackElementTag(StackTraceElement element) {
return String.format("(%s:%s)#%s",
element.getFileName(),
element.getLineNumber(),
element.getMethodName());
}
}
public class BaseApplication extends Application {
#Override
public void onCreate() {
super.onCreate();
if (BuildConfig.DEBUG) {
Timber.plant(new MyDebugTree);
}
}
}
The above causes it to not log at all.
If I use only return element.getFileName(); it successfully logs that one error.
The second problem I'm having is that using a custom DebugTree class does not give me the same results as using err.getStackTrace()[0].getLineNumber().
}, err -> {
Timber.e("Method name: " + err);
Timber.e("Method name: " + err.getStackTrace()[0].getMethodName());
}
The custom Debug Tree class does not display the name of the method I'm trying to log.
Why is it not logging when I use all three methods?
Also how can I get it to log like it would using
err.getStackTrace()[0].getMethodName()?
I'm using 'com.jakewharton.timber:timber:4.7.1'
You seem to be doing it right. I recreated your code in kotlin (programming language should not matter) and i was able to show my logs.
MyDebugTree.kt
class QueenlyDebugTree : Timber.DebugTree() {
override fun createStackElementTag(element: StackTraceElement): String {
return "(${element.fileName}:${element.lineNumber})#${element.methodName}"
}
}
force log using an actual exception:
try {
throw RuntimeException("Hello World")
} catch (e: Exception) {
Timber.e(e)
}
i got a log:
So, from what i saw from your code, its most probably because you have a compact logcat view. To update your logcat view, follow these steps:
1. Make sure you have standard view selected
2. Configure standard view
3. Make sure Show tags is selected and tag column is at max(35)
I am rewriting my vanilla Xamarin app to use Prism Library.
The current app uses Azure ADB2C for authorisation using this framework.
Android needs to have its parent window set, which is achieved by adding this code into the MainActivity.cs of the Android project:
var authenticationService = DependencyService.Get<IAuthenticationService>();
authenticationService.SetParent(this);
This doesn't work for the Prism app, authenticationService is null. For the record, the DependencyService used here is Xamarin.Forms.DependencyService.
I also tried the example from the Prism docs and put this code into the AndroidInitializer:
public void RegisterTypes(IContainerRegistry container)
{
// Register any platform specific implementations
container.RegisterSingleton<IAuthenticationService, B2CAuthenticationService>("B2CAuthenticationService");
var authService = Container.Resolve<IAuthenticationService>();
authService.SetParent(this);
}
In this code, Container (which is a DryIoC Container) had no definition for Resolve.
For completeness, this is my App.cs RegisterTypes:
protected override void RegisterTypes(IContainerRegistry containerRegistry)
{
containerRegistry.RegisterSingleton<IAuthenticationService, B2CAuthenticationService>();
...
...
}
There are a few wrong assumptions you're making here. To start you'll notice that IContainerRegistry specifically has the name Registry in it to imply we don't want you resolving types here. This is why you don't see the Resolve method on it but rather the IContainerProvider instance.
By design, Prism no longer works directly with the Xamarin.Forms DependencyService as this is a complete anti-pattern. That said if you follow the guidance for registering Platform Specific types you can see how to use the IPlatformInitializer to register platform specific types. It is important to realize here that the IPlatformInitializer is called before RegisterTypes is called in PrismApplication.
What I would suggest is to introduce a IParentWindowProvider like:
public interface IParentWindowProvider
{
object Parent { get; }
}
You can then implement this on Android like:
public class MainActivity : IPlatformInitializer, IParentWindowProvider
{
object IParentWindowProvider.Parent => this;
void IPlatformInitializer.RegisterTypes(IContainerRegistry containerRegistry)
{
containerRegistry.RegisterInstance<IParentWindowProvider>(this);
}
}
Then in your Application you might do something like:
protected override void OnInitialized()
{
if(Container.IsRegistered<IParentWindowProvider>())
{
var provider = Container.Resolve<IParentWindowProvider>();
var authService = Container.Resolve<IAuthenticationService>();
authService.SetParent(provider.Parent);
}
}
For more info be sure to check out the relevant docs and sample
https://prismlibrary.com/docs/xamarin-forms/dependency-injection/platform-specific-services.html
https://github.com/PrismLibrary/Prism-Samples-Forms/tree/master/03-PlatformSpecificServices
I've just migrated to MvvmCross 4 and my app uses fragments. The Setup class is as follows:
public class Setup : MvxAndroidSetup
{
public Setup(Context applicationContext) : base(applicationContext)
{
}
protected override IMvxApplication CreateApp()
{
return new AN.Core.App();
}
protected override IMvxTrace CreateDebugTrace()
{
return new DebugTrace();
}
protected override IEnumerable<Assembly> AndroidViewAssemblies => new List<Assembly>(base.AndroidViewAssemblies)
{
typeof(Android.Support.V7.Widget.Toolbar).Assembly,
typeof(Android.Support.V4.Widget.DrawerLayout).Assembly,
typeof(Android.Support.V4.View.ViewPager).Assembly,
typeof(MvvmCross.Droid.FullFragging).Assembly,
};
protected override IMvxAndroidViewPresenter CreateViewPresenter()
{
return new MvxFragmentsPresenter(AndroidViewAssemblies);
}
What is the proper Assembly to reference in the last entry of AndroidViewAssemblies? Is there a more optimal way of resolving the error received?
On here, it lists several references that are under the MvvmCross.Droid.FullFragging namespace.
Your not specifying a Type to then get the Assembly.
As your only interested in the .Assembly you must specify one of the classes, for instance instead of:-
typeof(MvvmCross.Droid.FullFragging).Assembly
try...
typeof(Cirrious.MvvmCross.Droid.FullFragging.MvxOwnedViewModelFragmentAttribute).Assembly
That will at least get around that 'namespace but is used like a type' error your experiencing.
I'm currently trying to develop an application under Android using Mono.
I'd like to add support for plugins to my application so additional features could be brought to it.
I was able to load simple .dll at runtime in my program, however whenever I try creating a dll implementing both my interface and a custom activity, an exception of type Java.Lang.NoClassDefFoundError is thrown.
There is the class inside the dll code:
[Activity (Label = "Vestiaire")]
public class Vestiaire : Activity, IModule
{
public string Name { get; set; }
public string Version { get; set; }
void OnClickVestiaireButton(object sender, System.EventArgs e)
{
;
}
public void InitVestiaireModule()
{
Run();
}
public Type LaunchActivity ()
{
return typeof(Vestiaire);
}
public void Init()
{
Name = "Vestiaire Module";
Version = "0.1";
}
public void Run()
{
}
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
}
}
The line responsible for the exception: (from the program core)
LoadedPlugin.Add((IModule)(Activator.CreateInstance(Plugin)));
Things I'm actually wonderring are:
- Is it possible to actually achieve what i'm trying to ?
If yes, help would be apreciated on that problem :P
Otherwise what would be the best alternative ?
Global point is to be able to load a custom menu at runtime loaded from a dll.
Thanks.
i think the key to your problem is that the Activity needs to be registered in you Manifest.xml file.
For Activities in you main app, MonoDroid does this for you - but I don't think this will work for your plugin.
Things you could try are:
putting the Activity in the Manifest yourself (MonoDroid does seem very capable at merging these files)
if that doesn't work, then you could try using a Fragment instead - and loading the Fragment into a custom FragmentActivity in your main app.
I am trying to add one function in a class which is in a grouped namespace, I am adding function declaration in a class which is .h file, and I am defining the function in .cpp file, and trying to call that from other function in same class. when I am trying to compile the whole, it is giving issue, no such function declared in the scope.
fyi-its a android source in which we are trying to add a function to one library
please suggest, whether we need to add the function declaration in any other places, for this name space.
ERROR: No function "my_mCamera()" declared in the scope
SOURCE:
CameraHardware.h:
namespace android
{
class CameraHardware : public CameraHardwareInterface
{
public:
void my_mCamera(); //Added new function
virtual sp<IMemoryHeap> getPreviewHeap() const;
virtual sp<IMemoryHeap> getRawHeap() const;
// other required function
};
};
CameraHardware.cpp
void CameraHardware::setZoom(const CameraParameters & params)
{
my_mCamera(); // new Function
LOGE("surya: inside setZoom function");
LOGV("surya: mParameters.KEY_ZOOM=%d",mParameters.KEY_ZOOM);
if (mParameters.get(mParameters.KEY_ZOOM) == NULL)
{
LOGE("%s Error! mParameters.KEY_ZOOM == NULL", _FUNCTION_);
return;
}
if ((mParameters.getInt("zoom") != mPreviousZoom))
{
LOGE("surya: checking for previous zoom");
if (mCamera)
{
LOGE("surya: looking for CameraObject in set zoom");
cam_parm.zoom = mCamera->convert_zoom(params);
mCamera->setZoom(&cam_parm);
}
}
LOGE("surya: working with previous zoom");
mPreviousZoom = mParameters.getInt("zoom");
}
//-------------------creating mBroadcomCamera :surya----------------
void CameraHardware::my_mCamera()
{
LOGV("surya; creating mCameraObject");
int preview_width=320, preview_height=240;
mCamera = new MyCamera(preview_width, preview_height, 0); // constructor of other class which is in the same namespace
}