Custom editor render for Xamarin on iOS

In Xamairin the Editor component doesn’t have a border on iOS. If you want to add one in the iOS project just added the following code.

using UIKit;
using WordBankEasy.iOS.Renderers;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;

[assembly: ExportRenderer(typeof(Editor), typeof(CustomEditorRenderer))]
namespace PSC.iOS.Renderers
{
    public class CustomEditorRenderer : EditorRenderer
    {
        protected override void OnElementChanged(
			    ElementChangedEventArgs<Editor> e)
        {
            base.OnElementChanged(e);

            if(Control != null)
            {
                Control.Layer.BorderColor = 
                              UIColor.FromRGB(204, 204, 204).CGColor;
                Control.Layer.BorderWidth = 0.5f;
                Control.Layer.CornerRadius = 3f;
            }
        }
    }
}

Happy coding!

Preserve data when deploying Xamarin.Android app

By default all your data from your previous runs is deleted when you’re deploying an Xamarin.Android app. In many cases you don’t want the data to be deleted.

Visual Studio


To preserve data go to Tools -> Options -> Xamarin -> Android Settings and check “Preserve application data/cache on device between deploys”.

Preserve_data_visualstudio

Xamarin Studio


To preserve data go to Tools -> Options -> Android and check “Preserve data/cache between application deploys”.

Preserve_data_xamarinstudio

Happy coding!

“System.IO.FileNotFoundException” using controls from another assembly in Xamarin Forms on iOS.

I was building a Xamarin solution with my components like that:

ProjectList

All my components (PSC.Xamarin.Controls.*) are working fine in other solutions.Always fine for Windows or UWP solutions. A problem was born when I started to deployed my solutions on iOS. When on the app I opened a page with my controls I always received an error like:

FileNotFoundException

System.IO.FileNotFoundException: Could not load file or assembly 'PSC.Xamarin.Controls.BindablePicker' or one of its dependencies. The system cannot find the file specified.

I can check my references and deployment settings in all ways, it turns out there’s probably a bug in Xamarin Forms’ iOS implementation. If you use controls and only controls from a PCL or dll that does not contain other code that is called from the app, apparently Xamarin on iOS ‘forgets’ to load/deploy the assembly (or something like that). But there is a work around.

The work around is as simple as it is weird. You go the iOS app’s AppDelegate class, and you add a reference to your class(es). If this is not enough, in the FinishedLaunching function you have to add a new instance to your control as in the following example:

using System;
using System.Collections.Generic;
using System.Linq;
using PSC.Xamarin.Controls.BindablePicker;

using Foundation;
using UIKit;

namespace myInventories.iOS {
    [Register("AppDelegate")]
    public partial class AppDelegate : 
        global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate {
        public override bool FinishedLaunching(UIApplication app, 
            NSDictionary options) {
            global::Xamarin.Forms.Forms.Init();

            // initialize my components
            // this is a work around only for iOS. 
            // If you don't do that, you received an error like 
            // System.IO.FileNotFoundException
            BindablePicker temporary = new BindablePicker();

            Xamarin.FormsMaps.Init();
            LoadApplication(new App());

            return base.FinishedLaunching(app, options);
        }
    }
}

Happy coding!

Xamarin Forms and Google Mobile Ads for iOS

If you have a new Xamarin Project and you want to add an advertising, the simple way it is to use Google Admob. This implementation is only for Android and iOS.

One of the first things people think about when developing for a new platform / using a new technology is monetization; and in my case the question is: how easy is it to integrate AdMob? For Xamarin Forms the answer would be: “It depends” – it depends on luck & on the complexity of what you want to achieve; but I will detail this as we move along.

The first thing you need to do is add the required components to your projects. For this walktrough I will be using Visual Studio but it should be relatively the same when using Xamarin Studio. Here, things go separate ways for each of the platforms:

  • for Android – add the Google Play Services component
  • for iOS – add the AdMob component
  • for Windows Phone – download the SDK from here and add it as a reference

By now, you Android project should no longer be building & you should be receiving a COMPILETODALVIK : UNEXPECTED TOP-LEVEL error. To fix that, go into your Droid project properties, select the Android Options tab and then under Advanced modify the value for the Java Max Heap Size to 1G. Your project should now build without any errors.

Next, inside your shared / PCL project add a new Content View and call it AdMobView. Remove the code generated inside it’s constructor & it should look like this:

public class AdMobView : ContentView
{
    public AdMobView() { }
}

Add this new view to your page. In XAML you can do it like this:

<controls:AdMobView WidthRequest="320" HeightRequest="50" />

