Xamarin.forms: [Enhancement] Checkbox Control

Created on 29 Jan 2018  Â·  21Comments  Â·  Source: xamarin/Xamarin.Forms

Rationale

Currently the only type of toggle control is a switch. Checkboxes can be useful for indicating action. For example agreeing to something and there are cases where people prefer a checkbox to a switch for their UI.

Implementation

Create a new Control and set of platform renderers for a CheckBox control and a CheckBoxCell

public class CheckBox : IButtonController
{
        public bool IsChecked {get; set; } // BP
}

VisualStateManager additions: Checked, Pressed

Android

https://developer.android.com/guide/topics/ui/controls/checkbox.html

iOS

Draw it

UWP

https://docs.microsoft.com/en-us/windows/uwp/design/controls-and-patterns/checkbox

Implications for CSS

Ensure a new target is created that maps to the new control

checkbox {
}

Backward Compatibility

This is a new control so there shouldn't be any issues with backwards compatibility

Difficulty : Medium

Not much work for Android and UWP but the iOS implementation still needs to be fleshed out a bit

F100 community-sprint help wanted in-progress enhancement âž• up-for-grabs

Most helpful comment

@samhouts @davidortinau @jassmith @jamesmontemagno @migueldeicaza Some feedback is required.
It requires some thinking in order to share as much as the existing implementation as possible.

It makes sense for CheckBox to implement these interfaces too: IFontElement, ITextElement, IBorderElement, IButtonController, IElementConfiguration, IPaddingElement
It makes sense for CheckBox to derive from Button.
The only issue I see is with iOS and how to handle the Image and ContentLayout properties.
On Android and UWP, a check-box could display an image if one would really want to, some simple modifications on renderers would allow that.

But the problem is on iOS, and I see these options for iOS:

  • Handle Image property allowing a CheckBox to have an image too. Some effort is required for this.
  • Use Image property for drawing the check. It would be very easy to do it like this. The problem would be how to handle it for Android and UWP, should it work only on these, but not on iOS?
  • Ignore the Image property. Then, how do handle it with Android and UWP, should it work on these or ignore it too?

Instead of deriving CheckBox from Button, another option is to add an intermediate class, called ButtonBase and have Button, CheckBox (and possibly RadioButton) derive it. All the current implementation of Button will move to ButtonBase, except Image and ContentLayout properties.
This would allow CheckBox to have all other existing properties of Button.

Additionally, I am thinking to have a ButtonBaseRenderer in every platform, and have the existing ButtonRenderer derive from it. CheckBoxRenderer would derive from ButtonBaseRenderer. This would allow sharing all logic in the existing ButtonRenderer (padding, font, border, etc.)
(the more I think about it, I think ideally I think we should actually have a base class ControlRenderer which has these).

Another problem I see is on WPF, I see Switch renders as WPF CheckBox. If we added a CheckBox in XF, we shouldn't map same control to same native control. Wouldn't look strange? Or it would be OK?

I also have a question. Is WPF supported offically? Meaning if I'd add a CheckBox, should I also include implementation for WPF too?

Looking forward for your input here.

All 21 comments

A decision needs to be taken for iOS.
For how it needs to look, I suggest using the look from Mac OSX (NSSwitchButton style)
And I think we should draw it using Core Graphics since vector graphics is only an option for iOS 11+ by using PDF AFAIK.

If this is implemented, I feel it should definitely have a tristate option, as this is one of the major use cases for checkboxes for me.
More important that a checkbox would be a radio button group, which I don't believe is on your list of new or enhances controls?

This needs some planning. There's already a Slider control.
I suggest having a ToggleButton abstract class and have CheckBox derive from it. Switch should derive from it too but I guess it's too late for that.

Well Switch currently derives from View, so I would have thought it possible to insert ToggleButton into the inheritance chain as suggested. However, I think that if this is being looked at then perhaps adding an interface or similar and making Switch and SwitchCell more consistent would be very useful as well as adding a bindable ToggleCommand in addition to the ToggledEvent.
Not sure quite how tristate would be handled using the existing event though as it would really need to have Value defined as bool? rather than bool.

