How do you programatically instantiate a subclassed ViewController in MonoTouch? - xamarin.ios

I have subclassed a ViewController that was created via XCode Interface Builder. my subclass is defined like so
public MyViewControllerGeneric<T> : MyViewController{
public MyViewControllerGeneric(IntPtr handle) : base(handle){}
}
I can use Storyboard.InstantiateViewController("MyViewController") to get an instance of MyViewController. However how do I create an instance of MyViewControllerGeneric and pass a handle to it?
Tried
var vc = new MyViewControllerGeneric<MyType>(this.Handle)
var vc = new MyViewControllerGeneric<MyType>(new IntPtr(DateTime.Now.Ticks)
both throw a SigAbort
Any Help highly appreciated.

The IntPtr handle is not something you should be passing in.
Use this constructor instead:
public MyViewControllerGeneric<T> : MyViewController{
public MyViewControllerGeneric() : base(){ }
}
Or this if you need a NIB loaded, depending on your base class:
public MyViewControllerGeneric<T> : MyViewController{
public MyViewControllerGeneric() : base("MyViewControllerGeneric", null){ }
}

Related

is the object instanciated

here is a sample source code of vala for creating a simple GTK application from elementary os website
public class Examples.Application : Gtk.Application {
public Application () {
Object (
application_id: "org.valadoc.examples",
flags: ApplicationFlags.FLAGS_NONE
);
}
protected override void activate () {
var application_window = new Gtk.ApplicationWindow (this);
application_window.show_all ();
}
public static int main (string[] args) {
var app = new Application ();
return app.run (args);
}
}
i dont understand th object in this code? what is it? is it an object ? if its an object so why it has not new keword and not instanciated?
The Object() you see there in the constructor is a Vala-specific syntax called: GObject-style construction. It allows you to set your properties all at once.
This allows you to work with GObject's so-called "construct properties": properties which can be set during construction (sometimes they can even only exclusively be set during construction).

Not able to use Custom XIB outlets with UICollectionViewCell

When accessing to outlets from my CustomClass : UICollectionViewCell, they are appearing as not initialized and can not set a proper value.
Every example I've seen it uses a plain Class (no XIB) to set the UI.
[Register("CustomCommentCell")]
public partial class CustomCommentCell : UICollectionViewCell
{
public static readonly NSString Identifier = new NSString("CustomCommentCell");
public CustomCommentCell () : base()
{
}
public CustomCommentCell (IntPtr handle) : base (handle)
{
}
public void updateData()
{
this.lblComment.Text = "Test";
}
}
On the other hand, I have registered the Class:
this.tableComments.RegisterClassForCell (typeof(CustomCommentCell),commentCellId);
and have the GetCell properly set.
However, when trying to set the outlets to a specific value, it indicates it is null. (this.lblcomment = null) while it should have been a UILabel initialized.
Any clues?
to create the Custom CollectionViewCell using XIB. do the following
1) create C# class which inherits from UIcollectionViewCell
[Register("MyCustomCell")]
public class MyCustomCell : UICollectionViewCell
{
public static readonly NSString Key = new NSString ("MyCustomCell");
[Export ("initWithFrame:")]
public MyCustomCell(CoreGraphics.CGRect frame) : base (frame)
{
}
public override UIView ContentView {
get {
var arr= NSBundle.MainBundle.LoadNib ("MyCustomCell", this, null);
UIView view =arr.GetItem<UIView> (0);
view.Frame = base.ContentView.Frame;
base.ContentView.AddSubview (view);
return base.ContentView;
}
}
}
2) Add a IphoneView XIB file has the Same Name as that of Class created in step 1
3) Open XIB in XCODE and do the Following Changes
3.1)Select the FileOwner set the Class same name as Step 1
3.2)Select The View Set the Class name UIView
4) Design Your XIB Accordingly
I can't follow quite the problem you are seeing. What is a "Custom XIB outlet"? Why is this question tagged "custom-controls"? Is there some example code or pictures you can show to help explain the problem?
The approach I use for UICollectionViewCell's is the same as I use for UITableViewCell - see the tutorial - http://slodge.blogspot.co.uk/2013/01/uitableviewcell-using-xib-editor.html
Update: From the code you've posted as a comment (not sure if it's complete or not), I think it would be useful for you to follow through that tutorial. There are a few steps to complete including registering the custom class name and including using RegisterNibForCellReuse - one of those will probably fix this for you.

How to convert NSDictionary() with values [PSPDFAnnotationParser class] / [MyCustomAnnotationParser class] into MonoTouch?

