ExtWebView

My custom WebView. It has a HTML string property. This was very useful to draw my chart :) a simple HTML file with some embedded Javascript to draw the shapes. It was the faster way for me to make a cross pie chart control. When the HTML property has changed, the source of the WebView gets updated.

//
// <copyright file=ExtWebView.cs company=Krossapp>
//     Copyright (c) Krossapp. All rights reserved.
// </copyright>
// <author>Nicolas Krier</author>
//
namespace SDF.XForm.Controls
{
    #region Using

    using System.Diagnostics.CodeAnalysis;
    using System.Windows.Input;
    using Xamarin.Forms;

    #endregion

    /// <summary>
    /// Web view.
    /// </summary>
    public class ExtWebView : WebView
    {
        #region Bindable property

        /// <summary>
        /// The html property.
        /// </summary>
        [SuppressMessage(StyleCop.CSharp.MaintainabilityRules, SA1401:FieldsMustBePrivate, Justification = Reviewed.)]
        public static BindableProperty HtmlProperty = BindableProperty.Create<ExtWebView, string>(x => x.Html, null, BindingMode.OneWay, propertyChanged: WhenHtmlChanged);

        /// <summary>
        /// The command clicked property.
        /// </summary>
        [SuppressMessage(StyleCop.CSharp.MaintainabilityRules, SA1401:FieldsMustBePrivate, Justification = Reviewed.)]
        public static BindableProperty Command = BindableProperty.Create<ExtWebView, ICommand>(x => x.CommandClicked, null);

        #endregion

        #region Constructor

        /// <summary>
        /// Initializes a new instance of the <see cref=ExtWebView/> class.
        /// </summary>
        public ExtWebView()
            : base()
        {
            this.HandleTapEvent();
        }

        #endregion

        #region Property

        /// <summary>
        /// Gets or sets the html.
        /// </summary>
        /// <value>The html.</value>
        public string Html
        {
            get { return (string)this.GetValue(HtmlProperty); }
            set { this.SetValue(HtmlProperty, value); }
        }

        /// <summary>
        /// Gets or sets the command clicked.
        /// </summary>
        /// <value>The command clicked.</value>
        public ICommand CommandClicked
        {
            get { return (ICommand)this.GetValue(Command); }
            set { this.SetValue(Command, value); }
        }

        #endregion

        /// <summary>
        /// Raises the html changed event.
        /// </summary>
        /// <param name=sender>The sender.</param>
        /// <param name=oldValue>Old value.</param>
        /// <param name=newValue>New value.</param>
        private static void WhenHtmlChanged(BindableObject sender, string oldValue, string newValue)
        {
            WebView ctrl = (WebView)sender;
            ctrl.Source = new HtmlWebViewSource() { Html = newValue };
        }

        /// <summary>
        /// Handle the tap event : the click.
        /// </summary>
        private void HandleTapEvent()
        {
            /*
            var tapGestureRecognizer = new TapGestureRecognizer();
            tapGestureRecognizer.Tapped += (sender, args) =>
            {
                if (args != null && this.CommandClicked != null && this.CommandClicked.CanExecute(args))
                {
                    this.CommandClicked.Execute(args);
                }
            };
            this.GestureRecognizers.Add(tapGestureRecognizer);
            */
        }
    }
}


ExtSwitch

My custom switch control. This control is kind of useless right now. I don’t use to bind a command on a switch. Even more if the switch is used in a ListView because I may handle the tap event on a bigger area than just the switch itself.

//
// <copyright file=ExtSwitch.cs company=Krossapp>
//     Copyright (c) Krossapp. All rights reserved.
// </copyright>
// <author>Nicolas Krier</author>
//
namespace SDF.XForm.Controls
{
    #region Using

    using System.Diagnostics.CodeAnalysis;
    using System.Windows.Input;
    using Xamarin.Forms;

    #endregion

    /// <summary>
    /// The Switch.
    /// </summary>
    public class ExtSwitch : Switch
    {
        #region Bindable property

        /// <summary>
        /// The command toggled property.
        /// </summary>
        [SuppressMessage(StyleCop.CSharp.MaintainabilityRules, SA1401:FieldsMustBePrivate, Justification = Reviewed.)]
        public static BindableProperty CommandToggledProperty = BindableProperty.Create<ExtSwitch, ICommand>(x => x.CommandToggled, null);