Make sure NOTHING interferes with the control. By nothing I mean – overlapping controls, page padding, control margins / spacing, etc. If you have something overlapping the ad control, ads will not display & you won’t receive an error, so be careful.

Android

Add a new class called AdMobRenderer with the code below. Make sure to keep the ExportRenderer attribute above the namespace, otherwise the magic won’t happen.

using WordBankEasy.Droid.Renderers;
using WordBankEasy.Views.AdMob;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;

[assembly: ExportRenderer(typeof(AdMobView), typeof(AdMobRenderer))]

namespace WordBankEasy.Droid.Renderers {
    public class AdMobRenderer : ViewRenderer<AdMobView, Android.Gms.Ads.AdView> {
        protected override void OnElementChanged(ElementChangedEventArgs<AdMobView> e) {
            base.OnElementChanged(e);

            if (Control == null) {
                var ad = new Android.Gms.Ads.AdView(Forms.Context);
                ad.AdSize = Android.Gms.Ads.AdSize.Banner;
                ad.AdUnitId = "ca-app-pub-4381168884554284/2250461656";

                var requestbuilder = new Android.Gms.Ads.AdRequest.Builder();
                ad.LoadAd(requestbuilder.Build());

                SetNativeControl(ad);
            }
        }
    }
}

Next, you need to modify your AndroidManifest.xml file to add the AdActivity & required permissions for displaying ads: ACCESS_NETWORK_STATE, INTERNET; just like in the example below (see also http://puresourcecode.com/dotnet/post/Android-required-permissions).

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
    <uses-sdk android:minSdkVersion="15" />
    <application>
    <activity android:name="com.google.android.gms.ads.AdActivity" 
            android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|uiMode|screenSize|smallestScreenSize" android:theme="@android:style/Theme.Translucent" />
    </application>
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.INTERNET" />
</manifest>

That’s it. Your Android build should now display ads inside the AdMobView content view.

iOS

This, I haven’t got the chance to test yet as I don’t have a Mac around but people say it works, so I’ve added it for reference. Same as before, just add a new class called AdMobRenderer and copy-paste the code below but before you have to add a component.

In your iOS project click on “Components” (as in the picture)

Components

and click on “Get More Components…”. Then search admob and install it.

Google-Admob-Xamarin

using Xamarin.Forms;
using CoreGraphics;
using Xamarin.Forms.Platform.iOS;
using UIKit;
using WordBankEasy.Views.AdMob;
using WordBankEasy.iOS.Renderers;
using Google.MobileAds;

[assembly: ExportRenderer(typeof(AdMobView), typeof(AdMobRenderer))]
namespace WordBankEasy.iOS.Renderers {
    public class AdMobRenderer : ViewRenderer {
        const string AdmobID = "ca-app-pub-4381168884554284/5843056458";

        BannerView adView;
        bool viewOnScreen;

        protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.View> e) {
            base.OnElementChanged(e);

            if (e.NewElement == null)
                return;

            if (e.OldElement == null) {
                adView = new BannerView(size: AdSizeCons.Banner, origin: new CGPoint(-10, 0)) {
                    AdUnitID = AdmobID,
                    RootViewController = UIApplication.SharedApplication.Windows[0].RootViewController
                };

                adView.AdReceived += (sender, args) => {
                    if (!viewOnScreen) this.AddSubview(adView);
                    viewOnScreen = true;
                };

                adView.LoadRequest(Request.GetDefaultRequest());
                base.SetNativeControl(adView);
            }
        }
    }
}

Here you can receive an strange error like:

Foundation.MonoTouchException: Objective-C exception thrown. Name: NSInvalidArgumentException Reason: -[AppDelegate window]: unrecognized selector sent to instance 0x7ffee9cdd4d0

Native stack trace:

0 CoreFoundation 0x000000010a12ed85 __exceptionPreprocess + 165

1 libobjc.A.dylib 0x000000010a5e3deb objc_exception_throw + 48

2 CoreFoundation 0x000000010a137d3d -[NSObject(NSObject) doesNotRecognizeSelector:] + 205

3 CoreFoundation 0x000000010a07db17 forwarding + 487

4 CoreFoundation 0x000000010a07d8a8 _CF_forwarding_prep_0 + 120

5 WordBankEasyiOS 0x0000000100bc65e4 GADiTunesMetadataForFileAtPath + 4181

6 WordBankEasyiOS 0x0000000100c2d484 hasRequiredParams + 10260

7 WordBankEasyiOS 0x0000000100bc5f06 GADiTunesMetadataForFileAtPath + 2423

8 WordBankEasyiOS 0x0000000100bc1c35 GADCategories_NSURL_GADNSURLUtilities + 4438

