Line Separator in iOS ImageCell not always showing - xamarin.forms

I have an ImageCell which binds to an iOS Asset. When it renders, the line separator doesn't always show.
Seems to be a drawing issue because if I scroll up and down some of the rows get the separator line redrawn as can be seen in the screenshot.
Any ideas?
I've coded up my UI like this:
public class Contact{
public Contact(string name, string email) {
Name = name;
Email = email;
Initial = "Avatar";
}
public string Name { get; }
public string Email { get; }
public string Initial { get; }
}
public class ContactCell: ImageCell {
public ContactCell() {
this.SetBinding(TextProperty, "Name");
this.SetBinding(DetailProperty, "Email");
this.SetBinding(ImageSourceProperty, "Initial");
}
}
public class ContactListPage : ContentPage {
public ContactListPage() {
Title = "List";
Content = new ListView {
RowHeight = 60,
ItemTemplate = new DataTemplate(typeof(ContactCell)),
Margin = new Thickness(10, 0, 0, 0),
ItemsSource = new List<Contact> {
new Contact("Isa Tusa", "isa.tusa#me.com"),
.
.
};
}
}

I think that's the behavior when using the default viewcell templates like Image cell, etc. I would suggest you go for custom implementation like using grid for the item template. We have more control over it and can be easily modified to any required design. I've modified your code and pasted below. Check if it is useful for you...
public ContactListPage()
{
Title = "List";
Content = new ListView
{
RowHeight = 71,
SeparatorVisibility = SeparatorVisibility.None,
// ItemTemplate = new DataTemplate(typeof(ContactCell)),
ItemTemplate = new DataTemplate(() =>
{
return new ViewCell { View = ContactCellGrid() };
}),
ItemsSource = new List<Contact> {
new Contact("Isa Tusa", "isa.tusa#me.com"),
new Contact("Racquel Ricciardi", "racquel.ricciardi#me.com"),
new Contact("Teresita Mccubbin", "teresita.mccubbin#me.com"),
new Contact("Rhoda Hassinger", "rhoda.hassinger#me.com"),
new Contact("Carson Cupps", "carson.cupps#me.com"),
new Contact("Devora Nantz", "devora.nantz#me.com"),
new Contact("Tyisha Primus", "tyisha.primus#me.com"),
new Contact("Muriel Lewellyn", "muriel.lewellyn#me.com"),
new Contact("Hunter Giraud", "hunter.giraud#me.com"),
}
};
}
private Grid ContactCellGrid()
{
var grid = new Grid();
grid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(5, GridUnitType.Absolute) });
grid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(2, GridUnitType.Star) });
grid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(1, GridUnitType.Star) });
grid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(5, GridUnitType.Absolute) });
grid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(1, GridUnitType.Absolute) });
grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(5, GridUnitType.Absolute) });
grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Auto) });
grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) });
grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(5, GridUnitType.Absolute) });
var nameLabel = new Label { FontAttributes = FontAttributes.Bold, VerticalTextAlignment = TextAlignment.Center };
var ageLabel = new Label { VerticalTextAlignment = TextAlignment.Start }; ;
var locationLabel = new Image { HorizontalOptions = LayoutOptions.Center };
var boxView = new BoxView { Color = Color.Gray, HeightRequest = 1 };
nameLabel.SetBinding(Label.TextProperty, "Name");
ageLabel.SetBinding(Label.TextProperty, "Email");
locationLabel.SetBinding(Image.SourceProperty, "Initial");
grid.Children.Add(nameLabel, 2, 1);
grid.Children.Add(ageLabel, 2, 2);
grid.Children.Add(locationLabel, 1, 1);
Grid.SetRowSpan(locationLabel, 2);
grid.Children.Add(boxView, 1, 4);
Grid.SetColumnSpan(boxView, 2);
return grid;
}
below is the screenshot of it..

Related

How do I write this in code behind: <Button Command="{prism:NavigateTo 'path/to/navigate'}" />