        /// <summary>
        /// The command parameter toggled property.
        /// </summary>
        [SuppressMessage(StyleCop.CSharp.MaintainabilityRules, SA1401:FieldsMustBePrivate, Justification = Reviewed.)]
        public static BindableProperty CommandToggledParameterProperty = BindableProperty.Create<ExtSwitch, object>(x => x.CommandToggledParameter, null);

        #endregion

        #region Constructor

        /// <summary>
        /// Initializes a new instance of the <see cref=ExtSwitch/> class.
        /// </summary>
        public ExtSwitch()
            : base()
        {
            // SubscribeClickToRaiseCommand();
            this.Toggled += this.OnItemSelected;
        }

        #endregion

        #region Property

        /// <summary>
        /// Gets or sets the command toggled.
        /// </summary>
        /// <value>The command toggled.</value>
        public ICommand CommandToggled
        {
            get { return (ICommand)this.GetValue(CommandToggledProperty); }
            set { this.SetValue(CommandToggledProperty, value); }
        }

        /// <summary>
        /// Gets or sets the command parameter toggled.
        /// </summary>
        /// <value>The command parameter toggled.</value>
        public object CommandToggledParameter
        {
            get { return (object)this.GetValue(CommandToggledParameterProperty); }
            set { this.SetValue(CommandToggledParameterProperty, value); }
        }

        #endregion

        /// <summary>
        /// Raises the item selected event.
        /// </summary>
        /// <param name=sender>The sender.</param>
        /// <param name=e>The event args</param>
        private void OnItemSelected(object sender, ToggledEventArgs e)
        {
            if (this.CommandToggled != null && sender.GetType() == typeof(ExtSwitch) && ((ExtSwitch)sender).CommandToggledParameter != null && this.CommandToggled.CanExecute(e) && e.Value)
            {
                this.CommandToggled.Execute(this.CommandToggledParameter);
            }
        }

        /// <summary>
        /// Subscribes the click to raise command.
        /// </summary>
        private void SubscribeClickToRaiseCommand()
        {
            var tapGestureRecognizer = new TapGestureRecognizer();
            tapGestureRecognizer.Tapped += (sender, e) =>
            {
                if (this.CommandToggled != null && this.CommandToggled.CanExecute(e))
                {
                    this.CommandToggled.Execute(this.CommandToggledParameter);
                }
            };
            this.GestureRecognizers.Add(tapGestureRecognizer);
        }
    }
}


ExtProgressBar

This control needs a custom renderer to use the ProgressColor. A custom renderer gives you the possibility to animate the progress bar on iOS when its progress value changes.

//
// <copyright file=ExtProgressBar.cs company=Krossapp>
//     Copyright (c) Krossapp. All rights reserved.
// </copyright>
// <author>Nicolas Krier</author>
//
namespace SDF.XForm.Controls
{
    #region Using

    using System.Diagnostics.CodeAnalysis;
    using Xamarin.Forms;

    #endregion

    /// <summary>
    /// Progress bar.
    /// </summary>
    public class ExtProgressBar : ProgressBar
    {
        #region Bindable property

        /// <summary>
        /// The progress color property.
        /// </summary>
        [SuppressMessage(StyleCop.CSharp.MaintainabilityRules, SA1401:FieldsMustBePrivate, Justification = Reviewed.)]
        public static BindableProperty ProgressColorProperty = BindableProperty.Create<ExtProgressBar, Color>(x => x.ProgressColor, Color.Blue);

        #endregion

        #region Constructor

        /// <summary>
        /// Initializes a new instance of the <see cref=ExtProgressBar/> class.
        /// </summary>
        public ExtProgressBar()
            : base()
        {
        }

        #endregion

        #region Property

        /// <summary>
        /// Gets or sets the color of the progress.
        /// </summary>
        /// <value>The color of the progress.</value>
        public Color ProgressColor
        {
            get { return (Color)this.GetValue(ProgressColorProperty); }
            set { this.SetValue(ProgressColorProperty, value); }
        }

        #endregion
    }
}


ExtListView

I like to bind a command to my list view so I don’t have to create a wrapper to pass the item tapped command. I also deactivate the separator which behave very strange sometimes depends on the device. I prefer to handle it myself. I have added a DesactivateSelection property so once you’ve tapped an item, the command is executed and the item gets unselected.

I created this control before the pull to refresh and pull to load event were added to the list view. I still not have clean this control yet. It’s in my todo ;D

//
// <copyright file=ExtListView.cs company=Krossapp>
//     Copyright (c) Krossapp. All rights reserved.
// </copyright>
// <author>Nicolas Krier</author>
//
namespace SDF.XForm.Controls
{
    #region Using