@andreinitescu Here is pseudo code for set of classes that maintains the base types already in Xamarin.Forms along with their properties but rationalises the existing controls and adds a CheckBox and TriState variant control. Obviously I have not included any of the binding properties or hooked up the implementations at all, but thought it might be food for thought and addresses your comment regarding base abstract classes.

    public interface IToggle<TValueType, TEventArgs> 
        where TEventArgs : ToggledEventArgs<TValueType>
    {
        TValueType Value { get; set; }

        event EventHandler<TEventArgs> Toggled;
    }
    public abstract class Toggle<TValueType,TEventArgs> : 
        View,
        IToggle<TValueType, TEventArgs>
        where TEventArgs : ToggledEventArgs<TValueType>
    {

        public event System.EventHandler<TEventArgs> Toggled;

        public TValueType Value { get; set; }

        protected virtual void OnToggled() {
            Toggled?.Invoke(this, CreateEventArgs());
        }
        protected abstract TEventArgs CreateEventArgs();

    }



md5-97f8e0df18a233a0384125d86fab6494



    public abstract class ToggleCell<TValueType, TEventArgs> : Xamarin.Forms.Cell, 
        IToggle<TValueType, TEventArgs>
        where TEventArgs : ToggledEventArgs<TValueType>
    {
        public event EventHandler<TEventArgs> Toggled;
        public TValueType Value { get; set; }

        public string Text { get; set; }

        public ToggleCell() : base() { }

        public ToggleCell(string text, TValueType value = default(TValueType)) : this() {
            Text = text;
            Value = value;
        }

        protected virtual void OnToggled()
        {
            Toggled?.Invoke(this, CreateEventArgs());
        }
        protected abstract TEventArgs CreateEventArgs();
    }



md5-97f8e0df18a233a0384125d86fab6494



    public class ToggledEventArgs<TValueType> : EventArgs
    {
        public TValueType Value { get; }
        public ToggledEventArgs(TValueType value)
        {
            Value = value;
        }
    }



md5-97f8e0df18a233a0384125d86fab6494



    public class ToggledEventArgs : ToggledEventArgs<bool>
    {
        public ToggledEventArgs(bool value) : base(value) { }
    }



md5-97f8e0df18a233a0384125d86fab6494



    public class Switch :
        Toggle<bool, ToggledEventArgs>,
        IElementConfiguration<Switch>
    {
        public Switch() { }

        public IPlatformElementConfiguration<T, Switch> On<T>() where T : IConfigPlatform
        {
            throw new NotImplementedException();
        }

        [Obsolete("Use Value property")]
        public bool IsToggled { get => Value; set => Value = value; }

        protected override ToggledEventArgs CreateEventArgs() => new ToggledEventArgs(Value);
    }



md5-97f8e0df18a233a0384125d86fab6494



    public class SwitchCell : ToggleCell<bool,ToggledEventArgs>
    {
        public EventHandler<ToggledEventArgs> OnChanged { get; set; }

        [Obsolete("Use Value property")]
        public bool On { get => Value; set => Value = value; }

        public string Text { get; set; }
        protected override ToggledEventArgs CreateEventArgs() => new ToggledEventArgs(Value);

        protected override void OnToggled()
        {
            base.OnToggled();
            OnChanged?.Invoke(this,CreateEventArgs());
        }
    }



md5-97f8e0df18a233a0384125d86fab6494



    public class CheckBox : Toggle<bool, ToggledEventArgs>
    {
        protected override ToggledEventArgs CreateEventArgs() => new ToggledEventArgs(Value);
    }



md5-97f8e0df18a233a0384125d86fab6494



    public class CheckBoxCell : ToggleCell<bool, ToggledEventArgs>
    {
        protected override ToggledEventArgs CreateEventArgs() => new ToggledEventArgs(Value);
    }



md5-97f8e0df18a233a0384125d86fab6494



    public class TriState : Toggle<bool?, ToggledEventArgs<bool?>>
    {
        protected override ToggledEventArgs<bool?> CreateEventArgs() => new ToggledEventArgs<bool?>(Value);
    }



md5-97f8e0df18a233a0384125d86fab6494



    public class TriStateCell : ToggleCell<bool?, ToggledEventArgs<bool?>>
    {
        protected override ToggledEventArgs<bool?> CreateEventArgs() => new ToggledEventArgs<bool?>(Value);
    }

TriState is an interesting one because UWP is really the only place that has that concept natively.