9 WordBankEasyiOS 0x0000000100c00fde GADDispatchAsyncSafeMainQueue + 45

10 libobjc.A.dylib 0x000000010a5e4bff _class_initialize + 679

11 libobjc.A.dylib 0x000000010a5eacc5 lookUpImpOrForward + 176

12 libobjc.A.dylib 0x000000010a5f98bb objc_msgSend + 187

13 WordBankEasyiOS 0x0000000100bbe0ff GADCategories_DFPBannerView_CustomRenderedAd + 18074

14 WordBankEasyiOS 0x0000000100bbe382 GADCategories_DFPBannerView_CustomRenderedAd + 18717

15 WordBankEasyiOS 0x0000000100bbe527 GADCategories_DFPBannerView_CustomRenderedAd + 19138

16 ??? 0x000000011d368a0e 0x0 + 4785080846

17 ??? 0x000000011d36843b 0x0 + 4785079355

18 ??? 0x000000011d364d88 0x0 + 4785065352

19 ??? 0x000000011c51bbd6 0x0 + 4770085846

20 ??? 0x000000011c51b138 0x0 + 4770083128

21 ??? 0x000000011c51b138 0x0 + 4770083128

22 ??? 0x000000011c51b138 0x0 + 4770083128

Don't worry! I received the same error and I spend a lot of time to understand and fix it. There is a workaround that seems working fine.

In your iOS project, open AppDelegate.cs and add this code:

/// <summary>
/// Gets the window.
/// </summary>
/// <returns>UIWindow.</returns>
[Export("window")]
public UIWindow GetWindow() {
   return UIApplication.SharedApplication.Windows[0];
}

A complete example of this class is:

using System;
using System.Collections.Generic;
using System.Linq;

using Foundation;
using ImageCircle.Forms.Plugin.iOS;
using UIKit;

namespace WordBankEasy.iOS {
    // The UIApplicationDelegate for the application. This class is responsible for launching the 
    // User Interface of the application, as well as listening (and optionally responding) to 
    // application events from iOS.
    [Register("AppDelegate")]
    public partial class AppDelegate : global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate {
        //
        // This method is invoked when the application has loaded and is ready to run. In this 
        // method you should instantiate the window, load the UI into it and then make the window
        // visible.
        //
        // You have 17 seconds to return from this method, or iOS will terminate your application.
        //
        public override bool FinishedLaunching(UIApplication app, NSDictionary options) {
            global::Xamarin.Forms.Forms.Init();

            ImageCircleRenderer.Init();

            LoadApplication(new App());

            return base.FinishedLaunching(app, options);
        }

        /// <summary>
        /// Gets the window.
        /// </summary>
        /// <returns>UIWindow.</returns>
        [Export("window")]
        public UIWindow GetWindow() {
            return UIApplication.SharedApplication.Windows[0];
        }
    }
}

After that you can start you app and see you advertising without problem. For now :)

Happy coding!

What is the difference between Xamarin.Form’s layout options?

In Xamarin.Forms every View has the two properties HorizontalOptions and VerticalOptions. Both are of type LayoutOptions and can have one of the following values:

  • LayoutOptions.Start
  • LayoutOptions.Center
  • LayoutOptions.End
  • LayoutOptions.Fill
  • LayoutOptions.StartAndExpand
  • LayoutOptions.CenterAndExpand
  • LayoutOptions.EndAndExpand
  • LayoutOptions.FillAndExpand

Apparently it controls the view’s alignment on the parent view. But how exactly is the behavior of each individual option? And what is the difference between Fill and the suffix Expand?

Theory

The structure LayoutOptions controls two distinct behaviors:

  • Alignment:

    How is the view aligned within the parent view?

    • Start: For vertical alignment the view is moved to the top. For horizontal alignment this is usually the left-hand side. But note, that on devices with right-to-left language setting this is the other way around, i.e. right aligned.
    • Center: The view is centered.
    • End: Usually the view is bottom or right aligned. On right-to-left languages, of course, it is left aligned.

    • Fill: This alignment is slightly different. The view will stretch across the full size of the parent view. If the parent, however, is not larger then its children, you won’t notice any difference between those alignments. Alignment only matters for parent views with additional space available.

  • Expansion:

    Will the element occupy more space if available?

    • Suffix Expand:

      If the parent view is larger than the combined size of all its children, i.e. additional space is available, then the space is proportioned amongst child views with that suffix. Those children will “occupy” their space, but do not necessarily “fill” it. We’ll have a look on this behavior in the example below.

    • No suffix: The children without the Expand suffix won’t get additional space, even if more space is available. Again, if the parent view is not larger than its children, the expansion suffix does not make any difference as well.

