Xamarin Monodroid: WP7 => Android and Custom Control? - c#

i am in the process of porting some of my Windows Phone Applications to Android using Xamarin Monodroid.
I am pretty new with the Xamarin stuff, just bought a license actually.
So far so good as far as recreating the XAML UI in AXML but i am facing a problem with Custom Controls.
Here is what i mean by custom controls:
In .NET, i created a bunch of controls by creating class that inherit from the 'UserControl' class, i created the logic and set the Content. Then i just create new instance with 'new my_control()', etc...
Some of my controls are not created this way but instead i created the UserControl by defining the XAML, where there is no specific logics but when i need to combine 2 or more controls(for example, a colored square with text beside it, so Rectangle + TextBlock) and again i just need to do 'new my_control()' and add it somewhere in the XAML UI(Grid, ListBox, StackPanel, etc...).
How can i achieve something similar with Monodroid?
Thanks in advance!

You can make your own custom view by inheriting the View class. This allows you to do anything. Then you can reference it in your AXML with:
<your.awesome.namespace.AwesomeViewName
android:id="#+id/awesomeView"
android:layout...
/>
Just make sure your namespace name in the AXML is all lower case, otherwise it won't pick it up.
But if you just need a very simple AXML layout that you are going to use a lot, you can create a new AXML file and use the include tag to put it in there.
There is some more general info on some Layout Tricks for Android which will work for Mono for Android as well here: https://developer.android.com/resources/articles/layout-tricks-merge.html

You can do "custom controls" in Mono for Android too - and once you've written them, then you can include them in your axml files.
I'm afraid I don't have any perfectly simple examples to hand, but there's a complicated example in:
https://github.com/slodge/MvvmCross/blob/master/Sample%20-%20CirriousConference/Cirrious.Conference.UI.Droid/Resources/Layout/ChildPage_Twitter.axml
If you declare a class MyControl in MyNamespace and inherit that control from an Android View and you can then setup your custom control - including pulling in attributes from the XML - using a constructor like:
public MyControl(Context context, IAttributeSet attrs) { /* ... */ }
and using XML like:
<mynamespace.MyControl android:layout_height='wrap_content' />
One example of this could be the control from https://github.com/Cheesebaron/MonoDroid.HorizontalPager - which could be used from xml using xml like
<mynamespace.controls.HorizontalPager
android:id="#+id/MyPageHost"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
/>

Any reason why it won't enter the constructor? Here is my constructor:
protected CropImageView(IntPtr javaReference, JniHandleOwnership transfer)
: base(javaReference, transfer)
{
}
The Init method causes the circular dependency when I inflate the crop_image_view xml
I have tried with public, private but no luck... here is my code: https://github.com/slown1/Xamarin.CircleImageCropper

Related

