I am building an application using Xamarin.iOS. At first I want to display a list of categories in a GridView. For this I have used CollectionView with Custom Cell Layout. To build the Custom Cell Layout I have used "CollectioViewCell" from the interface which allows me to design the layout with Drag and Drop.
Below is the code:
ViewController.cs
public override void ViewDidLoad ()
{
base.ViewDidLoad ();
//initialize the data
sectionCategories = new List<SectionCategory>();
sectionCategories.Add(new SectionCategory("Lajme", "LajmeUrl"));
sectionCategories.Add(new SectionCategory("Lajme", "LajmeUrl"));
sectionCategories.Add(new SectionCategory("Lajme", "LajmeUrl"));
sectionCategories.Add(new SectionCategory("Lajme", "LajmeUrl"));
sectionCategories.Add(new SectionCategory("Lajme", "LajmeUrl"));
sectionCategories.Add(new SectionCategory("Lajme", "LajmeUrl"));
sectionCategories.Add(new SectionCategory("Lajme", "LajmeUrl"));
sectionCategories.Add(new SectionCategory("Lajme", "LajmeUrl"));
sectionGrid.RegisterClassForCell(typeof(SectionViewCell), SectionViewCell.Key);
sectionGrid.Source = new SectionViewSource (sectionCategories);
}
SectionViewCell.cs
public partial class SectionViewCell : UICollectionViewCell
{
public static readonly NSString Key = new NSString ("SectionViewCell");
public static readonly UINib Nib;
static SectionViewCell ()
{
Nib = UINib.FromName ("SectionViewCell", NSBundle.MainBundle);
}
public SectionViewCell (IntPtr handle) : base (handle)
{
}
public void UpdateCell (string text)
{
imageUrl.Text = text;
sectionName.Text = text;
}
}
SectionViewCell.designer.cs
[Register ("SectionViewCell")]
partial class SectionViewCell
{
[Outlet]
[GeneratedCode ("iOS Designer", "1.0")]
UILabel imageUrl { get; set; }
[Outlet]
[GeneratedCode ("iOS Designer", "1.0")]
UILabel sectionName { get; set; }
void ReleaseDesignerOutlets ()
{
if (imageUrl != null) {
imageUrl.Dispose ();
imageUrl = null;
}
if (sectionName != null) {
sectionName.Dispose ();
sectionName = null;
}
}
}
SectionViewSource.cs
public class SectionViewSource: UICollectionViewSource
{
public List<SectionCategory> category { get; set; }
public SectionViewSource(List<SectionCategory> _category)
{
category = _category;
}
public override nint NumberOfSections (UICollectionView collectionView)
{
return 1;
}
public override nint GetItemsCount (UICollectionView collectionView, nint section)
{
return category.Count;
}
public override UICollectionViewCell GetCell (UICollectionView collectionView, NSIndexPath indexPath)
{
var cell = (SectionViewCell)collectionView.DequeueReusableCell (SectionViewCell.Key, indexPath);
cell.UpdateCell ("lajme");
return cell;
}
}
But when I run the app it throws me an error:
System.NullReferenceException: Object reference not set to an instance of an object
at MyIkub.SectionViewCell.UpdateCell (System.String text) [0x00008] in /Users/crs/Projects/MyIkub/MyIkub/SectionViewCell.cs:26
at MyIkub.SectionViewSource.GetCell (UIKit.UICollectionView collectionView, Foundation.NSIndexPath indexPath) [0x00019] in /Users/crs/Projects/MyIkub/MyIkub/SectionViewSource.cs:33
at at (wrapper managed-to-native) UIKit.UIApplication:UIApplicationMain (int,string[],intptr,intptr)
at UIKit.UIApplication.Main (System.String[] args, IntPtr principal, IntPtr delegate) [0x00005] in /Users/builder/data/lanes/2761/d7cac503/source/maccore/src/UIKit/UIApplication.cs:77
at UIKit.UIApplication.Main (System.String[] args, System.String principalClassName, System.String delegateClassName) [0x0001c] in /Users/builder/data/lanes/2761/d7cac503/source/maccore/src/UIKit/UIApplication.cs:60
at MyIkub.Application.Main (System.String[] args) [0x00008] in /Users/crs/Projects/MyIkub/MyIkub/Main.cs:12
Any suggestions?
Use RegisterNibForCell instead of RegisterClassForCell.
sectionGrid.RegisterNibForCell (UINib.FromName("SectionViewCell", NSBundle.MainBundle), SectionViewCell.Key);
Here is a tutorial
Related
I'm following mvvmcross tutorial for iOS project. I think I'm doing exactly for is described there, but when I run the appliaction I'm getting following error:
ObjCRuntime.RuntimeException
Message=Failed to lookup the required marshalling information.
Additional information:
Selector: setGenerositySlider:
Type: TipView
Source=
StackTrace:
at (wrapper managed-to-native) UIKit.UIApplication.UIApplicationMain(int,string[],intptr,intptr)
at UIKit.UIApplication.Main (System.String[] args, System.IntPtr principal, System.IntPtr delegate) [0x00005] in /Library/Frameworks/Xamarin.iOS.framework/Versions/14.2.0.12/src/Xamarin.iOS/UIKit/UIApplication.cs:86
at UIKit.UIApplication.Main (System.String[] args, System.String principalClassName, System.String delegateClassName) [0x0000e] in /Library/Frameworks/Xamarin.iOS.framework/Versions/14.2.0.12/src/Xamarin.iOS/UIKit/UIApplication.cs:65
at TipCalc.iOS.Application.Main (System.String[] args) [0x00001] in C:\Users\MYUSERNAME\source\repos\xamarin\TipCalc.Core\TipCalc.iOS\Main.cs:12
I cloned the same project from the samples and it runs fine. I think I compared everything I could and projects are the same as far as I can tell.
namespace TipCalc.iOS
{
public class Application
{
// This is the main entry point of the application.
static void Main(string[] args)
{
// if you want to use a different Application Delegate class from "AppDelegate"
// you can specify it here.
UIApplication.Main(args, null, "AppDelegate");
}
}
}
namespace TipCalc.iOS
{
[Register(nameof(AppDelegate))]
public class AppDelegate : MvxApplicationDelegate<MvxIosSetup<App>, App>
{
public override UIWindow Window { get; set; }
public override bool FinishedLaunching(UIApplication application, NSDictionary launchOptions)
{
var result = base.FinishedLaunching(application, launchOptions);
return result;
}
}
}
public partial class TipView : MvxViewController<TipViewModel>
{
public TipView() : base(nameof(TipView), null)
{
}
public override void ViewDidLoad()
{
base.ViewDidLoad();
var set = this.CreateBindingSet<TipView, TipViewModel>();
set.Bind(TipLabel).To(vm => vm.Tip);
set.Bind(SubTotalTextField).To(vm => vm.SubTotal);
set.Bind(GenerositySlider).To(vm => vm.Generosity);
set.Apply();
View.AddGestureRecognizer(new UITapGestureRecognizer(() =>
{
this.SubTotalTextField.ResignFirstResponder();
}));
}
}
Generated code behind
namespace TipCalc.iOS
{
[Register ("TipView")]
partial class TipView
{
[Outlet]
[GeneratedCode ("iOS Designer", "1.0")]
UISlider GenerositySlider { get; set; }
[Outlet]
[GeneratedCode ("iOS Designer", "1.0")]
UITextField SubTotalTextField { get; set; }
[Outlet]
[GeneratedCode ("iOS Designer", "1.0")]
UILabel TipLabel { get; set; }
void ReleaseDesignerOutlets ()
{
if (GenerositySlider != null) {
GenerositySlider.Dispose ();
GenerositySlider = null;
}
if (SubTotalTextField != null) {
SubTotalTextField.Dispose ();
SubTotalTextField = null;
}
if (TipLabel != null) {
TipLabel.Dispose ();
TipLabel = null;
}
}
}
}
What am I missing here?
I didn't set File's Owners class, adding it resolved the problem.
I'm starting with Xamarin.Forms and what I'm trying to do is simply setting a CurrentUrl property on a custom Webview in Xamarin.Forms
In other words: When OnPageFinished method is called, I need to set the CurrentUrl property of MyWebView to the new Url.
Anyone have an idea?
Here's my main Webview:
public class MyWebView: Xamarin.Forms.WebView
{
public static readonly BindableProperty UrlProperty = BindableProperty.Create(
propertyName: "CurrentUrl",
returnType: typeof(string),
declaringType: typeof(MyWebView),
defaultValue: default(string));
public string CurrentUrl
{
get { return (string)GetValue(UrlProperty); }
set { SetValue(UrlProperty, value); }
}
}
And here's my Renderer in Project.Droid:
[assembly: ExportRenderer(typeof(MyWebView), typeof(MyProject.Droid.WebViewRenderer))]
namespace Manateq.Droid
{
public class WebViewRenderer : Xamarin.Forms.Platform.Android.WebViewRenderer
{
public WebViewRenderer(Context context) : base(context)
{
}
protected override void OnElementChanged(Xamarin.Forms.Platform.Android.ElementChangedEventArgs<Xamarin.Forms.WebView> e)
{
base.OnElementChanged(e);
Control.SetWebViewClient(new Callback(Plugin.CurrentActivity.CrossCurrentActivity.Current.Activity));
}
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
MyWebView myWebView = sender as MyWebView;
if (e.PropertyName == "CurrentUrl")
{
}
}
}
public class Callback : WebViewClient
{
Activity _context;
public Callback(Activity _context)
{
this._context = _context;
}
public override bool ShouldOverrideUrlLoading(Android.Webkit.WebView view, string url)
{
//view.LoadUrl(url);
Intent i = new Intent(Intent.ActionView, Uri.Parse(url));
_context.StartActivity(i);
return true;
}
public override void OnPageStarted(Android.Webkit.WebView view, string url, Android.Graphics.Bitmap favicon)
{
base.OnPageStarted(view, url, favicon);
DependencyService.Get<ILoadingIndicator>().Show();
}
public override void OnPageFinished(Android.Webkit.WebView view, string url)
{
base.OnPageFinished(view, url);
//element.CurrentUrl = url;
DependencyService.Get<ILoadingIndicator>().Dismiss();
}
}
}
And here's I'm using the custom web view in xaml:
<customControls:MyWebView VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand" x:Name="webView"/>
You can got the value of CurrentUrl by MyWebView myWebView = e.NewElement as MyWebView; var currentUrl=myWebView.CurrentUrl; in OnElementChanged; Then you can transfer this value to Callback's constructor. In the end, you can set it in the OnPageFinished method by element.CurrentUrl = currenturl; like following code.
[assembly: ExportRenderer(typeof(MyWebView), typeof(WebViewRenderer))]
namespace WebviewDemo.Droid
{
public class WebViewRenderer : Xamarin.Forms.Platform.Android.WebViewRenderer
{
public WebViewRenderer(Context context) : base(context)
{
}
protected override void OnElementChanged(Xamarin.Forms.Platform.Android.ElementChangedEventArgs<Xamarin.Forms.WebView> e)
{
base.OnElementChanged(e);
MyWebView myWebView = e.NewElement as MyWebView;
var currentUrl=myWebView.CurrentUrl;
Control.SetWebViewClient(new Callback(Plugin.CurrentActivity.CrossCurrentActivity.Current.Activity, currentUrl));
}
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
MyWebView myWebView = sender as MyWebView;
if (e.PropertyName == "CurrentUrl")
{
}
}
}
public class Callback : WebViewClient
{
Activity _context;
string currenturl;
public Callback(Activity _context,string currenturl)
{
this._context = _context;
this.currenturl = currenturl;
}
public override bool ShouldOverrideUrlLoading(Android.Webkit.WebView view, string url)
{
//view.LoadUrl(url);
Intent i = new Intent(Intent.ActionView, Uri.Parse(url));
_context.StartActivity(i);
return true;
}
public override void OnPageStarted(Android.Webkit.WebView view, string url, Android.Graphics.Bitmap favicon)
{
base.OnPageStarted(view, url, favicon);
DependencyService.Get<ILoadingIndicator>().Show();
}
public override void OnPageFinished(Android.Webkit.WebView view, string url)
{
base.OnPageFinished(view, url);
element.CurrentUrl = currenturl;
DependencyService.Get<ILoadingIndicator>().Dismiss();
}
}
}
Do you want to achieve the result like this GIF?
If so, you can load the current url in the OnPageFinished method.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Webkit;
using Android.Widget;
using WebviewDemo;
using WebviewDemo.Droid;
using Xamarin.Forms;
[assembly: ExportRenderer(typeof(MyWebView), typeof(WebViewRenderer))]
namespace WebviewDemo.Droid
{
public class WebViewRenderer : Xamarin.Forms.Platform.Android.WebViewRenderer
{
public WebViewRenderer(Context context) : base(context)
{
}
protected override void OnElementChanged(Xamarin.Forms.Platform.Android.ElementChangedEventArgs<Xamarin.Forms.WebView> e)
{
base.OnElementChanged(e);
MyWebView myWebView = e.NewElement as MyWebView;
var currentUrl=myWebView.CurrentUrl;
Control.SetWebViewClient(new Callback(Plugin.CurrentActivity.CrossCurrentActivity.Current.Activity, currentUrl));
}
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
MyWebView myWebView = sender as MyWebView;
if (e.PropertyName == "CurrentUrl")
{
}
}
}
public class Callback : WebViewClient
{
Activity _context;
string currenturl;
public Callback(Activity _context,string currenturl)
{
this._context = _context;
this.currenturl = currenturl;
}
public override bool ShouldOverrideUrlLoading(Android.Webkit.WebView view, string url)
{
//if (!loadingFinished)
//{
// redirect = true;
//}
//loadingFinished = false;
//view.LoadUrl(currenturl);
//Console.WriteLine("Loading web view...");
return true;
}
public override void OnPageStarted(Android.Webkit.WebView view, string url, Android.Graphics.Bitmap favicon)
{
base.OnPageStarted(view, url, favicon);
}
public override void OnPageFinished(Android.Webkit.WebView view, string url)
{
if (url.Equals("https://www.google.com/"))
{
view.LoadUrl(currenturl);
}
}
//public override bool ShouldOverrideUrlLoading(Android.Webkit.WebView view, string url)
//{
// //view.LoadUrl(url);
// // Intent i = new Intent(Intent.ActionView, Uri.Parse(url));
// // _context.StartActivity(i);
// view.LoadUrl(url);
// isRedirected = true;
// return true;
//}
//public override void OnPageStarted(Android.Webkit.WebView view, string url, Android.Graphics.Bitmap favicon)
//{
// base.OnPageStarted(view, url, favicon);
// if (!isRedirected)
// {
// //Do something you want when starts loading
// }
// isRedirected = false;
// // DependencyService.Get<ILoadingIndicator>().Show();
//}
//public override void OnPageFinished(Android.Webkit.WebView view, string url)
//{
// base.OnPageFinished(view, url);
// if (!isRedirected)
// {
// //Do something you want when finished loading
// }
// // element.CurrentUrl = currenturl;
// // DependencyService.Get<ILoadingIndicator>().Dismiss();
//}
}
}
In the xaml. You can bind the value for CurrentUrl, Or just set it directly.
<customControls:MyWebView VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand" x:Name="webView"/>
Xaml background code.
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
webView.Source = "https://www.google.com";
webView.CurrentUrl = "https://www.baidu.com";
}
}
The answer provided by Leon is good. But I found an easier way to do it. Here's what I've done.
In the Callback class that extends WebviewClient I've edited OnPageStarted and OnPageFinished to be as following:
public override void OnPageStarted(Android.Webkit.WebView view, string url, Android.Graphics.Bitmap favicon)
{
DependencyService.Get<ILoadingIndicator>().Show();
base.OnPageStarted(view, url, favicon);
var args = new WebNavigatingEventArgs(WebNavigationEvent.NewPage, new UrlWebViewSource { Url = url }, url);
_renderer.ElementController.SendNavigating(args);
}
public override void OnPageFinished(Android.Webkit.WebView view, string url)
{
DependencyService.Get<ILoadingIndicator>().Dismiss();
base.OnPageFinished(view, url);
var source = new UrlWebViewSource { Url = url };
var args = new WebNavigatedEventArgs(WebNavigationEvent.NewPage, source, url, WebNavigationResult.Success);
_renderer.ElementController.SendNavigated(args);
}
As for _rendered its: ElementController => Element; and it exist in the WebViewRenderer class.
When adding these line of codes, the Navigated event is being hit normally. So when that happens we can simply use the url parameter that exist in Navigated event.
i am trying to set MainPage whenever logout button taps but i am getting below mentioned exception.
Logout Function:
private void Logout()
{
//Settings.Current.Remove(Constants.PREF_IS_LOGGED_IN);
//Settings.Current.Remove(Constants.PREF_AUTH_TOKEN);
MainPage = new NavigationPage(new LoginPage());
}
LoginPageViewModel:
using Prism.Mvvm;
using Prism.Navigation;
using SalesApp.Controllers.RestController;
using System;
using System.Windows.Input;
using Xamarin.Forms;
using Acr.Settings;
using Plugin.Connectivity;
using SalesApp.Utils;
using SalesApp.Views;
using SalesApp.Views.SideMenu;
using Acr.UserDialogs;
using SalesApp.Interfaces;
namespace SalesApp.ViewModels
{
public class LoginPageViewModel : BindableBase, INavigationAware
{
private String _email = Constants.Username; // dummy value
private String _password = Constants.Password; // dummy value
private Boolean _isShowPassword = true;
private Boolean _isShowPasswordIcon = false;
private Boolean _isRememberMe = false;
ICommand _tapCommandShowPassword;
ICommand _tapCommandNavigateForgotPassword;
ICommand _login;
INavigationService _navigationService;
public DataManager DataManager { get; private set; }
public LoginPageViewModel(INavigationService navigationService)
{
_tapCommandShowPassword = new Command(ShowHidePassword);
_tapCommandNavigateForgotPassword = new Command(NavigateToForgotPassword);
_login = new Command(LoginApiCalls);
_navigationService = navigationService;
}
public String Email
{
get
{
return _email;
}
set
{
_email = value;
}
}
public String Password
{
get
{
return _password;
}
set
{
_password = value;
if (_password.Length > 0)
IsShowPasswordIcon = true;
else
{
IsShowPasswordIcon = false;
IsShowPassword = true;
}
}
}
public bool IsShowPassword
{
get
{
return _isShowPassword;
}
set
{
_isShowPassword = value;
RaisePropertyChanged("IsShowPassword");
}
}
public bool IsRememberMe
{
get
{
return _isRememberMe;
}
set
{
_isRememberMe = value;
RaisePropertyChanged("IsRememberMe");
}
}
public bool IsShowPasswordIcon
{
get
{
return _isShowPasswordIcon;
}
set
{
_isShowPasswordIcon = value;
RaisePropertyChanged("IsShowPasswordIcon");
}
}
public ICommand TapCommandShowPassword
{
get { return _tapCommandShowPassword; }
}
public ICommand TapCommandNavigateForgotPassword
{
get { return _tapCommandNavigateForgotPassword; }
}
public ICommand Login
{
get { return _login; }
}
public void OnNavigatedFrom(NavigationParameters parameters)
{
}
public void OnNavigatedTo(NavigationParameters parameters)
{
}
public void OnNavigatingTo(NavigationParameters parameters)
{
}
void ShowHidePassword()
{
IsShowPassword = !IsShowPassword;
if (IsShowPassword)
IsShowPassword = true;
else
IsShowPassword = false;
}
void NavigateToForgotPassword()
{
_navigationService.NavigateAsync("ForgotPasswordPage");
}
async void LoginApiCalls(object s)
{
if (CrossConnectivity.Current.IsConnected)
{
try
{
UserDialogs.Instance.ShowLoading(ResX.AppResources.Loading_mesg, MaskType.Black);
if (_tapCommandNavigateForgotPassword != null)
{
DataManager = new DataManager(new RestService());
var resp = await DataManager.GetAuthToken(_password);
var isSuccess = false;
if (resp != null)
isSuccess = resp.IsSuccess;
if (isSuccess)
resp = await DataManager.GetUerAuth(_email, resp.Data);
if (resp.IsSuccess)
{
//store flag in shared pref
if (IsRememberMe)
{
Settings.Current.Set(Constants.PREF_IS_LOGGED_IN, true);
}
Settings.Current.Set(Constants.PREF_SALES_AGENT_ID, resp.SalesAgentId);
UserDialogs.Instance.HideLoading();
App.Current.MainPage = new NavigationPage(new HomePage());
//_navigationService.NavigateAsync("/HomePage");
}
else
{
await App.Current.MainPage.DisplayAlert(ResX.AppResources.Error_txt,
ResX.AppResources.UserName_Password_Error,ResX.AppResources.OK_txt);
UserDialogs.Instance.HideLoading();
}
}
}
catch (Exception e)
{
await App.Current.MainPage.DisplayAlert(ResX.AppResources.Error_txt,
ResX.AppResources.Generic_Error_txt, ResX.AppResources.OK_txt);
UserDialogs.Instance.HideLoading();
}
}
else
{
await App.Current.MainPage.DisplayAlert(ResX.AppResources.Net_Error_txt,
ResX.AppResources.No_Network_Error_txt, ResX.AppResources.OK_txt);
}
}
public void OnPhoneTapped(String phone)
{
var dialer = DependencyService.Get<IDialer>();
if (dialer != null)
{
dialer.Dial(phone);
}
}
public void OnRouteTap(string sourceLat, string sourceLon, string destinationLat, string destinationLon)
{
var route = DependencyService.Get<IDirection>();
if (route != null)
{
route.DrawDirection(sourceLat, sourceLon, destinationLat, destinationLon);
}
}
}
}
UNHANDLED EXCEPTION:
08-29 15:59:43.868 I/MonoDroid( 3268): System.NullReferenceException: Object reference not set to an instance of an object.
08-29 15:59:43.868 I/MonoDroid( 3268): at Xamarin.Forms.Platform.Android.AppCompat.NavigationPageRenderer.OnLayout (System.Boolean changed, System.Int32 l, System.Int32 t, System.Int32 r, System.Int32 b) [0x00007] in C:\BuildAgent3\work\ca3766cfc22354a1\Xamarin.Forms.Platform.Android\AppCompat\NavigationPageRenderer.cs:292
08-29 15:59:43.868 I/MonoDroid( 3268): at Xamarin.Forms.Platform.Android.FormsViewGroup.n_OnLayout_ZIIII (System.IntPtr jnienv, System.IntPtr native__this, System.Boolean p0, System.Int32 p1, System.Int32 p2, System.Int32 p3, System.Int32 p4) [0x00008] in C:\BuildAgent3\work\ca3766cfc22354a1\Xamarin.Forms.Platform.Android.FormsViewGroup\obj\Release\generated\src\Xamarin.Forms.Platform.Android.FormsViewGroup.cs:198
08-29 15:59:43.868 I/MonoDroid( 3268): at (wrapper dynamic-method) System.Object:bbd5dc5a-77cf-45bd-9d16-717bbe7e4232 (intptr,intptr,bool,int,int,int,int)
I'm using xamarin.ios with XamarinSidebar, but I have a problem with the MvxTableViewSource in EditActionsForRow event, if I don't use the presentation using XamarinSidebar, for example presenting in a modal, it detects the event perfectly, and shows me the content, but if I show it with the XamarinSidebar doesn't detect the horizontal swipe.
CustomViewController:
[MvxSidebarPresentation(MvxPanelEnum.Center, MvxPanelHintType.ResetRoot, true, MvxSplitViewBehaviour.Detail)]
public partial class CustomViewController : MvxViewController<CustomViewModel>
{
public CustomViewController() : base("CustomViewController", null)
{
}
public override void ViewDidLoad()
{
base.ViewDidLoad();
var set = this.CreateBindingSet<CustomViewController, CustomViewModel>();
var source = new TableViewSource(TableView);
set.Bind(source).For(s => s.ItemsSource).To(vm => vm.CustomList);
TableView.Source = source;
set.Apply();
}
}
and TableViewSource:
public class TableViewSource : MvxTableViewSource
{
public List<CustomItems> TableItems { get { return ItemsSource as List<CustomItems>; } }
string CellIdentifier = "CustomCell";
public ChatContactTableViewSource(UITableView tableView) : base(tableView)
{
}
public override nint RowsInSection(UITableView tableview, nint section)
{
return TableItems.Count;
}
public override void RowSelected(UITableView tableView, NSIndexPath indexPath)
{
Contact item = TableItems[indexPath.Row];
Console.WriteLine("Item selected: " + item.ContactName);
}
public override UITableViewRowAction[] EditActionsForRow(UITableView tableView, NSIndexPath indexPath)
{
List<UITableViewRowAction> items = new List<UITableViewRowAction>();
//Button
var Button = UITableViewRowAction.Create(UITableViewRowActionStyle.Normal, "Delete",
delegate
{
Console.WriteLine("DeleteButton");
});
Button.BackgroundColor = UIColor.Red;
items.Add(Button);
//I have more than one button here
return items.ToArray();
}
public override bool CanEditRow(UITableView tableView, NSIndexPath indexPath)
{
return true;
}
public override void CommitEditingStyle(UITableView tableView, UITableViewCellEditingStyle editingStyle, NSIndexPath indexPath)
{
Console.WriteLine("EDITING STYLE");
if (editingStyle == UITableViewCellEditingStyle.Delete)
{
TableItems.RemoveAt(indexPath.Row);
}
}
protected override UITableViewCell GetOrCreateCellFor(UITableView tableView, NSIndexPath indexPath, object item)
{
var cell = tableView.DequeueReusableCell(CellIdentifier) as CustomCell;
CustomItems ItemCustom = TableItems[indexPath.Row];
//---- if there are no cells to reuse, create a new one
if (cell == null)
{
cell = CustomCell.Create();
}
cell.LabelText.Text = ItemCustom.Name;
return cell;
}
}
Solved implementing:
public class BaseMenuViewController<TViewModel> : BaseMenuView<TViewModel>, IMvxSidebarMenu where TViewModel : class, IMvxViewModel
{
public virtual UIImage MenuButtonImage => UIImage.FromBundle("threelines");
public virtual bool AnimateMenu => true;
public virtual float DarkOverlayAlpha => 0.7f;
public virtual bool HasDarkOverlay => true;
public virtual bool HasShadowing => false;
public virtual bool DisablePanGesture => true; //Here the solution
public virtual bool ReopenOnRotate => true;
private int MaxMenuWidth = 304;
private int MinSpaceRightOfTheMenu = 55;
public int MenuWidth => UserInterfaceIdiomIsPhone ?
int.Parse(UIScreen.MainScreen.Bounds.Width.ToString()) - MinSpaceRightOfTheMenu : MaxMenuWidth;
private bool UserInterfaceIdiomIsPhone
{
get { return UIDevice.CurrentDevice.UserInterfaceIdiom == UIUserInterfaceIdiom.Phone; }
}
public virtual void MenuWillOpen()
{
}
public virtual void MenuDidOpen()
{
}
public virtual void MenuWillClose()
{
}
public virtual void MenuDidClose()
{
}
}
Is iOS Picker available in the Xamarin.iOS? I have searched throughly but there is neither example nor information has been founded; however, it is available in Xamarin.Form.
A real quickie example of a UIPickerView: (iOS SDK)
Add a UIPickerView to your xib or Storyboard called slotMachineView:
using System;
using UIKit;
namespace Slots
{
public partial class ViewController : UIViewController
{
public ViewController (IntPtr handle) : base (handle)
{
}
public override void ViewDidLoad ()
{
base.ViewDidLoad ();
slotMachineView.Model = new StackOverflowModel (selectedLbl);
}
public override void DidReceiveMemoryWarning ()
{
base.DidReceiveMemoryWarning ();
}
}
public class StackOverflowModel : UIPickerViewModel
{
static string[] names = new string [] {
"pscorlib.dll",
"pscorlib_aot.dll",
"Mono.PlayScript.dll",
"PlayScript.Dynamic.dll",
"PlayScript.Dynamic_aot.dll",
"PlayScript.Optimization.dll",
"playshell.exe",
"psc.exe"
};
UILabel lbl;
public StackOverflowModel (UILabel lbl)
{
this.lbl = lbl;
}
public override nint GetComponentCount (UIPickerView v)
{
return 3;
}
public override nint GetRowsInComponent (UIPickerView pickerView, nint component)
{
return names.Length;
}
public override string GetTitle (UIPickerView picker, nint row, nint component)
{
switch (component) {
case 0:
return names [row];
case 1:
return row.ToString ();
case 2:
return new string ((char)('A' + row), 1);
default:
throw new NotImplementedException ();
}
}
public override void Selected (UIPickerView picker, nint row, nint component)
{
lbl.Text = String.Format ("{0} : {1} : {2}",
names [picker.SelectedRowInComponent (0)],
picker.SelectedRowInComponent (1),
picker.SelectedRowInComponent (2));
}
public override nfloat GetComponentWidth (UIPickerView picker, nint component)
{
if (component == 0)
return 220f;
else
return 30f;
}
}
}
Yes it is. The native iOS control is called UIPickerView
public class GenderPicker : UIViewController
{
public TestVC() { }
UITextField SelectGenderTextField = new UITextField();
UIPickerView GenderPicker = new UIPickerView();
public override void ViewDidLoad()
{
base.ViewDidLoad();
AddTextField();
GenderTextField();
Constraint();
}
}
Textfield To Show The Selected Data
private void AddTextField()
{
SelectGenderTextField.Placeholder = "Select Gender";
SelectGenderTextField.Layer.BorderWidth = 1;
SelectGenderTextField.Layer.BorderColor = UIColor.Black.CGColor;
SelectGenderTextField.Layer.MasksToBounds = true;
SelectGenderTextField.Layer.SublayerTransform = CATransform3D.MakeTranslation(5, 0, 0); //to Create a Space At The beginning of the text field
SelectGenderTextField.InputView = GenderPicker; //To Start The UIPickerView from The bottom.
}
Gender Picker
private void GenderTextField()
{
var genderList = new List<string> {
"Male","Female"
};
var picker = new GenderPickerModel(genderList);
GenderPicker.Model = picker;
picker.ValueChanged += (sender, e) => {
SelectGenderTextField.Text = picker.SelectedGenderByUser; //Update The Selected Value In the TextField
View.EndEditing(true);// To Dismiss the Picker View Once The User Select The Value
};
}
Constraints
// Used Cirrious.FluentLayouts.Touch For Constraints
private void Constraint()
{
View.AddSubviews(SelectGenderTextField);
View.SubviewsDoNotTranslateAutoresizingMaskIntoConstraints();
View.AddConstraints(
SelectGenderTextField.WithRelativeWidth(View, 0.80f),
SelectGenderTextField.WithRelativeHeight(View, 0.05f),
SelectGenderTextField.WithSameCenterX(View),
SelectGenderTextField.WithSameCenterY(View)
);
}
Picker Model Class
class GenderPickerModel : UIPickerViewModel
{
public EventHandler ValueChanged;
public string SelectedGenderByUser;
private List<string> genderList;
public GenderPickerModel(List<string> genderList)
{
this.genderList = genderList;
}
public override nint GetRowsInComponent(UIPickerView pickerView, nint component)
{
return genderList.Count;
}
public override nint GetComponentCount(UIPickerView pickerView)
{
return 1;
}
public override string GetTitle(UIPickerView pickerView, nint row, nint component)
{
return genderList[(int)row];
}
public override void Selected(UIPickerView pickerView, nint row, nint component)
{
var gender = genderList[(int)row];
SelectedGenderByUser = gender;
ValueChanged(null,null);
}
}