Example

To demonstrate the effect of different LayoutOptions, we create a tiny example app. It consists of a gray StackLayout with some padding and some spacing between its child elements.

static readonly StackLayout stackLayout = new StackLayout {
    BackgroundColor = Color.Gray,
    Padding = 2,
    Spacing = 2,
};

The constructor of our App adds eight child elements before assigning the StackLayout to the MainPage. Note that we use a device-dependent padding for the MainPage to avoid elements being overlaid by the iOS status bar.

public App()
{
    AddElement("Start", LayoutOptions.Start);
    AddElement("Center", LayoutOptions.Center);
    AddElement("End", LayoutOptions.End);
    AddElement("Fill", LayoutOptions.Fill);
    AddElement("StartAndExpand", LayoutOptions.StartAndExpand);
    AddElement("CenterAndExpand", LayoutOptions.CenterAndExpand);
    AddElement("EndAndExpand", LayoutOptions.EndAndExpand);
    AddElement("FillAndExpand", LayoutOptions.FillAndExpand);

    MainPage = new ContentPage {
        Padding = new Thickness(0, Device.OnPlatform(20, 0, 0), 0, 0),
        Content = stackLayout,
    };
}

The method AddElement creates a new Label with different text and corresponding layoutOption. Its text is centered horizontally and vertically using the two properties HorizontalTextAlignment and VerticalTextAlignment.

Furthermore, it adds a flat yellow BoxView. This will serve as a visual separator between the space occupied by the white labels.

static void AddElement(string text, LayoutOptions layoutOption)
{
    stackLayout.Children.Add(new Label {
        Text = text,
        BackgroundColor = Color.White,
        HorizontalTextAlignment = TextAlignment.Center,
        VerticalTextAlignment = TextAlignment.Center,
        HorizontalOptions = layoutOption,
        VerticalOptions = layoutOption,
        WidthRequest = 160,
        HeightRequest = 25,
    });
    stackLayout.Children.Add(new BoxView {
        HeightRequest = 1,
        Color = Color.Yellow,
    });
}

The screenshot shows the resulting layout. We make the following observations:

  • The different alignment is only visible if there is space available. If the stackLayout would not fill the page, we might not be able to see a difference between elements with options Start or StartAndExpand.

  • Additional space is evenly proportioned amongst all labels with Expand suffix. To see this more clearly we added yellow horizontal lines – actually flat BoxViews – between every two neighboring labels. Labels with more space than their requested height do not necessarily “fill” it. In this case the actual behavior is controlled by their alignment. E.g. they are either aligned on top, center or label of their space or fill it completely.

  • If there is space available and no other expanding element – like in the horizontal direction – the alignment controls the element’s position even if it is not expanding, like the first four labels.

screenshot

Android required permissions

In Visual Studio 2015 if you checked same permissions on your project properties and when reopen it, your checks are disappeared, you have two ways:

  1. Is the manifest file marked as 'read only' in Windows Explorer? You have to select the Properties directory and un-tick 'read only' for the entire folder.
  2. Add manually in AndroidManifest.xml file same new rows:
    <?xml version="1.0" encoding="utf-8"?>
    
    <manifest xmlns:android="http://schemas.android.com/apk/res/android">
    
      <uses-sdk android:minSdkVersion="15" />
      <application android:label="$safename$">
        <meta-data android:name="com.google.android.maps.v2.API_KEY" 
                      android:value="yourcode" />
      </application>
    
      <uses-permission android:name="android.permission.INTERNET" />
      <uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES" />
    
      <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
      <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
      <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
      <uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" />
      <uses-permission android:name="android.permission.ACCESS_MOCK_LOCATION" />
      <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
      <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    
    </manifest>
    
    
Happy coding!

Custom ContextAction with Xamarin Forms

I using a Xamarin Forms ListView and I want to enable or disable the Context Actions based on a certain binding or in the code behind.