    using System.Diagnostics.CodeAnalysis;
    using System.Windows.Input;
    using Xamarin.Forms;

    #endregion

    /// <summary>
    /// List view.
    /// </summary>
    public class ExtListView : ListView
    {
        #region Bindable property

        /// <summary>
        /// The command refresh property.
        /// </summary>
        [SuppressMessage(StyleCop.CSharp.MaintainabilityRules, SA1401:FieldsMustBePrivate, Justification = Reviewed.)]
        public static BindableProperty CommandRefreshProperty = BindableProperty.Create<ExtListView, ICommand>(x => x.CommandRefresh, null);

        /// <summary>
        /// The deselection auto property.
        /// </summary>
        [SuppressMessage(StyleCop.CSharp.MaintainabilityRules, SA1401:FieldsMustBePrivate, Justification = Reviewed.)]
        public static BindableProperty DesactivateSelectionProperty = BindableProperty.Create<ExtListView, bool>(x => x.DesactivateSelection, false);

        /// <summary>
        /// The command clicked property.
        /// </summary>
        [SuppressMessage(StyleCop.CSharp.MaintainabilityRules, SA1401:FieldsMustBePrivate, Justification = Reviewed.)]
        public static BindableProperty CommandProperty = BindableProperty.Create<ExtListView, ICommand>(x => x.Command, null);

        #endregion

        #region Constructor

        /// <summary>
        /// Initializes a new instance of the <see cref=ExtListView/> class.
        /// </summary>
        public ExtListView()
        {
            this.SeparatorVisibility = SeparatorVisibility.None;

            // this.ItemTapped += this.OnItemTapped;
            this.ItemSelected += this.OnItemSelected;
        }

        #endregion

        #region Property

        /// <summary>
        /// Gets or sets a value indicating whether this <see cref=ListView/> deselection auto.
        /// </summary>
        /// <value><c>true</c> if deselection auto; otherwise, <c>false</c>.</value>
        public bool DesactivateSelection
        {
            get { return (bool)this.GetValue(DesactivateSelectionProperty); }
            set { this.SetValue(DesactivateSelectionProperty, value); }
        }

        /// <summary>
        /// Gets or sets the command clicked.
        /// </summary>
        /// <value>The command clicked.</value>
        public ICommand Command
        {
            get { return (ICommand)this.GetValue(CommandProperty); }
            set { this.SetValue(CommandProperty, value); }
        }

        /// <summary>
        /// Gets or sets the command refresh.
        /// </summary>
        /// <value>The command refresh.</value>
        public ICommand CommandRefresh
        {
            get { return (ICommand)GetValue(CommandRefreshProperty); }
            set { this.SetValue(CommandRefreshProperty, value); }
        }

        #endregion

        /// <summary>
        /// Raises the item tapped event.
        /// </summary>
        /// <param name=sender>The sender.</param>
        /// <param name=e>The event args.</param>
        private void OnItemTapped(object sender, ItemTappedEventArgs e)
        {
            if (e.Item != null && this.Command != null && this.Command.CanExecute(e))
            {
                this.Command.Execute(e.Item);
            }
        }

        /// <summary>
        /// Raises the item selected event.
        /// </summary>
        /// <param name=sender>The sender.</param>
        /// <param name=e>The event args.</param>
        private void OnItemSelected(object sender, SelectedItemChangedEventArgs e)
        {
            // We force the selected item so the view model can handle differents events.
            this.SelectedItem = e.SelectedItem;

            if (e.SelectedItem != null && this.Command != null && this.Command.CanExecute(e))
            {
                this.Command.Execute(e.SelectedItem);
            }

            if (this.DesactivateSelection)
            {
                this.SelectedItem = null;
            }
        }
    }
}


ExtImage

This is my image control. I have added a property that allows me to change the look of the control so it looks like it is desabled. You can also bind a command to it that will be executed on tapp on the image.

//
// <copyright file=ExtImage.cs company=Krossapp>
//     Copyright (c) Krossapp. All rights reserved.
// </copyright>
// <author>Nicolas Krier</author>
//
namespace SDF.XForm.Controls
{
    #region Using

    using System;
    using System.Diagnostics.CodeAnalysis;
    using System.Windows.Input;
    using Xamarin.Forms;

    #endregion

    /// <summary>
    /// The Button.
    /// </summary>
    public class ExtImage : Image
    {
        #region Bindable property