Efficiently creating UI elements from XML file (OpenGL / C# NET 6.0)

I'm currently working on a small game framework, build on top of OpenTK. In this project there should also be a way to easily create UI elements by defining their layout in an XML file, like WPF and XAML but way less complex (no bindings planned etc).
Now I'm kind of stuck when it comes to efficiently creating these ui elements from the XML file. The concept is that there are few core elements like image, label and panes for layouting and the structure of all more complex elements are defined in XML and represented by a seperated class (that inherits from UIElement, the base class for all UIElements).
For example, this is how it could look like for a button:
Button.xml
<Button Layout="AlignLayout Stretch Stretch">
<Image Name="image"></Image>
<Image Name="hoverImage"></Image>
<Image Name="pressedImage"></Image>
<AlignPane HorizontalLayout="Center" VerticalLayout="Center">
<Label Name="label"
IgnoreInputEvents="true">
</Label>
</AlignPane>
</Button>
Button.cs
public class Button : UIElement
{
protected Image image;
protected Image hoverImage;
protected Image pressedImage;
protected Label label;
public Button(UIElement? parent, Texture2D backgroundTexture,
Texture2D hoverTexture, Texture2D pressedTexture,
string text) : base(parent)
{
// Receive XML layout here probably? (from cache, not parsed)
image.Texture = backgroundTexture;
hoverImage.Texture = hoverTexture;
pressedImage.Texture = pressedTexture;
label.Text = text;
// ...
}
}
and the usage in code would simply be:
Button startButton = new Button(OverlayUICanvas, bgTex, hovTex, prsTex, "Start");
or use the element in some other XML file.
The element attributes in xml set properties in the corresponding class (except "Name", which is expected to set the fields/properties in the root element to the instance of the created class)
Basically i got something like this working already except that it is super inefficient (probably because all the reflection going on including parametered constructor calls). While testing it took over 100ms to load something simple with just 8 total elements.
It wouldn't be too bad if i could somehow cache the loaded layout somehow and then just create a new instance, without all the reflection going on again (layout would be loaded at game start or something) but i really have no clue how i could archive this.
Creating new instance of these elements is pretty important: imagine the game needs to creates some elements at runtime from a list or something like that.
I didn't really found any good information on how to do this, not even sure if it is possible like that. If I undestood correctly, WPF solves this by generating some source code on compilation but it stated this only works for netstandard2.0 and I'm having a hard time wrapping my head around if this would even help me solve this problem.
If you want to take a look at the current source yourself for some reason:
https://github.com/BlakkM9/VengineX/tree/master/VengineX/UI
but please keep in mind - this project is WIP, in a very very early state and nothing professional, really.
I'm graceful for any tips and hints that might lead me in the right direction!

MvvmCross can't add second xaml view for other device family

In a UWP project you can add a new xaml view with the same name without the class background to create a specific view for a platform, for example mobile.
So I have my general view with code behind class:
PaymentListView.xaml and PaymentListView.xaml.cs.
And I wanted to create a new view for Mobile. So I created a XAML view with the name:
PaymentListView.DeviceFamily-Mobile.xaml
Both have the type views:MvxWindowsPage.
Now when I run the application, I get an exception on setup.Initialize:
Problem seen creating View-ViewModel lookup table - you have more than one View registered for the ViewModels: 2*PaymentListViewModel (PaymentListView,PaymentListView)'
Is there a way to solve this or do I have to make a giant Visual Trigger an press both UI's in one XAML?
During creating an example I found the issue.
I have all my views in a folder views. When I created a new XAML view in that folder the class path was something like this:
x:Class="MoneyFox.Windows.PaymentListView"
Therefore it wasn't correctly mapped to the PaymentListView.xaml.cs who has the namespace MoneyFox.Windows.Views.PaymentListView.
As soon as I adjusted that, it worked.

Windows Universal App UI Library Parser internal error

I built a user control in an user control library and I want to include it into my windows universal app. I remember in the old days you had to add something to app.xaml (something like pack:// this is my xaml).
So my thoughts (or hope) I just include my library and user the control. When I do I get - Parser internal error: Object writer 'xClassNotDerivedFromElement'.
I tried adding it as a msappx reference in the App.Xaml, but I may have the syntax wrong. If I can get this working by literally copying over the code itself into my project (which I do not want to do). Suggestions?
Thanks
EDIT: Added source code
public MainPage()
{
_webControl = new NativeWebView.WebUserControl();
_webControl.Loaded += _webControl_Loaded;
_contentView = new NativeWebView.ContentView(_webControl);
this.InitializeComponent();
root.Children.Add(_webControl);
}
public sealed partial class WebUserControl : UserControl, IWebView
{
public WebUserControl()
{
this.InitializeComponent();
}
}
So, I found out the answer. So to include a library into another project, you have to have some extra crazy files (.xr.xml and .xrc). I manually copied them into a folder, but it seems they can get out of date. I found that if I want to include the library from the build directory, I have to check a box in the build properties page (Generate library layout). This copies the files for me. SOLUTION!
Just add namespace of the library into root tag of the page where you use the control, ex. for ImageButton control in WinRT XAML Toolkit:
<Page
[...]
xmlns:toolkit="using:WinRTXamlToolkit.Controls">
[...]
<toolkit:ImageButton [...] />
[...]
If you still get xClassNotDerivedFromElement, it means there's a problem in the library. (need source to track it)

Changing Views in Fragments

In My app, i use an altered Example of the ViewPagerIndicator, which launches 5 Fragments. so far all works well, but the fragments do have to change their View (completly new layout) for other purposes. how do i do that? a Fragment doesn't have a function SetContentView like activities do. so is there a way to update the view or something like that?
Use Fragment.getView() to get the root view of the Fragment. On that View, call removeAllViews(). Then build your new views and add them to the view you got from getView().
Edit
I never used Mono for Android before, but looking at the documentation; I suggest you put the inflated View from inflater.Inflate in a private member of your Fragment. Later on, when needed, you can use that reference to edit your layout.

ASP.NET user control designer support

I have a user control which when added to the markup via the Toolbox or manually typing
<myNameSpc:myCtrl ... I would like to spit out:
<myNameSpc:myCtrl>
<template></template>
</myNameSpc:myCtrl>
I remember doing this for windows workflows and it involved implementing something like a TypeConverter and WorkflowXmlSerializer so it maybe possible for user controls as well I'd guess ? the only thing is that I don't have time to research this matter now, so I was wondering if anyone would be kind enough to point me in the right direction so that I don't have to dig deep into the designer serialization of VS (which I remember was a big pain).
For your custom control, you can specify a ToolboxDataAttribute which defines the default html that will be generated when you drag a control onto the design service. E.g.:
[ToolboxData("<{0}:myCtrl runat="server"><template></template></{0}:myCtrl>")]
public class myCtrl : System.Web.UI.Control
{
}
For the manual generation you can create a Code Snippet. The best way to do that is find existing ASPX snippet and modify it to gen your control. I'm assuming you are using VS 2010.

Categories

Resources