I have a common Page class which the rest of my app pages inherit from.
I'm writing the buttons in code but I'd like to replicate the way prims does it as it more predictable/readable for a beginner. e.g.
This is current method. How do I change the Command property below to do what the button code does i.e
var im_Logo = new ImageButton
{
Margin = new Thickness(0),
Padding = new Thickness(0),
Source = "blalogo",
BackgroundColor = Color.Transparent,
HorizontalOptions = LayoutOptions.Start,
Command = new Command(GoHome)// This works but other pages are not so easy.
};
void GoHome(object obj)
{
Navigation.PopToRootAsync();
}
Plus I'm just curious how you write Command="{prism:NavigateTo 'path/to/navigate'}" in code.
If I could attach a Viewmodel to this 'code' page, it would also solve the problem as the Viewmodels I have have all the Prism stuff built in.(Supplied by infragistics)
Edit Update: I'm adding full class of page I'm creating in code. I thought writing a common class for multiple pages to use would be simple but I'm stumped.
My error on these fails are when clicking on the Search button which I'll concentrate on for now is.
11-06 16:28:54.988 D/Mono (30123): Loading reference 0 of System.Drawing.Common.dll asmctx DEFAULT, looking for mscorlib, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e
11-06 16:28:54.988 D/Mono (30123): Assembly Ref addref System.Drawing.Common[0xc7e18f60] -> mscorlib[0xe5c08580]: 70
Loaded assembly: System.Drawing.Common.dll [External]
11-06 16:28:55.040 D/EGL_emulation(30123): eglMakeCurrent: 0xc9270ce0: ver 2 0 (tinfo 0xc8d25b10)
**System.NullReferenceException:** 'Object reference not set to an instance of an object.'
using iBasisAppV1.ViewModels;
using Prism.Navigation;
using Prism.Navigation.Xaml;
using Syncfusion.XForms.BadgeView;
using Syncfusion.XForms.Buttons;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using Xamarin.Forms;
namespace iBasisAppV1.Views.Templates
{
public class CommonToolbarPage : ContentPage
{
public CommonToolbarPage()
{
NavigationPage.SetHasBackButton(this, false);
ShowDefaultTitle();
//this.BindingContext= new CommonToolbarPageViewModel(navigationService);
}
private void ShowDefaultTitle()
{
var im_Logo = new ImageButton
{
Margin = new Thickness(0),
Padding = new Thickness(0),
Source = "boilerparts",
BackgroundColor = Color.Transparent,
HorizontalOptions = LayoutOptions.Start,
Command = new NavigateToExtension { Name = $"/Home" }
//Command = new Command(GoHome)
};
var b_search = new SfButton
{
HorizontalTextAlignment = TextAlignment.End,
HorizontalOptions = LayoutOptions.FillAndExpand,
FontSize = 26,
TextColor = Color.White,
BackgroundColor = Color.Transparent,
Margin = new Thickness(0),
Padding = new Thickness(0),
FontFamily = "UIFontIcons",
Text = (String)Application.Current.Resources["Search"],
//Command = new NavigateToExtension { Name = "../Search" } //Not Work
//Command = new NavigateToExtension { Name = "Search" } //Not Work
//Command = new NavigateToExtension { Name = $"{nameof(Search)}" } //Not Work
// Command = new NavigateToExtension { Name = $"../{nameof(Search)}" } //Not Work
//Command = new Command(ShowSearch)// Works
};
var boxView = new BoxView
{
HorizontalOptions = LayoutOptions.FillAndExpand,
BackgroundColor = Color.Red,
Margin = new Thickness(0,0,0,0),
};
SfButton sfButton = new SfButton
{
CornerRadius = 4,
HorizontalOptions = LayoutOptions.End,
VerticalOptions= LayoutOptions.Center,
Style = (Style)Application.Current.Resources["IconButtonStyle"],
Text = (String)Application.Current.Resources["Cart"],
FontFamily = "UIFontIcons",
TextColor = Color.White,
// Command = new Command(GoCart)
};
var imSfBadgeView = new SfBadgeView
{
BadgeText = "4",
Margin = new Thickness(0, 0, 10, 0),
Padding = new Thickness(0),
WidthRequest = 40,
Content = sfButton,
HorizontalOptions = LayoutOptions.EndAndExpand,
VerticalOptions = LayoutOptions.Center,
BackgroundColor = Color.Transparent,
BadgeSettings = new BadgeSetting
{
BackgroundColor= (Color)Application.Current.Resources["PrimaryColor"],
BadgeType = BadgeType.None,
FontSize = 10,
Stroke = (Color)Application.Current.Resources["Gray-White"],
StrokeWidth = 1,
Offset = new Point(-10, 10)
}
};
var layout = new StackLayout
{
Orientation = StackOrientation.Horizontal,
HorizontalOptions=LayoutOptions.FillAndExpand,
BackgroundColor = (Color)Application.Current.Resources["HeaderColor"]
};
var Endlayout = new StackLayout
{
Orientation = StackOrientation.Horizontal,
HorizontalOptions = LayoutOptions.EndAndExpand,
};
if (this.GetType().Name.ToLower() != "search")
Endlayout.Children.Add(b_search);
Endlayout.Children.Add(imSfBadgeView);
layout.Children.Add(im_Logo);
layout.Children.Add(Endlayout);
NavigationPage.SetTitleView(this, layout);
}
private void ShowSearch(object obj)
{
Navigation.PushAsync(new Search());
}
private void cancel(object obj)
{
ShowDefaultTitle();
}
void GoCart(object obj)
{
Navigation.PushAsync(new Home());
}
void GoHome(object obj)
{
Navigation.PopToRootAsync();
// Navigation.PushAsync(new NavigationPage(new Home()));
//NavigationService.NavigateAsync("/MainPage/NavigationPage/ViewA");
}
}
}
If you want the exact match, here we go...
var im_Logo = new ImageButton
{
Margin = new Thickness(0),
Padding = new Thickness(0),
Source = "blalogo",
BackgroundColor = Color.Transparent,
HorizontalOptions = LayoutOptions.Start,
Command = new NavigateToExtension {Name = "/path/to/navigate"}
};
void GoHome(object obj)
{
Navigation.PopToRootAsync();
}
And you will need the following import:
using Prism.Navigation.Xaml;
Long story short, Prism use this class to create a command which can use INavigationService accessing the container in Application.Current. If you check the source code in Github you will see how all the magic happens.
https://github.com/PrismLibrary/Prism/blob/master/src/Forms/Prism.Forms/Navigation/Xaml/NavigateToExtension.cs
If you want to do it in ViewModel, then you need a INavigationService.
Then you can use it like:
await NavigationService.NavigateAsync(nameof(YourView));
So like
Command = new Command(async () => await NavigationService.NavigateAsync("YourView"));
NavigateAsync uses URI parameters, you can use ../ and ../YourView.
I like the nameof() method eg. await NavigationService.NavigateAsync($"../{nameof(YourView)}"));