From the documentation of a bound API I'm using:
overrideClassNames
Use this to use specific subclasses instead of the default PSPDF*
classes. e.g. add an entry of [PSPDFAnnotationParser class] /
[MyCustomAnnotationParser class] as key/value pair to use the custom
subclass. (MyCustomAnnotationParser must be a subclass of
PSPDFAnnotationParser) Throws an exception if the overriding class is
not a subclass of the overridden class. Note: does not get serialized
when saved to disk.
#property (nonatomic, strong) NSDictionary *overrideClassNames
Here's what I tried but doesn't work. Appearently not strings are required but actual types or something. How can I use this in MonoTouch?
var oClassDic = new NSMutableDictionary();
oClassDic.Add(new NSString("[PSPDFAnnotationParser class]"), new NSString("[PSPDFKitAnnotationParser class]"));
oDoc.OverrideClassNames = oClassDic;
The PSPDFKitAnnotationParser I created like this:
[Register("PSPDFKitAnnotationParser")]
public class PSPDFKitAnnotationParser : PSPDFAnnotationParser
{
public PSPDFKitAnnotationParser () : base()
{
}
public PSPDFKitAnnotationParser (PSPDFDocumentProvider provider) : base(provider)
{
}
public PSPDFKitAnnotationParser (IntPtr handle) : base(handle)
{
}
public PSPDFKitAnnotationParser (NSObjectFlag t) : base(t)
{
}
public PSPDFKitAnnotationParser (NSCoder coder) : base(coder)
{
}
MonoTouch's own bindings generally hides the class and replace them with, the more .NETy, System.Type.
However the MonoTouch.ObjCRuntime.Class type exists and can also be used. If the native code expects class instances then you should be able to do something like:
var oClassDic = new NSMutableDictionary();
oClassDic.Add(new Class("PSPDFAnnotationParser"), new Class("PSPDFKitAnnotationParser"));
oDoc.OverrideClassNames = oClassDic;
You might have to tweak this a bit since a Class instance is not an NSObject, it's a NativeObject in MonoTouch, so you might have to go one level deeper and use the Handle properties (IntPtr) when adding values/keys to your dictionary.
Following #poupou answer this might work, I have not tested it this is what you have to do, It Works (TM)
var oClassDic = new NSMutableDictionary();
var key = new Class("PSPDFAnnotationParser");
var val = new Class("PSPDFKitAnnotationParser");
IntPtr selSetObjectForKey = Selector.GetHandle ("setObject:forKey:");
Messaging.void_objc_msgSend_IntPtr_IntPtr (oClassDic.Handle, selSetObjectForKey, val.Handle, key.Handle);
oDoc.OverrideClassNames = oClassDic;
Selector setObject: forKey: expects an ObjC id type on both params
"id" its just a special type that can hold a pointer to any object you can construct with ObjC
So this should work :)
Hope this helps
Alex

Using LogManager.GetLogger with Unity

Given this class:
class Foo
{
readonly ILog log;
public Foo(ILog log)
{
this.log = log;
}
...
}
I'd like to configure Unity to inject ILog. That's easy:
container.RegisterInstance<ILog>(LogManager.GetLogger(typeof(XYZ)));
But I'd like to make Unity call LogManager.GetLogger with the type of the parent type being resolved.
This is close:
container.RegisterType<ILog>(new InjectionFactory((c, t, s) => LogManager.GetLogger(t)));
But t in this case is the type being resolved (ILog), not the type that the object is being resolved for (Foo).
I know I can do this:
container.RegisterType<Foo>(new InjectionFactory(c => new Foo(LogManager.GetLogger(typeof(Foo)));
But I don't want to have to add that crazy declaration every time I register an object.
I know this can be done in Autofac, and I know the Real Answer is not to use Unity in the first place, but can this be done? :)
Unity might not give you all the goodies some of the other containers offer but I have yet to find a feature you can't easily add.
var container = new UnityContainer();
container.AddNewExtension<TrackingExtension>();
container.RegisterType<ILog>(
new InjectionFactory((ctr, type, name) =>
{
var tracker = ctr.Resolve<ITracker>();
var parentType = tracker.CurrentBuildNode.Parent.BuildKey.Type;
return LogManager.GetLogger(parentType);
}));
var sut = container.Resolve<UsesLog>();
Assert.AreEqual(typeof(UsesLog), sut.Log.Type);
You can find the source code for the TrackingExtension here. Its located in the TecX.Unity project folder.
If you want a DI container to return you a logger based on the class’ type information, then put the type information into the public interface so the DI container can see it. It removes the need for any container specific override features and then it won’t matter if you are using Unity or AutoFac.
Someone that knows the log4net object model well might be able to give you a more efficient implementation, but try something like this:
using System;
using Microsoft.Practices.Unity;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace UnityLoging
{
public interface ILog<T> : log4net.ILog
{ }
public class MyLogger<T> : log4net.Core.LogImpl, ILog<T>
{
public MyLogger() : base(log4net.LogManager.GetLogger(typeof(T).Name).Logger)
{ }
}
public class ClassToLog
{
private readonly log4net.ILog log;
public ClassToLog(ILog<ClassToLog> log)
{
this.log = log;
}
public void LogMe()
{
log.Debug("Got here");
}
}
[TestClass]
public class TestClass
{
[TestMethod]
public void GenericLogRegistrationTest()
{
log4net.Config.XmlConfigurator.Configure();
IUnityContainer container = new UnityContainer();
container.RegisterType(typeof(ILog<>), typeof(MyLogger<>));
ClassToLog c = container.Resolve<ClassToLog>();
c.LogMe();
log4net.LogManager.Shutdown();
}
}
}
This seems like a very clean approach: https://github.com/roblevine/UnityLoggingExtensions

Need help with UITabBarController and orientation

I have an app (written using MonoTouch and currently working) that I want to add landscape orientation to. I am using a UITabBarController.
I don't see how to create a controller that will allow me to override the "ShouldAutorotate..." method. Can anybody point me to an example using a UITabBarController in MonoTouch?
TweetStation contains a sample precisely for this setup, and propagates the rotation down all of the nested view controllers.
Are you subclassing UITabBarController?
You are probably non subclassing and just adding a vanilla controller in Interface Builder. You have to subclass to override that property.
First make a new class like this:
//Test this, it's off the top of my head
[Register("YourTabController")]
public class YourTabController : UITabBarController
{
public YourTabController (IntPtr handle) : base (handle) { }
[Export("initWithCoder:")]
public YourTabController (NSCoder coder) : base (coder) { }
//Override should rotate
public bool ShouldAutoRotateToInterfaceOrientation(UIInterfaceOrientation o)
{ return true; }
}
Then, if you already have a UITabBarController in IB, there is a 'Class' property that you set to the name of your new class.

Resources