How do you add a custom UIViewController to existing XIB? - xamarin.ios

I am just getting my feet wet with MonoTouch and have the most basic of questions. In their tutorials, they cover adding controls to the XIB directly through XCode's Interface Builder. However, I cannot figure out how to add a custom control to the XIB.
I have seen a number of examples of subclassing the base UICollectionView to customize it for your own purposes, and have done this in C# code in my project. My question is, how do I add that specific subclass of the UICollectionView to the XIB for use in the project?

For a normal UIView, the basic steps you need to go through are:
Create your custom view in C# as a class
public class MyView
{
}
Add the UIView base class to it, add a Register attribute and add two constructors:
[Register("MyView")]
public class MyView : UIView
{
public MyView() {}
public MyView(IntPtr handle) : base(handle) {}
}
To make it do something useful, then add a Draw implementation:
public override Draw(RectangleF rect)
{
var context = UIGraphics.CurrentGraphics();
UIColor.Red.SetFill();
context.FillEclipseInRect(rect);
}
Save and Build your project
Now in the XIB editor for the UIViewController in which you want to use your custom view, add a UIView to the design surface
Select that UIView and in the Identity Inspector, set the UIView's "Custom Class" to "MyView"
Save everything in xCode
Return to MonoDevelop, build and run
There's a video of this flow available at:
- http://www.youtube.com/watch?v=ggwO46dd-50&feature=youtube_gdata
For a custom UICollectionView, UILabel, UITableViewCell, or any other UIView base class, then you follow similar steps, just with a different base class and with different constructors too in order to support the specific View.
For a video about custom Table cells, see: http://slodge.blogspot.co.uk/2013/01/uitableviewcell-using-xib-editor.html

Related

Creating Xamarin ios storyboard interfaces using classes that are not directly or do not inheret directly from InterfaceController

When creating a WatchKit (WatchOS) Interface controller in the storyboard designer/editor, I cannot set it's class to something that is not itself type WKInterfaceController nor an immediate derived child of WKInterfaceController.
Basically in the hope of abstraction and better code reuse, better design overall, I would like to be able to use classes that are how to say, a more distant relative of their base WKInterfaceController
Basically right now it seems that your stuck using the storyboard designer to make a new WatchOS project. And using the storyboard designer you only have the option to select the WKInterfaceController class:
public partial class WKInterfaceController
or one that directly inherits from it:
public partial class ChildInterfaceController : WKInterfaceController
but nothing else such as:
public partial class GrandChildInterfaceController: ChildInterfaceController
So is there any way to do this that doesn't risk the chance of getting corrupted when you reenter the storyboard designer at some point?
Note: I've already asked if it is possible to avoid using a storyboard all together, but that has gone unanswered so I'm assuming no.
For clarity I'm talking about this dialog for "class":

Developing Xamarin.iOS application using MVVMCross and Storyboards

