简体   繁体   中英

Create a custom iOS control in xamarin

I have created a custom iOS control in a Xamarin project. However, it currently does not draw on to the page when added into the XAML on a Xamarin.Forms page.

<OnPlatform.iOS>
    <iOSControls:CellContent BindingContext="{Binding}" CellData="{Binding VM.CellCollection}"/>
</OnPlatform.iOS>

I am also not sure if this is the correct way to bind data from the ViewModel on to the control, and due to the fact it does not load am unable to test this.

The CellContent class is as below

   `Public partial class CellContent : UIView
    {

    #region [ Private Fields ]

    /// <summary>
    /// The cell data model used for generating each cell
    /// </summary>
    private ICell cellData;

    #endregion

    #region [ Constructor ]

    /// <summary>
    /// Initializes a new instance of the <see cref="CellContent" /> class.
    /// </summary>
    /// <param name="handle">handle pointer passed to the base class</param>
    public CellContent(IntPtr handle) : base(handle)
    {
    }

    #endregion

    #region [ Public Properties ]

    /// <summary>
    /// Gets or sets the cell data model
    /// </summary>
    [Export("CellData"), Browsable(true)]
    public ICell CellData
    {
        get
        {
            return this.cellData;
        }
        set
        {
            this.cellData = value;
        }
    }

    #endregion

    #region [ UIView Events ]

    /// <summary>
    /// Static control generator
    /// </summary>
    /// <returns>A control instance</returns>
    public static CellContent Create()
    {
        var arr = NSBundle.MainBundle.LoadNib("CellContent", null, null);
        var v = Runtime.GetNSObject<CellContent>(arr.ValueAt(0));

        return v;
    }

    /// <summary>
    /// Initialises the sub controls
    /// </summary>
    public override void AwakeFromNib()
    {
        base.AwakeFromNib();

        HorizontalGridLines horizontalRows = HorizontalGridLines.Create();
        VerticalGridLines verticalRows = VerticalGridLines.Create();
        PlottedActivity plottedActivity = PlottedActivity.Create();
        horizontalRows.VM = this.CellData;
        verticalRows.VM = this.CellData;
        plottedActivity.VM = this.CellData;

        this.AddSubview(horizontalRows);
        this.AddSubview(verticalRows);
        this.AddSubview(plottedActivity);
    }

    #endregion`

The horizontal/vertical grid lines and plotted activity files are all basically the same and I have verified they work in a separate project (without the binding or being instantiated from the XAML), but the HorizontalGridLines file can be seen below as well for reference

`public partial class HorizontalGridLines : UIView
{
    /// <summary>
    /// Initializes a new instance of the <see cref="HorizontalGridLines" /> class.
    /// </summary>
    /// <param name="handle">handle pointer passed to the base class</param>
    public HorizontalGridLines(IntPtr handle) : base(handle)
    {
    }

    /// <summary>
    /// Gets or sets the data context cast as an interface for binding
    /// </summary>
    [Export("CellData"), Browsable(true)]
    public ICell CellData{ get; set; }

    /// <summary>
    /// Static control generator
    /// </summary>
    /// <returns>A control instance</returns>
    public static HorizontalGridLines Create()
    {
        var arr = NSBundle.MainBundle.LoadNib("HorizontalGridLines", null, null);
        var v = Runtime.GetNSObject<HorizontalGridLines>(arr.ValueAt(0));

        return v;
    }

    /// <summary>
    /// Drawing override
    /// </summary>
    /// <param name="rect">The content bounds</param>
    public override void Draw(CGRect rect)
    {
        base.Draw(rect);
        int numOfLines = this.CellData.ActivityRows.Count;

        var context = UIGraphics.GetCurrentContext();

        context.SetLineWidth(2);
        context.SetLineDash(0, new nfloat[] { 3, 4 });
        UIColor.Black.SetStroke();

        int y = 0;

        int width = (int)this.Frame.Width;
        int height = (int)this.Frame.Height;
        int heightPerLine = y = height / numOfLines;

        for (int i = 0; i < numOfLines - 1; i++)
        {
            var path = new CGPath();
            CGPoint[] lines = new CGPoint[2];
            lines[0] = new PointF(0, y);
            lines[1] = new PointF(width, y);
            y += heightPerLine;
            path.AddLines(lines);
            path.CloseSubpath();
            context.AddPath(path);
        }

        context.DrawPath(CGPathDrawingMode.FillStroke);
    }
}`

Any help would be greatly appreciated, thanks! :)

So I discovered the way to do this:

  • On the custom control that you have created, create a public property that you will be assigning your data to.
  • On the XAML assign the {Binding .} to the public property you have just created providing that they are of the same type.
  • The data will be accessible from within the custom control during/after the LayoutSubviews() method.

For Example:

<iOSControls:CellContent CellData="{Binding .}"/>

The BindingContext property seems to be a part of standard Xamarin controls rather than custom native controls.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM