I'm setting the ItemSource of a listview and trying to create multiple Labels within the listview DataTemplate based on the children of a property of that particular item (the items are gigs, and they have a list of band members and im trying to list the band members).
I'm not sure how to get the properties of the current item that's having it's template created, can someone help?
ListView listView = new ListView {
ItemsSource = viewModel.gigs,
ItemTemplate = new DataTemplate (() => {
var grid = new Grid();
grid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(1, GridUnitType.Star)});
for(int x = 0;x<=viewModel.bandMembers.Count;x++) {
grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star)});
}
var venueName = new Label { Text = "Top Left" };
venueName.SetBinding (Label.TextProperty, "Venue");
grid.Children.Add(venueName, 0, 0);
for(int x = 0;x<THISITEM.bandMembers.Count;x++) {
grid.Children.Add(new Label() {Text="Test"},x,0);
}
return new ViewCell { View = grid };
});
// Build the page.
this.Content = new StackLayout {
Children = {
header,
listView
}
};
You can override OnBindingContextChnaged function in ViewCell and get the ItemData from BindingContext
Related
public DataTemplate CreateQuestionAnswerRadioButtonTemplate(string question, List<string> answers){
DataTemplate template = new DataTemplate(() =>
{
StackLayout parentLayout = new StackLayout()
{
Padding = new Thickness(20, 20, 20, 20),
HeightRequest = 500,
};
ScrollView surveyScrollView = new ScrollView()
{
Orientation = ScrollOrientation.Vertical,
};
StackLayout questionLayout = new StackLayout()
{
Padding = new Thickness(5, 5, 5, 5),
HeightRequest = 500,
};
Label questLabel = new Label();
questLabel.Text = question;
questLabel.TextColor = Color.FromHex("#EF4D80");
questLabel.FontAttributes = FontAttributes.Bold;
questLabel.FontSize = 18;
BindableRadioGroup radioGroup = new BindableRadioGroup(false);
radioGroup.ItemsSource = answers;
questionLayout.Children.Add(questLabel);
questionLayout.Children.Add(radioGroup);
surveyScrollView.Content = questionLayout;
parentLayout.Children.Add(surveyScrollView);
return parentLayout;
});
return template;
}
Adding these Data Templates to a List.
new CarouselView
{
Margin = new Thickness(0, 20, 0, 0),
ItemsSource = dataTemplates,
ItemTemplate = dataTemplates[0],
};
Now when I swipe the Carousel, How do I load dataTemplates[1 or 2 or 3] ??
I have a Next Button in which in am setting the item source of the Carousel View to dataTemplates[1] but the template does not get updated
Pls Suggest the right approach ?
dataTemplates = new List<DataTemplate>();
dataTemplates.Add(CreateQuestionAnswerRadioButtonTemplate(Constants.SurveyQuestion_1, SurveyQuestion_1_Answers));
dataTemplates.Add(CreateQuestionAnswerRadioButtonTemplate(Constants.SurveyQuestion_3, SurveyQuestion_3_Answers));
dataTemplates.Add(CreateQuestionAnswerRadioButtonTemplate(Constants.SurveyQuestion_4, SurveyQuestion_4_Answers));
dataTemplates.Add(CreateQuestionAnswerRadioButtonTemplate(Constants.SurveyQuestion_5, SurveyQuestion_5_Answers));
You need a DataTemplateSelector for your CarouselView.
in your code behind of the page:
new CarouselView
{
Margin = new Thickness(0, 20, 0, 0),
ItemsSource = dataTemplates,
ItemTemplate = new SurveyDataTemplateSelector()
};
SurveyDataTemplateSelector
DataTemplate survey1Template;
DataTemplate survey3Template;
DataTemplate survey4Template;
DataTemplate survey5Template;
public SurveyDataTemplateSelector()
{
survey1Template = CreateQuestionAnswerRadioButtonTemplate(Constants.SurveyQuestion_1, SurveyQuestion_1_Answers);
survey3Template = CreateQuestionAnswerRadioButtonTemplate(Constants.SurveyQuestion_3, SurveyQuestion_3_Answers);
survey4Template = CreateQuestionAnswerRadioButtonTemplate(Constants.SurveyQuestion_4, SurveyQuestion_4_Answers);
survey5Template = CreateQuestionAnswerRadioButtonTemplate(Constants.SurveyQuestion_5, SurveyQuestion_5_Answers);
}
protected override DataTemplate OnSelectTemplate(object item, BindableObject container)
{
// Here you define which DataTemplate is selected, for example:
if (item == null)
{
return null;
}
SurveyAnswers answers = item as SurveyAnswers;
if (answers.question == 1)
{
return survey1Template;
}
else if (answers.question == 3)
{
return survey3Template;
}
else if (answers.question == 4)
{
return survey4Template;
}
else if (answers.question == 5)
{
return survey5Template;
}
return null;
}
Check this link for a good documentation by Xamarin: https://developer.xamarin.com/guides/xamarin-forms/application-fundamentals/templates/data-templates/selector/
I have used Segmented Control in my application. I don't know how to add two content pages to Segment control like a tabbed page. I have attached the sample file. Please give any suggestion Link for Sample Application
Sample Code:
public partial class SamplePage : ContentPage
{
SegmentedControl segControl;
SegmentedControlOption optionOne;
SegmentedControlOption optionTwo;
public SamplePage()
{
segControl = new SegmentedControl();
optionOne = new SegmentedControlOption();
optionTwo = new SegmentedControlOption();
optionOne.Text = "One";
optionTwo.Text = "Two";
segControl.Children.Add(optionOne);
segControl.Children.Add(optionTwo);
var stack = new StackLayout()
{
VerticalOptions = LayoutOptions.StartAndExpand,
HorizontalOptions = LayoutOptions.CenterAndExpand,
Children = { segControl }
};
this.Content = stack;
}
}
ScreenShot Attached
Just some suggestions and explanations.
We can't put a ContentPage inside another ContentPage
It's better to use ContentView instead of ContentPage
Grid is more recommended in this scenario , since it fills with the whole Screen.
Use ValueChanged event to change the view dynamically.
Code :
Page
public partial class SegmentedAppPage : ContentPage
{
SegmentedControl segControl;
SegmentedControlOption scOptionOne;
SegmentedControlOption scOptionTwo;
Grid grid;
View1 view1 = new View1();
View2 view2 = new View2();
public SegmentedAppPage()
{
InitializeComponent();
segControl = new SegmentedControl();
segControl.SelectedValue = "One";
scOptionOne = new SegmentedControlOption();
scOptionTwo = new SegmentedControlOption();
scOptionOne.Text = "One";
scOptionTwo.Text = "Two";
segControl.Children.Add(scOptionOne);
segControl.Children.Add(scOptionTwo);
grid = new Grid();
grid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(1, GridUnitType.Auto) });
grid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(1, GridUnitType.Star) });
grid.Children.Add(segControl, 0, 0);
grid.Children.Add(view1, 0, 1);
this.Content = grid;
segControl.ValueChanged += SegControl_ValueChanged;
}
private void SegControl_ValueChanged(object sender, EventArgs e)
{
SegmentedControl control = sender as SegmentedControl;
if(control.SelectedValue is "One")
{
grid.Children.Remove(view2);
grid.Children.Add(view1,0,1); //This line
}
else if (control.SelectedValue is "Two")
{
grid.Children.Remove(view1);
grid.Children.Add(view2, 0, 1); //This line
}
this.Content = grid;
}
}
ContentView
public class View1 : ContentView
{
public View1()
{
Content = new StackLayout
{
BackgroundColor = Color.Green,
Children = {
new Label { Text = "View1" }
}
};
}
}
To set default value on segmentedControl , modify code in SegmentedControlRenderers
protected override void OnElementChanged(ElementChangedEventArgs<SegmentedControl> e)
{
base.OnElementChanged(e);
var segmentedControl = new UISegmentedControl();
for (var i = 0; i < e.NewElement.Children.Count; i++)
{
segmentedControl.InsertSegment(e.NewElement.Children[i].Text, i, false);
}
segmentedControl.ValueChanged += (sender, eventArgs) => {
e.NewElement.SelectedValue = segmentedControl.TitleAt(segmentedControl.SelectedSegment);
};
segmentedControl.SelectedSegment = 0; // add this line
SetNativeControl(segmentedControl);
}
Test
This is my listview class
public class ListViewClass : ListView
{
public ListViewClass ()
{
var cell = new DataTemplate(typeof(ViewCellClass));
ItemTemplate = cell;
SeparatorVisibility = SeparatorVisibility.None;
this.Style = (Style)Application.Current.Resources["commonBottomMarginThickness"];
HasUnevenRows = true;
}
}
I attached the screenshot. how to put space between the listview items above and below.
Add the value Transparent to your SeparatorColor property.
Like this:
public ListViewClass ()
{
var cell = new DataTemplate(typeof(ViewCellClass));
ItemTemplate = cell;
SeparatorVisibility = SeparatorVisibility.None;
SeparatorColor = Color.Transparent;
this.Style = (Style)Application.Current.Resources["commonBottomMarginThickness"];
HasUnevenRows = true;
}
I have a custom ViewCell. I was wondering if I could add a command to it, which would navigate to another page, when the ViewCell is clicked.
Below is what I have so far:
public class MainMenuItem : ViewCell
{
public MainMenuItem(string text, string icon)
{
View = new StackLayout()
{
Spacing = 10,
Padding = 10,
Orientation = StackOrientation.Horizontal,
VerticalOptions = LayoutOptions.Center,
Children = {
new Image() {
Source = ImageSource.FromFile(icon),
HorizontalOptions = LayoutOptions.Start,
HeightRequest = 30,
WidthRequest = 30,
},
new Label() {
Text = text,
HorizontalOptions = LayoutOptions.Start,
FontSize = 18,
},
new Image() {
Source = ImageSource.FromFile("listitem_next.png"),
HeightRequest = 12,
HorizontalOptions = LayoutOptions.EndAndExpand
}
}
};
View = View;
}
}
Above is my view cell. Now I render these within Table sections of a TableView. And here is the code for that:
TableView tvProfile = new TableView
{
HasUnevenRows = true,
Intent = TableIntent.Form,
Root = new TableRoot {,
new TableSection ("Emergency Contacts")
{
new MainMenuItem("Contacts", "icon_phone.png")
},
new TableSection ("Check in Timers")
{
new MainMenuItem("Timers", "icon_clock.png")
},
new TableSection ("Medical Information")
{
new MainMenuItem("Medcial Info", "icon_medicalkit.png")
}
}
};
What I want is, when the user selects an Item (the ViewCell), I want to navigate the user to the respective page.
How do I do this using a command? If it's even possible. I'm new to using commands, so whatever I've gotten on the web has gone over my head.
Any help on this would be HUGELY appreciated.
Here is a quick'n'dirty implementation. Add command and commandParameter to constructor and add GestureRecognizer which calls this command.
public class MainMenuItem : ViewCell
{
public MainMenuItem(string text, string icon, ICommand command, Func<Page> commandParameterFunc)
{
View = new StackLayout()
{
...
};
View.GestureRecognizers.Add(new TapGestureRecognizer { Command = command, CommandParameter = commandParameterFunc });
}
}
Then do the following changes - create a command and add 2 parameters to every cell. Here you define the command, what happens when you click and a parameter for the command, which is a Page (but you should not create it here already and check for errors).
Update: I changed to pass a function instead of an object, so the Page is created on click. Still a bit dirty ;)
public class MyPage : ContentPage
{
private readonly ICommand _navigateCommand;
public MyPage()
{
_navigateCommand = new Command(commandParamter => Navigation.PushModalAsync((commandParamter as Func<Page>)())));
TableView tvProfile = new TableView
{
HasUnevenRows = true,
Intent = TableIntent.Form,
Root = new TableRoot
{
new TableSection ("Emergency Contacts")
{
new MainMenuItem("Contacts", "icon_phone.png", _navigateCommand, () => new ContactsPage())
},
new TableSection ("Check in Timers")
{
new MainMenuItem("Timers", "icon_clock.png", _navigateCommand, () => new TimersPage())
},
new TableSection ("Medical Information")
{
new MainMenuItem("Medcial Info", "icon_medicalkit.png", _navigateCommand, () => new MedicalInfoPage())
}
}
};
Content = tvProfile;
}
}
So I have a horizontal scrollview that I'm trying to dynamically populate when the user takes a certain action. The items I am throwing into the view each contain 4 labels that are using custom fonts. When I try to add about 10 of these items it lags for about 1.5 seconds on android and 1 second on IOS. If I take the custom font out then its about 1 second on each platform. If I take out 3 of the labels and only display one then its almost instantaneous. Is there any known reason for the lag? And is there any way around it so I can still use a custom font without a huge lag?
Here's a quick sample I made that pretty much does what I'm doing in my app. However, my app has more stuff so the lag isn't quite as bad here but it is still very noticeable
public class App : Application
{
public int count;
public ScrollView scroll, scroll2, scroll3;
public App ()
{
count = 1;
scroll = new ScrollView {
VerticalOptions = LayoutOptions.Center,
Orientation = ScrollOrientation.Horizontal
};
scroll2 = new ScrollView {
VerticalOptions = LayoutOptions.Center,
Orientation = ScrollOrientation.Horizontal
};
Button button = new Button(){
Text = "click",
};
button.Clicked += (sender, e) => AddStuff();
Button button2 = new Button(){
Text = "click",
};
button2.Clicked += (sender, e) => AddStuff2();
MainPage = new ContentPage {
BackgroundColor = Color.White,
Content = new StackLayout{
Children={
button,
scroll,
button2,
scroll2
}
}
};
}
//this one is instantaneous
public void AddStuff()
{
StackLayout stack = new StackLayout () {
Orientation = StackOrientation.Horizontal,
HorizontalOptions = LayoutOptions.FillAndExpand,
HeightRequest = 200,
};
for (int i = 0; i < 11; i++)
stack.Children.Add (
new StackLayout(){
Children = {
new Label (){TextColor = Color.Blue, Text = "Size: ", WidthRequest = 100 },
}
}
);
scroll.Content = stack;
count++;
}
//this one takes forever
public void AddStuff2()
{
StackLayout stack = new StackLayout () {
Orientation = StackOrientation.Horizontal,
HorizontalOptions = LayoutOptions.FillAndExpand,
HeightRequest = 200,
};
for (int i = 0; i < 11; i++)
stack.Children.Add (
new StackLayout(){
Children = {
new Label (){TextColor = Color.Blue, Text = "Size: ", WidthRequest = 100 },
new Label (){TextColor = Color.Blue, Text ="" + count*i, WidthRequest = 100 },
new Label (){TextColor = Color.Blue, Text = "Size: ", WidthRequest = 100 },
new Label (){TextColor = Color.Blue, Text ="" + count*i, WidthRequest = 100 }
}
}
);
scroll2.Content = stack;
count++;
}
}
and the custom font label for droid
[assembly: ExportRenderer (typeof (Label), typeof (CustomFontLabel_Droid))]
namespace df.Droid
{
public class CustomFontLabel_Droid:LabelRenderer
{
protected override void OnElementChanged (ElementChangedEventArgs<Xamarin.Forms.Label> e) {
base.OnElementChanged (e);
var label = (TextView)Control;
Typeface font = Typeface.CreateFromAsset (Forms.Context.Assets, "SourceSansPro-Semibold.otf");
label.Typeface = font;
}
}
}
Just incase anyone else is having a similar problem, if you make a static typeface property in the android MainActivity instead of calling createFromAsset inside the Label.OnElementChanged function every time then it gets rid of the extra lag on android.
CustomFontLabel_Droid.cs
[assembly: ExportRenderer (typeof (Label), typeof (CustomFontLabel_Droid))]
namespace df.Droid
{
public class CustomFontLabel_Droid:LabelRenderer
{
protected override void OnElementChanged (ElementChangedEventArgs<Xamarin.Forms.Label> e) {
base.OnElementChanged (e);
var label = (TextView)Control;
// this guy slows things down-> Typeface font = Typeface.CreateFromAsset (Forms.Context.Assets, "SourceSansPro-Semibold.otf");
label.Typeface = MainActivity.semiBoldFont;
}
}
}
MainActivity.cs
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsApplicationActivity
{
public static Typeface semiBoldFont = null;
protected override void OnCreate (Bundle bundle)
{
base.OnCreate (bundle);
global::Xamarin.Forms.Forms.Init (this, bundle);
LoadApplication (new App ());
semiBoldFont = Typeface.CreateFromAsset (Forms.Context.Assets, "SourceSansPro-Semibold.otf");
}
}