        /// <summary>
        /// The command property.
        /// </summary>
        [SuppressMessage(StyleCop.CSharp.MaintainabilityRules, SA1401:FieldsMustBePrivate, Justification = Reviewed.)]
        public static BindableProperty CommandProperty = BindableProperty.Create<ExtImage, ICommand>(x => x.Command, null);

        /// <summary>
        /// The command indicatique wether the image should be opaque or not.
        /// </summary>
        [SuppressMessage(StyleCop.CSharp.MaintainabilityRules, SA1401:FieldsMustBePrivate, Justification = Reviewed.)]
        public static BindableProperty IsImageOpaqueProperty = BindableProperty.Create<ExtImage, bool>(x => x.IsImageOpaque, false, propertyChanged: WhenIsImageOpaqueChanged);

        #endregion

        #region Constructor

        /// <summary>
        /// Initializes a new instance of the <see cref=ExtImage/> class.
        /// </summary>
        public ExtImage()
            : base()
        {
            // this.SetBinding(ExtButton.IsEnabledProperty, new Binding(CanExecute, BindingMode.OneWay));
            this.SubscribeClickToRaiseCommand();
        }

        #endregion

        #region Property

        /// <summary>
        /// Gets or sets the command clicked.
        /// </summary>
        /// <value>The command clicked.</value>
        public ICommand Command
        {
            get { return (ICommand)this.GetValue(CommandProperty); }
            set { this.SetValue(CommandProperty, value); }
        }

        /// <summary>
        /// Gets or sets a value indicating whether this image is opaque.
        /// </summary>
        /// <value><c>true</c> if this instance is image opaque; otherwise, <c>false</c>.</value>
        public bool IsImageOpaque
        {
            get { return (bool)this.GetValue(IsImageOpaqueProperty); }
            set { this.SetValue(IsImageOpaqueProperty, value); }
        }

        #endregion

        /// <summary>
        /// Raises the html changed event.
        /// </summary>
        /// <param name=sender>The sender.</param>
        /// <param name=oldValue>Old value.</param>
        /// <param name=newValue>New value.</param>
        private static void WhenIsImageOpaqueChanged(BindableObject sender, bool oldValue, bool newValue)
        {
            if (sender == null)
            {
                return;
            }

            var ctrl = (ExtImage)sender;
            ctrl.Opacity = newValue ? 0.25 : 1.0;
        }

        /// <summary>
        /// Subscribes the click to raise command.
        /// </summary>
        private void SubscribeClickToRaiseCommand()
        {
            var tapGestureRecognizer = new TapGestureRecognizer();
            tapGestureRecognizer.Tapped += async (sender, e) =>
            {
                if (this.Command != null && this.Command.CanExecute(e))
                {
                    uint duration = 100;
                    await this.ScaleTo(.75, duration);
                    await this.ScaleTo(1, duration);

                    this.Command.Execute(null);
                }
            };
            
            this.GestureRecognizers.Add(tapGestureRecognizer);
        }
    }
}


ExtHyperLink

This is my hyperlink control. I can use some generic style on it. This control must have the appearance of a classic html hyperlink. By default it behaves like a button. But it can also be used to open the default mailing app of the device. This control allows you to open a phone number in the dial screen. Last, this control can be used to open a location on the default map application of the device.

//
// <copyright file=ExtHyperLink.cs company=Krossapp>
//     Copyright (c) Krossapp. All rights reserved.
// </copyright>
// <author>Nicolas Krier</author>
//
namespace SDF.XForm.Controls
{
    #region Using

    using System;
    using System.Diagnostics.CodeAnalysis;
    using System.Windows.Input;
    using Xamarin.Forms;

    #endregion

    /// <summary>
    /// All kind of link types.
    /// </summary>
    public enum TypesLink
    {
        /// <summary>
        /// The default link : execute the command binded.
        /// </summary>
        Default = 0,

        /// <summary>
        /// The email.
        /// </summary>
        Email,

        /// <summary>
        /// The phone number.
        /// </summary>
        PhoneNumber,

        /// <summary>
        /// The location.
        /// </summary>
        Location
    }

    /// <summary>
    /// “Xamarin.Forms.Label” extended to get a kind of hyperlink.
    /// </summary>
    public class ExtHyperLink : Label
    {
        #region Bindable property

        /// <summary>
        /// The type link property.
        /// </summary>
        [SuppressMessage(StyleCop.CSharp.MaintainabilityRules, SA1401:FieldsMustBePrivate, Justification = Reviewed.)]
        public static BindableProperty TypeLinkProperty = BindableProperty.Create<ExtHyperLink, TypesLink>(x => x.TypeLink, TypesLink.Default);