So for Android and iOS it'd have to be "invented" though iOS it's all being invented :-)

UWP is really the only platform I've seen that has an indeterminate state even other things like Flutter/React Native just have two

Tristate might be something better left to an effect/toolkit because I'm not sure if the added complexity in the core is worth it. This is the approach React Native took as well just declaring that it's easy enough for a user to implement themselves

For iOS I haven't really come across any implementation beyond just using images so seems like just need to settle on the images to bundle

I thought about the grouping as well in this scenario but it seems like the grouping will come about when we introduce a RadioButton. Which has native implementation on Android/UWP

For iOS I haven't really come across any implementation beyond just using images so seems like just need to settle on the images to bundle

It's pretty simple to do it with Core API.

This control is a must.
I think most people don't really give a 💩 if a control is not native in one or more platforms if the price is implementing or using custom renderers over and over again.
Xamarin.Forms should offer more controls, and loosen up it's strict 'native-only' rule.
Maybe non-native controls should be exposed under a different namespace or via an external official toolkit eventho it's redundant IMHO.
Please implement this.

Hi everyone!

I'm ready for resubmitting this control to Forms repository from https://github.com/xamarin/XamarinCommunityToolkit/pull/59

@wcoder Please do! Thanks. :)

@wcoder I see you're using Core API to draw the control on iOS which is what I wanted, but can you please attach a screenshot how the checkbox looks like on iOS? Thanks

@samhouts what do think about this library?

https://github.com/enisn/Xamarin.Forms.InputKit

2404

It's not clear to me how the API should look like, whether Xamarin agrees to painting the checkbox on iOS and how...

@samhouts @davidortinau @jassmith @jamesmontemagno @migueldeicaza Some feedback is required.
It requires some thinking in order to share as much as the existing implementation as possible.

It makes sense for CheckBox to implement these interfaces too: IFontElement, ITextElement, IBorderElement, IButtonController, IElementConfiguration, IPaddingElement
It makes sense for CheckBox to derive from Button.
The only issue I see is with iOS and how to handle the Image and ContentLayout properties.
On Android and UWP, a check-box could display an image if one would really want to, some simple modifications on renderers would allow that.

But the problem is on iOS, and I see these options for iOS:

  • Handle Image property allowing a CheckBox to have an image too. Some effort is required for this.
  • Use Image property for drawing the check. It would be very easy to do it like this. The problem would be how to handle it for Android and UWP, should it work only on these, but not on iOS?
  • Ignore the Image property. Then, how do handle it with Android and UWP, should it work on these or ignore it too?

Instead of deriving CheckBox from Button, another option is to add an intermediate class, called ButtonBase and have Button, CheckBox (and possibly RadioButton) derive it. All the current implementation of Button will move to ButtonBase, except Image and ContentLayout properties.
This would allow CheckBox to have all other existing properties of Button.

Additionally, I am thinking to have a ButtonBaseRenderer in every platform, and have the existing ButtonRenderer derive from it. CheckBoxRenderer would derive from ButtonBaseRenderer. This would allow sharing all logic in the existing ButtonRenderer (padding, font, border, etc.)
(the more I think about it, I think ideally I think we should actually have a base class ControlRenderer which has these).

Another problem I see is on WPF, I see Switch renders as WPF CheckBox. If we added a CheckBox in XF, we shouldn't map same control to same native control. Wouldn't look strange? Or it would be OK?

I also have a question. Is WPF supported offically? Meaning if I'd add a CheckBox, should I also include implementation for WPF too?

Looking forward for your input here.

@jassmith @hartez @samhouts any thoughts?

I can work on this, but I'm waiting for #1974 to be merged into master

I think i will do some work today on this on my live stream @andreinitescu

@andreinitescu @jamesmontemagno @samhouts with #1974 merged, is further progress being made to merge this in or has this task been put on hold for a later release? Checkbox control functionality is a highly desired functionality in Xamarin. Thanks!

@nawidy the PR James has done is close https://github.com/xamarin/Xamarin.Forms/pull/4369 we've just had some other things take priority in our current sprint but we will be getting back to the CheckBox soon

Thanks @PureWeen for the update. Looking forward to seeing this in :)

closed by #6232

Was this page helpful?
0 / 5 - 0 ratings