The way I found is to use BindingContextChanged in a ViewCell. I show you an example

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml">
  <ContentPage.Content>
    <StackLayout>
      <ListView x:Name="listDictionaries" 
                ItemsSource="{Binding DictionariesList}" 
                IsVisible="{Binding ShowList}"
                HorizontalOptions="FillAndExpand" 
                VerticalOptions="FillAndExpand" 
                HasUnevenRows="true" 
                IsPullToRefreshEnabled="true" 
                RefreshCommand="{Binding Refresh}" 
                SeparatorVisibility="Default" 
                ItemTapped="OnItemTapped" 
                IsRefreshing="{Binding IsBusy, Mode=OneWay}">
        <ListView.ItemTemplate>
          <DataTemplate>
            <ViewCell BindingContextChanged="OnBindingContextChanged">
              <ViewCell.View>
                <StackLayout>
                  <Grid Padding="10" ColumnSpacing="10">
                    <Grid.RowDefinitions>
                      <RowDefinition Height="*" />
                    </Grid.RowDefinitions>
                    <Grid.ColumnDefinitions>
                      <ColumnDefinition Width="Auto" />
                      <ColumnDefinition Width="*" />
                    </Grid.ColumnDefinitions>
                    <Label Text="{Binding Name}" FontSize="Large" 
                           Grid.Row="0" Grid.Column="0" />
                    <Label Text="{Binding Description}" FontSize="Small" 
                           Grid.Row="1" Grid.Column="0" />
                  </Grid>
                </StackLayout>
              </ViewCell.View>
            </ViewCell>
          </DataTemplate>
        </ListView.ItemTemplate>
      </ListView>
    </StackLayout>
  </ContentPage.Content>
</ContentPage>

Then you insert in the code the following code:

/// <summary>
/// Called when binding context changed.
/// </summary>
/// <param name="sender">The sender.</param>
/// <param name="e">The <see cref="EventArgs"/> 
/// instance containing the event data.</param>
private void OnBindingContextChanged(object sender, EventArgs e) {
    base.OnBindingContextChanged();

    if (BindingContext == null)
        return;

    ViewCell theViewCell = ((ViewCell)sender);
    var item = theViewCell.BindingContext as DictionaryModel;
    theViewCell.ContextActions.Clear();

    if (item != null) {
        MenuItem mn = new MenuItem();
        mn.Clicked += Menu_Clicked;
        mn.Text = "Delete";
        mn.IsDestructive = true;
        mn.CommandParameter = item.Id;
        theViewCell.ContextActions.Add(mn);
    }
}

private async void Menu_Clicked(object sender, EventArgs e) {
    var mi = ((MenuItem)sender);
}

Happy coding!

Android.Content.Res.Resources+NotFoundException: Resource ID #0x0

I've just created a simple MasterDetailPage and in the code I inserted an icon for the left page with:

public MainPage() {
    InitializeComponent();

    BackgroundColor = Color.FromHex("#007acc");
    Icon = "settings.png";
}

I tried to deploy my app on an Android emulator but I can't deploy it because Android.Content.Res.Resources+NotFoundException: Resource ID #0x0.

I checked everthing and evething seemed fine. The problem is the icon!

You have to remove Icon from the code and in the XAML page type the following code:

  <ContentPage.Icon>
    <OnPlatform x:TypeArguments="FileImageSource">
      <OnPlatform.iOS>settings.png</OnPlatform.iOS>
    </OnPlatform>
  </ContentPage.Icon>

Happy coding!

How to deploy an Universal Windows Project on real device mobile?

I'm trying to debbuging my app on real device (lumia 830 with windows 10 mobile 10.0.10581.0) Developer Mode is ON on both devices (mobile and PC), but when I'm deploying my app on my device I've got an error (DEP6100 and DEP6200). Howevere i can easily emulate on emulators and my PC, couldn’t understand whats the problem.

I googled a bit and I discovered how to resolve the problem.

Visual-Studio-2105-Deploy-Real-Device

  • Create a Registry Key in: [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SirepClient] (Probably you will need to create it)
  • Create a dword with name "DisableProtocol3" and value 00000001
  • Restart Visual Studio and try deploying the solution back again.

It's a provisional solution meanwhile a patch is included in Windows 10 mobile. We will have to consider deleting this key after that.

If you want to inspect your device, connect your device via USB and open a browser and type

https://127.0.0.1:10443

And you can watch your device in action!

Windows 10 Device – Home

Windows-10-Device-Home

Windows 10 Device – App Manager

Windows-10-Device-AppManager

Windows 10 Device – File Explorer

Windows-10-Device-FileExplorer

Windows 10 Device – Processes

Windows-10-Device-Processes

Windows 10 Device – Performances (in real time!)

Windows-10-Device-Performances

Visual Studio updates Xamarin

When you open Visual Studio 2015 and there is a pop windows to invite you to click on it for updating Xamarin and you click, nothing happends. There is a bug but clicking the update available popup was fixed in one of the recent releases. You can manually update in the Options menu under Tools.

As for the errors, I get those all the time. Support packages can often be a problem. Update to the latest XF package. Try deleting bin, obj, and the contents of packages folders and rebuild.

Visual-Studio-Update-Xamarin

Advertsing

125X125_06


Subscribe to our mailing list

* indicates required


TagCloud

MonthList

CommentList