        /// <summary>
        /// The command clicked property.
        /// </summary>
        [SuppressMessage(StyleCop.CSharp.MaintainabilityRules, SA1401:FieldsMustBePrivate, Justification = Reviewed.)]
        public static BindableProperty CommandProperty = BindableProperty.Create<ExtHyperLink, ICommand>(x => x.Command, null);

        #endregion

        #region Constructor

        /// <summary>
        /// Initializes a new instance of the <see cref=ExtHyperLink/> class.
        /// </summary>
        public ExtHyperLink()
            : base()
        {
            this.FontSize = Device.GetNamedSize(NamedSize.Medium, typeof(Xamarin.Forms.Label));
            this.LineBreakMode = Xamarin.Forms.LineBreakMode.TailTruncation;
            this.SubscribeClickToRaiseCommand();
        }

        #endregion

        #region Property

        /// <summary>
        /// Gets or sets the type link.
        /// </summary>
        /// <value>The type link.</value>
        public TypesLink TypeLink
        {
            get { return (TypesLink)this.GetValue(TypeLinkProperty); }
            set { this.SetValue(TypeLinkProperty, value); }
        }

        /// <summary>
        /// Gets or sets the command clicked.
        /// </summary>
        /// <value>The command clicked.</value>
        public ICommand Command
        {
            get { return (ICommand)this.GetValue(CommandProperty); }
            set { this.SetValue(CommandProperty, value); }
        }

        #endregion

        /// <summary>
        /// Subscribes the click to raise command.
        /// </summary>
        private void SubscribeClickToRaiseCommand()
        {
            var tapGestureRecognizer = new TapGestureRecognizer();
            tapGestureRecognizer.Tapped += (sender, e) =>
            {
                if (this.TypeLink == TypesLink.Default)
                {
                    if (this.Command != null)
                    {
                        Command.Execute(null);
                    }
                }
                else if (this.TypeLink == TypesLink.PhoneNumber)
                {
                    string numTel = this.Text.Replace(., string.Empty);
                    numTel = numTel.Replace( , string.Empty);
                    numTel = numTel.Replace(, string.Empty);
                    Device.OpenUri(new Uri(tel:// + numTel));
                }
                else if (this.TypeLink == TypesLink.Email)
                {
                    Device.OpenUri(new Uri(mailto: + this.Text));
                }
                else if (this.TypeLink == TypesLink.Location)
                {
                    Device.OpenUri(new Uri(geo: + this.Text));
                }
                else
                {
                    throw new NotImplementedException(SubscribeClickToRaiseCommand > TypeLink not implemented);
                }
            };
            this.GestureRecognizers.Add(tapGestureRecognizer);
        }
    }
}


ExtContentPage

This is the code of my base page. I use to set up a binding by default on a property called IsLoading. Thus, in my view models, I just have to change the value of the IsLoading property and my view will display the busy indicator of the page.

In the OnAppearing event of the ContentPage, I call the LoadViewModel method. I have an InitializeViewModel method which is intend to be called once. The LoadViewModel will be called each time the page appear on the screen.

//
// <copyright file=ExtContentPage.cs company=Krossapp>
//     Copyright (c) Krossapp. All rights reserved.
// </copyright>
// <author>Nicolas Krier</author>
//
namespace SDF.XForm.Controls
{
    #region Using

    using SDF.Core.ViewModels;
    using Xamarin.Forms;

    #endregion

    /// <summary>
    /// Content page base.
    /// </summary>
    public class ExtContentPage : ContentPage
    {
        #region Constructor

        /// <summary>
        /// Initializes a new instance of the <see cref=ExtContentPage/> class.
        /// </summary>
        public ExtContentPage()
            : base()
        {
            this.SetBinding(ExtContentPage.IsBusyProperty, new Binding(IsLoading, BindingMode.OneWay));
        }

        #endregion

        #region Property

        /// <summary>
        /// Gets the view model.
        /// </summary>
        /// <value>The view model.</value>
        public ViewModelBaseExt ViewModel
        {
            get
            {
                return this.BindingContext == null ? null : this.BindingContext as ViewModelBaseExt;
            }
        }

        #endregion

        /// <summary>
        /// Raises the appearing event and initialize the view model.
        /// </summary>
        protected override void OnAppearing()
        {
            base.OnAppearing();
            this.ViewModel.LoadViewModel();
        }
    }
}