How to bind CGPDFDocumentRef? - xamarin.ios

I assume CGPDFDocumentRef should be bind to CGPDFDocument
I'm trying the following
//- (id)initWithPDFDocument:(CGPDFDocumentRef)_document filepath:(NSString *)fullFilePath;
[Export("initWithPDFDocument:filepath:")]
IntPtr Constructor (CGPDFDocument document, string path);
I'm also including:
using MonoTouch.CoreGraphics;
When I try to compile my binding project, I'm getting following error:
: error BI1002: btouch: Unknown kind MonoTouch.CoreGraphics.CGPDFDocument document in method 'pdftest.ReaderDocument.Constructor'
EDIT:
After input from poupou, I have the following:
[BaseType (typeof (NSObject))]
partial interface ReaderDocument {
[Export("initWithPDFDocument:filepath:")]
[Internal] IntPtr Constructor (IntPtr document, string path);
AND in extras.cs:
public partial class ReaderDocument {
public ReaderDocument (CGPDFDocument doc, string path) : this (doc.Handle, path) { }
}
I can Build my bindingproject in MonoDevelop, but I'm getting following error in btouch.
I'm using the command "/Developer/MonoTouch/usr/bin/btouch MyBindingLib.cs -s:extras.cs"
MyBindingLib.cs(12,19): error CS0260: Missing partial modifier on declaration
of type `mybindingtest.ReaderDocument'. Another partial declaration of this type
exists
extras.cs(6,30): (Location of the symbol related to previous error)
extras.cs(6,30): error CS0261: Partial declarations of `mybindingtest.ReaderDocument'
must be all classes, all structs or all interfaces

btouch does not know every types that exists, only the basic ones and the one you define. In this case you can bind this in two steps.
First bind CGPDFDocumentRef as an IntPtr and decorate it as [Internal].
[Export("initWithPDFDocument:filepath:")]
[Internal]
IntPtr Constructor (IntPtr document, string path);
Next add a custom constructor in your Extra.cs file.
partial public class YourType {
public YourType (CGPDFDocument doc, string path) : this (doc.Handle, path) { }
}

There's an example that uses a CGPDFDocument in the Core Graphics seminar:
http://www.youtube.com/watch?v=MNxVMYKaZP0
The relevant code is here:
https://github.com/xamarin/Seminars/blob/master/2012-01-26-CoreGraphics/XaminarPDFDemo/XaminarPDFDemo/PDFView.cs

Related

Register and Resolve Generic Objects

i have some problems with Register my Interfaces.
I have the following Interfaces:
public interface IMapper<Q, T> { /* Mapper Helper Methods */ }
public interface ISourceObject { /* Properties */ }
public interface ITargetObject { /* Properties */ }
The Implementations are:
public class GenericMapper<Q, T> : IMapper<Q,T> { /* Mapper Helper Methods */ }
public class SourceObject : ISourceObject { /* Properties */ }
public class TargetObject : ITargetObject { /* Properties */ }
In my Autofac Module i want to Register it as following:
builder.RegisterType<GenericMapper<SourceObject, TargetObject>>().As<IMapper<ISourceObject, ITargetObject>>();
And resolve it via:
Container.Resolve<IMapper<ISourceObject, ITargetObject>>();
The Automapper Profile Configuration is:
CreateMap<ISourceObject, ITargetObject>()
// ForMember Mappings
.ForAllMembers(o => o.Condition((src, dest, value) => value != null));
When i start my Unittest, it crashes with the following Stacktrace:
at Autofac.Builder.RegistrationBuilder.CreateRegistration(Guid id, RegistrationData data, IInstanceActivator activator, IEnumerable`1 services, IComponentRegistration target)
at Autofac.Builder.RegistrationBuilder.CreateRegistration[TLimit,TActivatorData,TSingleRegistrationStyle](IRegistrationBuilder`3 builder)
at Autofac.Builder.RegistrationBuilder.RegisterSingleComponent[TLimit,TActivatorData,TSingleRegistrationStyle](IComponentRegistry cr, IRegistrationBuilder`3 builder)
at Autofac.RegistrationExtensions.<>c__DisplayClass3_0`1.<RegisterType>b__0(IComponentRegistry cr)
at Autofac.ContainerBuilder.Build(IComponentRegistry componentRegistry, Boolean excludeDefaultModules)
at Autofac.ContainerBuilder.Build(ContainerBuildOptions options)
System.ArgumentException:
System.ArgumentException: The type 'App.Test.Models.GenericMapper`2[App.Test.Models.SourceObject,App.Test.Models.TargetObject]' is not assignable
to service 'App.Test.Models.IMapper`2[[App.Test.Models.ISourceObject, App.Test, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null],
[App.Test.Models.ITargetObject, App.Test, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]'..
What do i wrong here?
When i Register the Implementations, the resolving works without a Problem. But it would be Hardwired to the implementations and that, i dont want. Can i resolve it that way or do i have to use the hard wired Version?
What you have is a problem with your interface definitions. If you pull Autofac entirely out of the mix and just test it manually, you can see the evidence:
[Fact]
public void TypesAreCompatible()
{
var init = new GenericMapper<SourceObject, TargetObject>();
var cast = (IMapper<ISourceObject, ITargetObject>)init;
Assert.Same(init, cast);
}
This will fail on the line that starts with var cast and give the exception:
System.InvalidCastException : Unable to cast object of type 'GenericMapper`2[SourceObject,TargetObject]' to type 'IMapper`2[ISourceObject,ITargetObject]'.
The reason is that your IMapper interface is not covariant. In simpler terms, that means you can't put a more derived type in as Q or T and have it "magically work." It has to be exact.
Update your interface to tell C# that it's OK to use covariant types by putting out in front of the type parameters.
public interface IMapper<out Q, out T> { }
Once you do that, the test I put above will work... and so will the Autofac registration.

Error while building the solution in vs2012?

I've created my project in vs2008.It works fine.But when i opened the solution and try to build it in vs2012 i am getting the following error in TransactionDB.dbml page.
a partial method may not have multiple defining declarations
What could be the problem??
.net supports partial methods.
It means you write a definition in one part of the partial class and the implementation in another. Like this:
partial class MyClass
{
partial void MyPartialMethod(string s);
}
// This part can be in a separate file.
partial class MyClass
{
// Comment out this method and the program will still compile.
partial void MyPartialMethod(string s)
{
Console.WriteLine("Something happened: {0}", s);
}
}
In your case I you have the two definitions of the partial method causing the compiler to fail.
Source MSDN
The defining declaration of a partial method is the part that specifies the method signature, but not the implementation (method body). A partial method must have exactly one defining declaration for each unique signature. Each overloaded version of a partial method must have its own defining declaration.
To correct this error
Remove all except one defining declaration for the partial method.
Example
// cs0756.cs
using System;
public partial class C
{
partial void Part();
partial void Part(); // CS0756
public static int Main()
{
return 1;
}
}

Regarding String functionality

I was developing the below class..
public class Test1
{
public void method(Object o)
{
System.out.println("Object Verion");
}
public void method(String s)
{
System.out.println("String Version");
}
public static void main(String args[])
{
Test1 question = new Test1();
//question.method(question);
question.method(null);
}
}
Now upon executing it invokes string version as output So please advise here string is treated as null and what should we pass to invoke the object version.Thanks in advance
All other things being equal, the most-specific method will be called. From the JLS:
15.12.2.5. Choosing the Most Specific Method
If more than one member method is both accessible and applicable to a
method invocation, it is necessary to choose one to provide the
descriptor for the run-time method dispatch. The Java programming
language uses the rule that the most specific method is chosen.
The informal intuition is that one method is more specific than
another if any invocation handled by the first method could be passed
on to the other one without a compile-time type error.
question.method(null) could mean either the String or Object overload, but since String is more specific (narrower) than Object, the String overload is the method that is called.

Mono Android: Java Android custom view JNI not calling constructors in xml layout

We're using Mono for Android, and we want to use a few custom view subclasses that we have written in Java Android. We created a C# "bridge" class to expose the Java class through JNI. The method overrides and custom methods we exposed are working fine when called from C# through the C# bridge class, but when we use the class in an XML layout (by referencing the fully qualified java namespace for the view), it never seems to call the constructor through C#, so the C# type does not get set properly.
XML Layout
<merge xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<com.example.widget.ImageView:id="#+id/custom_view" />
</merge>
C# "Bridge" class constructors
namespace Example.Widgets {
[Register ("com/example/widget/ImageView", DoNotGenerateAcw=true)]
public class ImageView : global::Android.Widget.ImageView {
private new static IntPtr class_ref = JNIEnv.FindClass("com/example/widget/ImageView");
private static IntPtr id_ctor_Landroid_content_Context_;
private static IntPtr id_ctor_Landroid_content_Context_Landroid_util_AttributeSet_;
private static IntPtr id_ctor_Landroid_content_Context_Landroid_util_AttributeSet_I;
...
protected override IntPtr ThresholdClass {
get {
return ImageView.class_ref;
}
}
protected override Type ThresholdType {
get {
return typeof(ImageView);
}
}
protected ImageView (IntPtr javaReference, JniHandleOwnership transfer) : base (javaReference, transfer) {
}
// --V-- this should get called by the android layout inflater, but it never does (nor do any of the other public constructors here)
[Register (".ctor", "(Landroid/content/Context;Landroid/util/AttributeSet;)V", "")]
public ImageView (Context context, IAttributeSet attrs) : base (IntPtr.Zero, JniHandleOwnership.DoNotTransfer)
{
Log.Debug("ImageView","Calling C# constructor (Landroid/content/Context;Landroid/util/AttributeSet;)V");
if (base.Handle != IntPtr.Zero)
{
return;
}
if (base.GetType () != typeof(ImageView))
{
base.SetHandle (JNIEnv.CreateInstance (base.GetType (), "(Landroid/content/Context;Landroid/util/AttributeSet;)V", new JValue[]
{
new JValue (JNIEnv.ToJniHandle (context)),
new JValue (JNIEnv.ToJniHandle (attrs))
}), JniHandleOwnership.TransferLocalRef);
return;
}
if (ImageView.id_ctor_Landroid_content_Context_Landroid_util_AttributeSet_ == IntPtr.Zero)
{
ImageView.id_ctor_Landroid_content_Context_Landroid_util_AttributeSet_ = JNIEnv.GetMethodID (ImageView.class_ref, "<init>", "(Landroid/content/Context;Landroid/util/AttributeSet;)V");
}
base.SetHandle (JNIEnv.NewObject (ImageView.class_ref, ImageView.id_ctor_Landroid_content_Context_Landroid_util_AttributeSet_, new JValue[]
{
new JValue (JNIEnv.ToJniHandle (context)),
new JValue (JNIEnv.ToJniHandle (attrs))
}), JniHandleOwnership.TransferLocalRef);
}
[Register (".ctor", "(Landroid/content/Context;)V", "")]
public ImageView (Context context) : base (IntPtr.Zero, JniHandleOwnership.DoNotTransfer) {
...
}
[Register (".ctor", "(Landroid/content/Context;Landroid/util/AttributeSet;I)V", "")]
public ImageView (Context context, IAttributeSet attrs, int defStyle) : base (IntPtr.Zero, JniHandleOwnership.DoNotTransfer) {
...
}
...
Java Class
package com.example.widget;
public class ImageView extends android.widget.ImageView {
//--V-- This constructor DOES get called here (in java)
public ImageView(Context context, AttributeSet attrs) {
super(context, attrs);
Log.d(TAG, "Called Java constructor (context, attrs)");
...
}
}
When we stop at a breakpoint in the program, we see that the local for our image view is of type Android.Widgets.ImageView, but holds the value {com.example.widget.ImageView#4057f5d8}. We're thinking that the type should show Example.Widgets.ImageView as well, but we can't figure out how to get .NET to use this type instead of the inherited Android type (Android.Widgets.ImageView).
Any ideas how to get .NET to call constructors properly when views exposed through JNI are used in XML layout?
Thanks in advance
The problem is that I haven't fully documented/explained what RegisterAttribute.DoNotGenerateAcw does, for which I must apologize.
Specifically, the problem is this: Android Layout XML can only refer to Java types. Normally this isn't a problem, as Android Callable Wrappers are generated at build-time, providing Java types for every C# type which subclasses Java.Lang.Object.
However, Android Callable Wrappers are special: they contain Java native method declarations, and Android Callable Wrapper constructors call into the Mono for Android runtime to create the relevant C# class. (See the example at the above url, and notice that the constructor body calls mono.android.TypeManager.Activate().)
Your example, however, completely bypasses all of that, because your layout XML isn't referencing an Android Callable Wrapper, it's instead referencing your Java type, and your Java type doesn't have a constructor that calls mono.android.TypeManager.Activate().
The result is that happens is exactly what you told it to happen: Your Java type is instantiated, and because there is no "plumbing" to associate the Java instance with a (to be) created C# instance (the mono.android.TypeManager.Activate() call), no C# instance is created, which is the behavior you're seeing.
All of which sounds entirely sane to me, but I'm the guy who wrote it, so I'm biased.
Thus, what do you want to have happen? If you really want a hand-written Java ImageView, as you've done, then there's only one reasonable C# constructor to have invoked: the (IntPtr, JniHandleOwnership) constructor. All that's missing is the mapping between the Java type and the C# type, which you can do "somewhere" during app startup via TypeManager.RegisterType():
Android.Runtime.TypeManager("com/example/widget/ImageView",
typeof(Example.Widgets.ImageView));
If you have that mapping in place, then when the com.example.widget.ImageView instance is surfaced in managed code, it will be wrapped with an Example.Widgets.ImageView instance, using the (IntPtr, JniHandleOwnership) constructor.
If, instead, you want to have your C# (Context context, IAttributeSet attrs, int defStyle) constructor invoked, you should bypass your wrapper type and just stick to C# code:
namespace Example.Widgets {
public class ImageView : global::Android.Widget.ImageView {
...
In summary, RegisterAttribute.DoNotGenerateAcw is "special": it means that you're "aliasing" an existing Java type, and that the "normal" Android Callable Wrapper generation should be skipped. This allows things to work (you can't have two different types with the same fully qualified name), but adds a different set of complications.

Type parameters - get concrete type from type T : IMyInterface

Suppose I have a List<IMyInterface>...
I have three classes which implement IMyInterface: MyClass1, MyClass2, and MyClass3
I have a readonly Dictionary:
private static readonly Dictionary<Type, Type> DeclarationTypes = new Dictionary<Type, Type>
{
{ typeof(MyClass1), typeof(FunnyClass1) },
{ typeof(MyClass2), typeof(FunnyClass2) },
{ typeof(MyClass3), typeof(FunnyClass3) },
};
I have another interface, IFunnyInteface<T> where T : IMyInterface
I have a method:
public static IFunnyInterface<T> ConvertToFunnyClass<T>(this T node) where T : IMyInterface
{
if (DeclarationTypes.ContainsKey(node.GetType())) {
IFunnyInterface<T> otherClassInstance = (FunnyInterface<T>) Activator.CreateInstance(DeclarationTypes[node.GetType()], node);
return otherClassInstance;
}
return null;
}
I'm trying to call the constructor of FunnyClasses and insert as parameter my MyClass object. I don't want to know which object it is: I just want to instantiate some FunnyClass with MyClass as a parameter.
What happens when I call ConvertToFunnyClass, T is of type IMyInterface, and when I try to cast it to FunnyInterface<T>, it says I can't convert FunnyClass1, for instance, to FunnyInterface<IMyInterface>
My current workaround (not a beautiful one), is this:
public static dynamic ConvertToFunnyClass<T>(this T node) where T : IMyInterface
{
if (DeclarationTypes.ContainsKey(node.GetType())) {
var otherClassInstance = (FunnyInterface<T>) Activator.CreateInstance(DeclarationTypes[node.GetType()], node);
return otherClassInstance;
}
return null;
}
And I don't like it because the return type is dynamic, so when I access it from somewhere else, I have no idea what type it is, and I lose intellisense, and stuff. I don't know about any performance implications either.
Any clues?
Thanks in Advance!
Resolution
As I'm using C# 4.0, I could stop casting errors using covariance (output positions only), and so I changed my IFunnyInterface to
IFunnyInteface<out T> where T : IMyInterface
Thank you all for the replies.
Essentially, your problem is that you are trying to convert FunnyInterface<T> to FunnyInterface<IMyInterface>. As has been mentioned several times (one example is here, more information here), this is not valid in most circumstances. Only in .NET 4, when the generic type is an interface or delegate, and the type parameter has been explicitly declared as variant with in or out, can you perform this conversion.
Is FunnyInterface actually an interface?
thecoop answer points you exactly to why you can't do it.
A cleaner solution to the problem (besides using dynamic) would be a base non-Generics Interface:
public interface IFunnyInterfaceBase
{
}
public interface IFunnyInteface<T> : IFunnyInterfaceBase
where T : IMyInterface
{
}
And you need to move methods signature you use in that code from IFunnyInteface to IFunnyInterfaceBase.
This way you would be able to write something like this:
MyClass2 c2 = new MyClass2();
IFunnyInterfaceBase funnyInstance = c2.ConvertToFunnyClass();
The Exception you said you got in your code is not due to the extension method signature itself (the method is fine)..it is originated by the type of your lvalue (the type of the variable you use to store its return value)!
Obviously this solution applies only if you can modify IFunnyInterface source code!

Resources