How can i press a button in headerbar and do things in window in vala

How to make a button in headerbar and do things in window i've tried:
public class headerbar : Gtk.HeaderBar {
construct {
title = "Quiz";
subtitle = "You can solve this!";
show_close_button = true;
Gtk.Button button = new Gtk.Button.with_label ("Quit");
button.get_style_context ().add_class ("suggested-action");
button.set_valign (Gtk.Align.CENTER);
button.clicked.connect (() => {
var label = new Gtk.Label ("Hi");
main.add (label);
label.show ();
});
pack_start (button);
}
}
I got a sample as follow, hope it could help you:
public class AppTitleBar : Gtk.HeaderBar {
private Gtk.Button m_new_tab_button;
private Gtk.Box m_app_title_gui_box;
private Gtk.MenuButton m_main_menu_button;
public weak Workbench workbench { get; construct; }
public AppTitleBar (Workbench workbench) {
Object ( workbench: workbench );
}
construct {
set_show_close_button (true);
this.build_title_bar_layout();
}
public void add_new_tab(Widget title_widget)
{
m_app_title_gui_box.pack_start(title_widget);
title_widget.focus.connect(() => {
this.update_tab_inactive_all();
return true;
});
}
public void update_tab_inactive_all()
{
m_app_title_gui_box.foreach ((widget) => {
widget.set_opacity(0.3);
});
}
public void remove_tab_widget(Widget tab_bar)
{
m_app_title_gui_box.remove(tab_bar);
}
private void build_title_bar_layout()
{
m_main_menu_button = new Gtk.MenuButton ();
var menu_image = new Gtk.Image.from_icon_name ("open-menu-symbolic", Gtk.IconSize.BUTTON);
m_main_menu_button.set_image (menu_image);
m_main_menu_button.tooltip_text = ("Main Menu");
// create title bar box
m_app_title_gui_box = new Box(Orientation.HORIZONTAL, 2);
// create add new tab button
m_new_tab_button = new Gtk.Button.from_icon_name("list-add", Gtk.IconSize.BUTTON);
m_new_tab_button.get_style_context ().add_class ("back-button");
m_new_tab_button.valign = Gtk.Align.CENTER;
m_new_tab_button.always_show_image = true;
m_new_tab_button.can_focus = false;
m_new_tab_button.action_name = WorkbenchActions.ACTION_PREFIX + WorkbenchActions.ACTION_TAB_NEW;
m_new_tab_button.has_tooltip = true;
m_new_tab_button.tooltip_text = "Open a new connection (Ctrl+N)";
this.pack_end(m_main_menu_button);
this.pack_start(m_app_title_gui_box);
this.pack_start(m_new_tab_button);
}
}