I am trying to understand how storyboards work in iOS development and how MVVMCross fits in. I thought the best solution would be to build an iOS version of the MVVMCRoss TipCalc Tutorial
I am using Storyboards as you cannot edit XIBs in Visual Studio. My current thinking is one Storyboard per screen.
I have it working but it feels like i did it with more luck than judgement. Therefore I want to check my understanding.
In TipCalc.UI.Touch I have
TipViewController.cs
TipViewController.storyboard
I have added a custom Mvx View Container as suggested in this SO answer. In the CreateViewOfType method of that container I am calling Storyboard.InstantiateViewController and casting that to an IMvxTouchView.
How can a controller be a View as well?
I am planning on having a "View" per storyboard.
If you have multiple views in a storyboard, would you have a controller per view?
When I bring up the Properties window for a "View" in the storyboard designer it has a Name and a class in the Identity section. What is the purpose of the Class property? Does that create a code-behind file?
I am creating the View-to-ViewModel bindings in the ViewDidLoad method of the Controller
public override void ViewDidLoad()
{
base.ViewDidLoad();
this.CreateBinding(this.tipValueText).To<TipViewModel>(vm => vm.Tip).Apply();
this.CreateBinding(this.subTotalTextBox).To<TipViewModel>(vm => vm.SubTotal).Apply();
this.CreateBinding(this.generositySlider).To<TipViewModel>(vm => vm.Generosity).Apply();
}
These bindings work but again I just wanted to check that it is how others do it too.
The iOS ViewController is actually the View in an MVVMCross application. You can think of the view controller as the code behind for the view (so just like a Windows Phone/Windows Store app will have a XAML and related .cs file, or an Android app will have an axml and a java view class)
Yes, when using multiple views in a single storyboard each one will actually be a viewcontroller (since that's what a screen in a storyboard is)
The class property defines which viewcontroller class the layout in the storyboard uses (so which code behind class to use, and if it doesn't exist it will be created)
I prefer a single storyboard as most of my apps don't have too many screens so these are the steps I follow when creating a View in an existing storyboard
Add a ViewController
Type in the view name in the Class field (this name would correspond to the ViewModel name, so HomeView for HomeViewModel, etc.). As soon as you hit enter the ViewController class should be created.
Type in the same view name as the Storyboard Id (this is used to fetch that view)
Add controls and set their names. Setting a control's name will updated the .designer file that was created for the ViewController
Create the ViewDidLoad override in the ViewController class and set up my bindings
If you use a storyboard per view, creating that storyboard with the correct name (HomeView for example) should create the ViewController and designer files for you and give you a storyboard with that one viewcontroller ready to go
edit:
in your bindings, you can use one set.Apply(); at the end

Customizing Xamarin.Forms layouts

I'm building an Android and iOS app using Xamarin Forms.
What I'm simply trying to do is set a background drawable on my Android app for my ListView items. The root view of my ListView items are StackLayout's:
var listView = new ListView
{
ItemsSource = items,
ItemTemplate = new DataTemplate(() =>
{
return new ViewCell
{
View = new StackLayout(...)
};
}
};
I know I can access the native element by using a custom renderer:
public class MyEntryRenderer : EntryRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
{
base.OnElementChanged(e);
if (e.OldElement == null) {
var nativeEditText = (EditText)Control;
...
}
}
}
But I'm not sure how this would work for a StackLayout (or any other layout for that matter).
I first extended StackLayout:
public class ListViewItem : StackLayout
{
}
And I read somewhere that layouts use the VisualElementRenderer, so I tried the following:
public class ListViewItemRenderer : VisualElementRenderer<StackLayout>
{
protected override void OnElementChanged(ElementChangedEventArgs<StackLayout> e)
{
base.OnElementChanged(e);
// any way to access the native element?
}
}
But VisualElementRenderer does not seem to give me access to the native element.
So is there any way I can access the native elements of Layout elements? Or maybe there is a different way to simply set a background drawable on layouts within my Android app?
Even though I still don't know how to access the native element of a layout, the VisualElementRenderer has a method for setting the background drawable on Android (which was exactly what I needed). So I ended up with the following:
protected override void OnElementChanged(ElementChangedEventArgs<StackLayout> e)
{
base.OnElementChanged(e);
SetBackgroundDrawable(Resources.GetDrawable(Resource.Drawable.listViewItem));
}
I understand you want to hook into an existing Layout renderer and extending it to access the native element with extra capabilities like background image.
Eventually the support for background-image will be supported just like background-colour is, I imagine, across the Layout controls. It may be worth while waiting for this as I can't see why they wouldn't implement these in a later release.
In the mean time you would need something that would work and is quite easy to implement?
Creating the background drawable via inheriting the renderer from a Layout may not be the simplest of solutions therefore, although does have its advantages as you can then re-use easily with the extra functionality across all Layouts for an application.
In your code for ListViewItemRenderer, however, it is inheriting from a Xamarin.Forms control (you specified StackLayout) and have not specified a native, platform dependent, control to be the base for the layout control that would have to match the Xamarin.Forms platform dependent control used.
Each Renderer is tied to a native element. Layout controls will be no different than other custom native control renderers.
For a custom control, you will write a renderer something like the following (note I haven't specified a layout renderer as I haven't had a need to do this yet and am just going from past experience - but similar rules should apply to implementing a renderer for a layout as opposed to a custom control):-
// System.Windows.Controls.Grid in this case is the root native control for a WindowsPhone renderer of MyControl
public class MyControlRenderer : ViewRenderer<MyControlView, System.Windows.Controls.Grid>
There is a simpler approach, however to achieve what you want to do:-
The simpler approach would be instead of inheriting from the Stack Layout control, it would be better to inherit from Grid as the root of the control.
Then you can add an Image control to the Grid and also a Stack Layout for the same Grid Row and Column.
By doing the above you will be able to achieve a background-image across the entire listview item row.

JavaFX access controller's variables from Scene Builder

If I declare something like
#FXML
private final static double PREF_SPACING = 10d;
or
#FXML
private Insets insets = new Insets(10d);
in the controller class,
is there a way to use their values in Scene Builder?
When I want to change the value, I want to change
it only once, in the controller class.
PRELIMINARY ANSWER
I haven't yet tried all of the techniques below, but it seems to be the way you would do it from reading the documentation. If I get some time, I'll try it out later and update this answer with results (or somebody else can do this and post a new answer or edit this one to create a definitive answer). I just wanted to publish something now to point you in what I believe to be the right direction.
If the below is not what you are looking for, add a few more specifics to your questions to fully describe what you want.
Don't using the #FXML annotation here. #FXML is for injecting values from the markup into the controller, not the other way around.
For your first example which is a constant, let's say your controller class is:
class MyControllerType {
public final static double PREF_SPACING = 10d;
}
Then in your fxml, reference the constant:
<?import MyControllerType?>
...
<VBox>
<spacing><MyControllerType fx:constant="PREF_SPACING"/></spacing>
</VBox>
For your second sample which is not a constant or a part of the SceneGraph, you can use an fx:define element to instantiate an instance of the class. Note that you can't directly instantiate an Insets class from FXML as it has no builder class nor zero length constructor. So what you might be able to do is create another placeholder class for the information and instantiate a reference to that in your FXML (or you can create a Builder that FXML can use to instantiate the Insets).
class InsetsHolder {
private Insets insets = new Insets(10d);
public Insets getInsets();
}
<?import InsetsHolder?>
<fx:define>
<InsetsHolder fx:id="i"/>
</fx:define>
<VBox>
<Button text="Click Me!" VBox.margin="$i.insets"/>
</VBox>
SceneBuilder should be able to read fxml files which use the fx:define and fx:constant notation, as well as (possibly) make use of the reference expression $i.insets. SceneBuilder might not have any UI to allow you to edit the values from within the SceneBuilder application, so you will probably need to hand edit the fxml file portions related to the fx:define and fx:constant elements if you wish to make use of these structures.
There is an executable example of using an fx:define element in this mailing list post on designing resolution independent units in FXML.
In general, I think I'd be a bit cautious of maintaining these kind of dependencies between fxml and java code. It may be more prudent to do more of this kind of stuff in plain Java code within the context of the controller initialize method as scottb suggests.
The #FXML annotation enables the JavaFX objects whose names you defined (fx:id) to have their references reflectively injected into nonpublic fields in the controller object as the scene graph is loaded from the fxml markup.
To the best of my knowledge, this is a one way operation. There is no provision for having named static class variables in the controller object injected into the scene graph during loading.
You can accomplish something very similar to what you are requesting by defining the values that you want set as class variables in your controller object's class, and then setting the appropriate object properties programmatically (rather than in markup) in the initialize() method of your controller object.
The initialize() method is called (if it is present) after the loading of the scene graph is complete (so all the GUI objects will have been instantiated) but before control has returned to your application's invoking code.

WPF UserControl inherited from custom UserControl class not working

i am creating a UserControl in WPF but it is not directly inherited from UserControl class. My base class is something as shown below
public class MyUserControlBase: UserControl, IMyInterface1, IMyInterface2
{..}
Now in my Usercontrol project, i have changed the usercontrol class signature
FROM
public partial class MyUserControl: UserControl //This is by default when the project was created.
TO
public partial class MyUserControl: MyUserControlBase
But it is giving error "Partial declarations of 'UI.MyUserControl' must not specify different base classes".
Please suggest what i have to change to make it run.
You also have to change where this control inherits from in the XAML part of your class. Still inheritance in WPF is a bit tricky, see this tutorial on how to get it right: http://svetoslavsavov.blogspot.com/2009/09/user-control-inheritance-in-wpf.html

Resources