Convert Xamarin.Forms.Binding into System.string

How would you convert a binding object into a string? I'm trying to bind text to a property using a bindable property, but I'm getting an error that says
cannot convert from Xamarin.Forms.Binding to System.string.
I assumed the BindableProperty returnType typeof(string) would have caught this.
Here's my front-end code (App.rug.Length is a string):
<local:MenuItem ItemTitle="Length" ItemImage="icons/blue/next" ItemSubText="{Binding App.rug.Length}" PageToo="{Binding lengthpage}"/>
Here's my back-end code:
public class MenuItem : ContentView
{
private string itemsubtext { get; set; }
public static BindableProperty SubTextProperty = BindableProperty.Create("ItemSubText", typeof(string), typeof(MenuItem), null, BindingMode.TwoWay);
public MenuItem()
{
var menuTapped = new TapGestureRecognizer();
menuTapped.Tapped += PushPage;
StackLayout Main = new StackLayout
{
Children = {
new SectionLine(),
new StackLayout {
Padding = new Thickness(10),
Orientation = StackOrientation.Horizontal,
HorizontalOptions = LayoutOptions.Fill,
Children = {
new Label {
Margin = new Thickness(10, 2, 10, 0),
FontSize = 14,
TextColor = Color.FromHex("#c1c1c1"),
HorizontalOptions = LayoutOptions.End,
Text = this.ItemSubText
}
}
}
}
};
Main.GestureRecognizers.Add(menuTapped);
Content = Main;
}
public string ItemSubText
{
get { return itemsubtext; }
set { itemsubtext = value; }
}
}
Here is the error:
Xamarin.Forms.Xaml.XamlParseException: Position 26:68. Cannot assign
property "ItemSubText": type mismatch between "Xamarin.Forms.Binding"
and "System.String"
the issue you are getting is probably caused by the binding you have used for the subtext property.
Your variable App.rug.Length is a static variable so therefore you will need to specify it in the binding like below
<local:MenuItem ItemTitle="Length" ItemImage="icons/blue/next" ItemSubText="{Binding Source={x:Static local:App.rug.Length}}" PageToo="{Binding lengthpage}"/>
where
xmlns:local="clr-namespace:{App Namespace here}"
Also fix up your property Accessors for ItemSubText property
public string ItemSubText
{
get { return (string)GetValue (SubTextProperty); }
set { SetValue (SubTextProperty, value); }
}

Avatar image clickable and display on screen Xamarin.Forms

I want to make my avatar image which is in a circle clickable. After click it has to be displayed on screen like in FB. So how I can implement this in my code?
listView.Header = "";
listView.HeaderTemplate = new DataTemplate(() =>
{
var avatarLayout = new StackLayout()
{
HeightRequest = 350,
};
var grid = new Grid();
grid.HeightRequest = 400;
grid.BackgroundColor = Color.White;
grid.RowDefinitions.Add(new RowDefinition());
grid.RowDefinitions.Add(new RowDefinition());
var bgrImg = new Image();
bgrImg.Aspect = Aspect.Fill;
bgrImg.Source = ImageSource.FromFile("abstract_background.jpg");
var avImg = new CircleImage();
avImg.VerticalOptions = new LayoutOptions(LayoutAlignment.Center, false);
avImg.Source = ImageSource.FromFile("about_background.png");
grid.Children.Add(bgrImg, 0, 0);
grid.Children.Add(avImg);
Grid.SetRowSpan(avImg, 2);
avatarLayout.Children.Add(grid);
Example of my
avatar
You can make an element tappable by using a GestureRecognizer
var tapGestureRecognizer = new TapGestureRecognizer();
tapGestureRecognizer.Tapped += (s, e) => {
// handle the tap
};
image.GestureRecognizers.Add(tapGestureRecognizer);

Xamarin Forms - Xamarin Forms Labs Camera on Page Showing Up

Does anyone have an example in Xamarin.Forms of Xamarin.Forms.Labs' Camera function?
I tried to get it working, but it does not seem to work at all.
Here's my code:
public partial class CameraPictureInfoPage : ContentPage
{
public CameraPictureInfoPage ()
{
Image img = new Image ();
this.Appearing += async (s, e) => {
img.Source = await GetPicture (true);
};
this.Content = new StackLayout {
Orientation = StackOrientation.Vertical,
VerticalOptions = LayoutOptions.Center,
WidthRequest = 250,
Padding = 40, Spacing = 10,
Children = {
img
}
};
}
async Task<ImageSource> GetPicture(bool chooseNotTake){
var mediaPicker = DependencyService.Get<IMediaPicker> ();
ImageSource imgSource = null;
if (mediaPicker != null) {
Task<MediaFile> pick;
if (chooseNotTake) {
pick = mediaPicker.TakePhotoAsync (new CameraMediaStorageOptions {
DefaultCamera = CameraDevice.Rear,
MaxPixelDimension = 1024,
});
} else {
pick = mediaPicker.SelectPhotoAsync (new CameraMediaStorageOptions{ MaxPixelDimension = 1024 });
}
await pick.ContinueWith (t => {
if (!t.IsFaulted && !t.IsCanceled) {
var mediaFile = t.Result;
MemoryStream mstr = new MemoryStream ();
mediaFile.Source.CopyTo (mstr);
imgSource = ImageSource.FromStream (() => mstr);
}
return imgSource;
});
}
return imgSource;
}
}
This works for me:
in iOS project in AppDelegate.cs:
public override bool FinishedLaunching (UIApplication app, NSDictionary options)
{
SetIoc ();
Forms.Init ();
window = new UIWindow (UIScreen.MainScreen.Bounds);
window.RootViewController = App.GetMainPage ().CreateViewController ();
window.MakeKeyAndVisible ();
return true;
}
private void SetIoc ()
{
var resolverContainer = new SimpleContainer ();
resolverContainer.Register<IDevice> (t => AppleDevice.CurrentDevice)
.Register<IDisplay> (t => t.Resolve<IDevice> ().Display)
.Register<IDependencyContainer> (t => resolverContainer);
Resolver.SetResolver (resolverContainer.GetResolver ());
}
In the Forms project:
private async Task<ImageSource> GetPicture(bool chooseNotTake){
var mediaPicker = DependencyService.Get<IMediaPicker> ();
ImageSource imgSource = null;
if (mediaPicker != null) {
Task<MediaFile> pick;
if (!chooseNotTake) {
pick = mediaPicker.TakePhotoAsync (new CameraMediaStorageOptions {
DefaultCamera = CameraDevice.Rear,
MaxPixelDimension = 1024,
});
} else {
pick = mediaPicker.SelectPhotoAsync (new CameraMediaStorageOptions{ MaxPixelDimension = 1024 });
}
await pick.ContinueWith (t => {
if (!t.IsFaulted && !t.IsCanceled) {
var mediaFile = t.Result;
MemoryStream mstr = new MemoryStream();
mediaFile.Source.CopyTo(mstr);
imgSource = ImageSource.FromStream (() => mstr);
}
return imgSource;
}
}
Keep in mind you may need to store the image stream by some other means or it may get garbage-collected prematurely.
To get the picture taker to show up on startup you'll have to avoid async and hook up to Appearing event. In your page's constructor add this:
public class PhotoPage : ContentPage
{
Image img = new Image ();
IMediaPicker picker = null;
Task<MediaFile> task = null;
public PhotoPage ()
{
img.WidthRequest = 60;
img.HeightRequest = 60;
img.BackgroundColor = Color.Silver;
this.Content = new StackLayout {
Orientation = StackOrientation.Vertical,
VerticalOptions = LayoutOptions.Center,
BackgroundColor = Color.Aqua,
WidthRequest = 250,
Padding = 40, Spacing = 10,
Children = {
img,
}
};
this.Appearing += (s, e) => {
picker = DependencyService.Get<IMediaPicker> ();
task = picker.SelectPhotoAsync (new CameraMediaStorageOptions{ MaxPixelDimension = 1024 });
};
Device.StartTimer (TimeSpan.FromMilliseconds (250), () => {
if (task != null) {
if (task.Status == TaskStatus.RanToCompletion) {
Device.BeginInvokeOnMainThread (() => {
img.Source = ImageSource.FromStream (() => task.Result.Source);
});
}
return task.Status != TaskStatus.Canceled
&& task.Status != TaskStatus.Faulted
&& task.Status != TaskStatus.RanToCompletion;
}
return true;
});
}
}

Resources