I am trying to get an image to show in my custom ViewCell, however, setting it manually doesn't work.
I am first creating a list of my custom view cells and setting the image through there. After I have all the view cells I need, I add them to a list and set that list to be the ItemSource for the listview. However; the image doesn't display even though it should through some very simplistic code. Am I missing something?
The following is the ContentPage that I am loading the view cells in.
public partial class InAppStorePage : ContentPage
{
private List<ViewCell> cells;
private Store inAppStore;
public InAppStorePage()
{
InitializeComponent();
InitializeObjects();
}
private void InitializeObjects()
{
cells = new List<ViewCell>();
inAppStore = AppStore.CurrentStore;
}
protected override void OnAppearing()
{
SetListViewTemplate();
LoadProductsIntoListView();
SetListViewItemSource();
}
private void LoadProductsIntoListView()
{
LoadPurchasedProductsIntoListView();
LoadPendingProductsIntoListView();
LoadNonPurchasedProductsIntoListView();
}
private void SetListViewTemplate()
{
InAppProductsListView.ItemTemplate = new DataTemplate(typeof(InAppStoreViewCell));
}
private void LoadPurchasedProductsIntoListView()
{
List<ViewCell> purchasedProductCells = new List<ViewCell>();
foreach (InAppProduct purchasedProduct in inAppStore.GetListOfPurchasedProducts())
{
InAppStoreViewCell purchasedProductViewCell = new InAppStoreViewCell();
//The Line in Question
purchasedProductViewCell.ProductImage.Source = purchasedProduct.GetIcon().Source;
purchasedProductCells.Add(purchasedProductViewCell);
}
cells.AddRange(purchasedProductCells);
}
private void LoadPendingProductsIntoListView()
{
List<ViewCell> pendingPurchasedProductCells = new List<ViewCell>();
foreach (InAppProduct pendingPurchaseProduct in inAppStore.GetListOfPendingPurchaseProducts())
{
InAppStoreViewCell pendingPurchaseProductCell = new InAppStoreViewCell();
//The Line in Question
pendingPurchaseProductCell.ProductImage.Source = pendingPurchaseProduct.GetIcon().Source;
pendingPurchasedProductCells.Add(pendingPurchaseProductCell);
}
cells.AddRange(pendingPurchasedProductCells);
}
private void LoadNonPurchasedProductsIntoListView()
{
List<ViewCell> nonPurchasedProductCells = new List<ViewCell>();
foreach (InAppProduct nonPurchasedProduct in inAppStore.GetListOfProductsThatHaventBeenPurchased())
{
InAppStoreViewCell nonPurchasedProductCell = new InAppStoreViewCell();
//The Line in Question
nonPurchasedProductCell.ProductImage.Source = nonPurchasedProduct.GetIcon().Source;
nonPurchasedProductCells.Add(nonPurchasedProductCell);
}
cells.AddRange(nonPurchasedProductCells);
}
private void SetListViewItemSource()
{
InAppProductsListView.ItemsSource = null;
InAppProductsListView.ItemsSource = cells;
}
}
And the following is the C# file of the custom viewcell and its accompanying xaml file
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class InAppStoreViewCell : ViewCell
{
public InAppStoreViewCell()
{
InitializeComponent();
}
public Image ProductImage
{
get
{
return CellProductIcon;
}
set
{
CellProductIcon = value;
}
}
public void SetColor(Color color)
{
ProductImage.BackgroundColor = color;
}
public Label ProductNameLabel
{
get
{
return CellProductNameLabel;
}
set
{
CellProductNameLabel = value;
}
}
public Label ProductStatusLabel
{
get
{
return CellProductStatus;
}
set
{
CellProductStatus = value;
}
}
public Label ProductPriceLabel
{
get
{
return CellProductPriceLabel;
}
set
{
CellProductPriceLabel = value;
}
}
}
The Xaml file
<?xml version="1.0" encoding="UTF-8"?>
<ViewCell xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Alan.Views.UIElements.InAppStoreViewCells.InAppStoreViewCell">
<ViewCell.View>
<RelativeLayout>
<RelativeLayout x:Name="TopContainer"
BackgroundColor="CornflowerBlue"
RelativeLayout.WidthConstraint="{ConstraintExpression Type=RelativeToParent, Property=Width, Factor=1}"
RelativeLayout.HeightConstraint="{ConstraintExpression Type=RelativeToParent, Property=Height, Factor=0.75}">
<Image x:Name="CellProductIcon"
BackgroundColor="Indigo"
Aspect="Fill"
RelativeLayout.WidthConstraint="{ConstraintExpression Type=RelativeToParent, Property=Width, Factor=1.0}"
RelativeLayout.HeightConstraint="{ConstraintExpression Type=RelativeToParent, Property=Height, Factor=1.0}"/>
</RelativeLayout>
<RelativeLayout x:Name="BottomContainer"
BackgroundColor="Orange"
RelativeLayout.WidthConstraint="{ConstraintExpression Type=RelativeToParent, Property=Width, Factor=1}"
RelativeLayout.HeightConstraint="{ConstraintExpression Type=RelativeToParent, Property=Height, Factor=0.25}"
RelativeLayout.YConstraint="{ConstraintExpression Type=RelativeToParent, Property=Height, Factor=0.75}">
<Label x:Name="CellProductNameLabel"/>
<Label x:Name="CellProductStatus"/>
<Label x:Name="CellProductPriceLabel"/>
</RelativeLayout>
</RelativeLayout>
</ViewCell.View>
</ViewCell>
Any help would be seriously appreciated because this super simplistic thing is driving me crazy :/
I think there's something wrong with the way you use it.
For example:
1.You didn't set the BindableProperty for your ViewCell.
2.Why do you assign cells to InAppProductsListView.ItemsSource while the type of its child element is ViewCell?
private List<ViewCell> cells;
cells = new List<ViewCell>();
InAppProductsListView.ItemsSource = cells;
We should assign our special data list to the ItemsSource of listView.
You can refer to the following sample code:
public ListPageCS()
{
Title = "BindingContextChanged Code Demo";
Padding = 10;
var customCell = new DataTemplate(typeof(CustomCell));
customCell.SetBinding(CustomCell.NameProperty, "Name");
customCell.SetBinding(CustomCell.AgeProperty, "Age");
customCell.SetBinding(CustomCell.LocationProperty, "Location");
var listView = new ListView
{
ItemTemplate = customCell
};
var button = new Button { Text = "Change Binding Context" };
button.Clicked += (sender, e) =>
{
listView.ItemsSource = Constants.People;
};
Content = new StackLayout
{
Children = {
listView,
button
}
};
}
For how to use custom ViewCell , you can check document Customizing ListView Cell Appearance.
And you can check up the sample included above link.
The sample is here: https://github.com/xamarin/xamarin-forms-samples/tree/main/UserInterface/ListView/BindingContextChanged .
Related
I have a Xamarin MVVM class that displays a full page image. The code is shown below. The single tap simply closes the view. My question is how to implement the pan or zoom. The only things that I can find are written for Xamarin Forms and I can't figure out how to adapt them to MVVM. Thanks.
<?xml version="1.0" encoding="utf-8" ?>
<views:MvxContentPage x:TypeArguments="viewModels:ImageViewModel"
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:views="clr-namespace:MvvmCross.Forms.Views;assembly=MvvmCross.Forms"
xmlns:viewModels="clr-namespace:BLE.Client.ViewModels;assembly=BLE.Client"
x:Class="BLE.Client.Pages.ImagePage" Title="View Image">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"></RowDefinition>
</Grid.RowDefinitions>
<StackLayout Grid.Row="0" Orientation="Horizontal" >
<Image x:Name="WaypointImage" Source="{Binding MyImage}" HorizontalOptions="FillAndExpand">
<Image.GestureRecognizers>
<TapGestureRecognizer Command="{Binding TapCommand}"/>
<PinchGestureRecognizer Command="{Binding PinchCommand}"/>
<PanGestureRecognizer Command="{Binding PanCommand}"/>
</Image.GestureRecognizers>
</Image>
</StackLayout>
</Grid>
</views:MvxContentPage>
using System;
using System.Windows.Input;
using Xamarin.Forms;
using Acr.UserDialogs;
using MvvmCross;
using MvvmCross.ViewModels;
using MvvmCross.Navigation;
using Plugin.BLE.Abstractions.Contracts;
namespace BLE.Client.ViewModels
{
public class ImageViewModel : BaseViewModel
{
private ImageSource _myImage;
public ImageSource MyImage
{
get => _myImage;
set
{
_myImage = value;
RaisePropertyChanged(() => MyImage);
}
}
private readonly IUserDialogs _userDialogs;
private readonly IMvxNavigationService _navigation;
public String _waypoint;
public Waypoint waypoint;
public ICommand tapCommand;
public ICommand TapCommand {
get { return tapCommand; }
}
public ICommand pinchCommand;
public ICommand PinchCommand {
get { return pinchCommand; }
}
public ICommand panCommand;
public ICommand PanCommand {
get { return panCommand; }
}
public ImageViewModel(IAdapter adapter, IUserDialogs userDialogs) : base(adapter)
{
_userDialogs = userDialogs;
_navigation = Mvx.IoCProvider.Resolve<IMvxNavigationService>();
tapCommand = new Command (OnTapped);
pinchCommand = new Command (OnPinched);
panCommand = new Command (OnPan);
}
void OnTapped (object s) {
Console.WriteLine($"OnTapped: {s}");
_navigation.Close(this);
}
void OnPinched (object s) {
Console.WriteLine($"OnPinched: {s}");
}
void OnPan (object s) {
Console.WriteLine($"OnPan: {s}");
}
public override async void Prepare(MvxBundle parameters)
{
base.Prepare(parameters);
_waypoint = await GetWaypointFromBundleAsync(parameters);
string[] tags = _waypoint?.Split(' ');
char[] trimChars = { 'I', 'D', '=' };
string id = tags[0].TrimStart(trimChars);
int ID = System.Convert.ToInt32(id);
waypoint = await Database.GetWaypointAsync(ID);
MyImage = ImageSource.FromFile(waypoint.FileName);
Console.WriteLine($"prepare ID={waypoint.ID} {waypoint.FileName} ");
}
public override void ViewAppeared()
{
base.ViewAppeared();
if (_waypoint != null)
{
return;
}
_navigation.Close(this);
}
public override void ViewDisappearing()
{
base.ViewDisappearing();
}
public override void ViewDisappeared()
{
base.ViewDisappeared();
}
}
}
Update:
I found an even better solution to the one below:
My answer to a pinch and pan question
This is my previous answer that works to a point but I could not get the pinch and pan gestures to trigger:
I have found an MVVM solution that takes advantage of the bindable properties Image: TranslationX, TranslationY, and Scale. Here are the relevant code changes. I tested this by modifying MyImageTranslationX in the OnTapped method and saw that the image shifts to the right.
Now I just need to get the Image.GestureRecognizers (PinchGestureRecognizer and PanGestureRecognizer) working and then add code that I have seen elsewhere to smoothly pan and zoom.
<Image x:Name="WaypointImage"
Source="{Binding MyImage}"
Scale = "{Binding MyImageScale}"
TranslationX = "{Binding MyImageTranslationX}"
TranslationY = "{Binding MyImageTranslationY}"
HorizontalOptions="FillAndExpand">
<Image.GestureRecognizers>
<TapGestureRecognizer Command="{Binding TapCommand}"/>
<PinchGestureRecognizer Command="{Binding PinchCommand}"/>
<PanGestureRecognizer Command="{Binding PanCommand}"/>
</Image.GestureRecognizers>
</Image>
public double _myImageScale = 1.0;
public double MyImageScale
{
get => _myImageScale;
set
{
_myImageScale = value;
RaisePropertyChanged(() => MyImageScale);
}
}
public double _myImageTranslationX = 0;
public double MyImageTranslationX
{
get => _myImageTranslationX;
set
{
_myImageTranslationX = value;
RaisePropertyChanged(() => MyImageTranslationX);
}
}
public double _myImageTranslationY = 0;
public double MyImageTranslationY
{
get => _myImageTranslationY;
set
{
_myImageTranslationY = value;
RaisePropertyChanged(() => MyImageTranslationY);
}
}
private ImageSource _myImage;
public ImageSource MyImage
{
get => _myImage;
set
{
_myImage = value;
RaisePropertyChanged(() => MyImage);
}
}
void OnTapped (object s) {
Console.WriteLine($"OnTapped: {MyImage}");
MyImageTranslationX = MyImageTranslationX + 100;
// _navigation.Close(this);
}
I have simple XAML page with code like this:
<StackLayout BindableLayout.ItemsSource="{Binding Data}">
<BindableLayout.ItemTemplate>
<DataTemplate>
<Label BackgroundColor="{Binding Color}"
Text="{Binding Text}"
FontAttributes="Italic"
FontSize="20"
VerticalTextAlignment="Center"
HorizontalTextAlignment="Center"
HeightRequest="105"
Margin="25" />
</DataTemplate>
</BindableLayout.ItemTemplate>
</StackLayout>
In the view page code behind I have:
public partial class DataView
{
public DataView()
{
InitializeComponent();
BindingContext = new ViewModel();
}
...
}
Data is:
public class ViewModel
{
public ViewModel()
{
Data = new ObservableCollection()<Model> {
new Model { Text = "Pink", Color = Color.DeepPink },
new Model { Text = "Crimson", Color = Color.Crimson },
new Model { Text = "Aqua", Color = Color.Aqua },
new Model { Text = "Blue", Color = Color.DeepSkyBlue },
new Model { Text = "BurlyWood", Color = Color.BurlyWood }, };
}
public ObservableCollection<Model> Data { get; set; }
}
public class Model
{
public Color Color { get; set; }
public string Text { get; set; }
}
However, on compile, I get:
Binding: Property "Color" not found on "MyComp.ViewModel".
Seems like its searching for Color in ViewModel instead of parent (Data).
I'm using the latest Xamarin.Forms 4.8.0, .NET Standard 2.0 and Visual Studio 2019 16.7.4.
I tested the xaml code, it still works fine.Check the gif: https://us.v-cdn.net/5019960/uploads/editor/pd/aa0fp5pwnvkl.gif
Here is the related code, you could refer to it.
Page.xaml
<StackLayout x:Name="expanderLayout" BindableLayout.ItemsSource="{Binding Data}">
<BindableLayout.ItemTemplate>
<DataTemplate>
<Expander>
<Expander.Header>
<Grid>
<Label BackgroundColor="{Binding Color}"/>
</Grid>
</Expander.Header>
<Expander.ContentTemplate>
<DataTemplate>
<Label
Text="{Binding Text}"
FontAttributes="Italic"
FontSize="20"
VerticalTextAlignment="Center"
HorizontalTextAlignment="Center"
HeightRequest="105"
Margin="25" />
</DataTemplate>
</Expander.ContentTemplate>
</Expander>
</DataTemplate>
</BindableLayout.ItemTemplate>
</StackLayout>
Page.xaml.cs
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
BindingContext = new ViewModel();
}
}
Model class and ViewModel class
public class ViewModel
{
public ViewModel()
{
Data = new System.Collections.ObjectModel.ObservableCollection<Model>() {
new Model { Text = "Pink", Color = Color.DeepPink },
new Model { Text = "Crimson", Color = Color.Crimson },
new Model { Text = "Aqua", Color = Color.Aqua },
new Model { Text = "Blue", Color = Color.DeepSkyBlue },
new Model { Text = "BurlyWood", Color = Color.BurlyWood }, };
}
public ObservableCollection<Model> Data { get; set; }
}
public class Model
{
public Color Color { get; set; }
public string Text { get; set; }
}
I tried run your code and see nothing wrong with it
Apart from some slight typo in your question, I have it as this
public ViewModel()
{
Data = new ObservableCollection<Model>
{
new Model {Text = "Pink", Color = Color.DeepPink},
new Model {Text = "Crimson", Color = Color.Crimson},
new Model {Text = "Aqua", Color = Color.Aqua},
new Model {Text = "Blue", Color = Color.DeepSkyBlue},
new Model {Text = "BurlyWood", Color = Color.BurlyWood},
};
}
, maybe try clean/rebuild solution and run again?
Hi I am a beginner with Xamarin forms and need some help. I have tried looking for this method everywhere.
I have a List view with a lot of animal names. When a item is clicked it shows more info about that particular animal. I have added a button that is on each animals info page. I would like to click that "add" button, that would then add the name off the animal to another List view.
But I am stuck on how to do this, any help would be greatly appreciated.
this is the first list page in code behind
public partial class BirdListAZ : ContentPage
{
IEnumerable<birdlistmodel> GetBirds(string searchText = null)
{
var birds = new List<birdlistmodel>
{
new birdlistmodel (){Id = 1, BirdNames = "Apalis, Bar-throated" },
new birdlistmodel (){Id = 2, BirdNames = "Apalis, Yellow-breasted"},//there are alot more birds here
};
if (String.IsNullOrWhiteSpace(searchText))
return birds;
var lowerBirds = searchText.ToLower();
return birds.Where(c => c.BirdNames.ToLower().StartsWith(lowerBirds));
}
public BirdListAZ()
{
InitializeComponent();
blistview.ItemsSource = GetBirds();
}
private void SearchBar_TextChanged(object sender, TextChangedEventArgs e)
{
blistview.ItemsSource = GetBirds(e.NewTextValue);
}
private void blistview_ItemSelected(object sender, SelectedItemChangedEventArgs e)
{
var birds = e.SelectedItem as birdlistmodel;
Navigation.PushAsync(new BirdPages(birds.BirdNames, birds.BirdSelect));
}
}
}
this is the content page for that code behind
<ScrollView HeightRequest="3000">
<StackLayout>
<SearchBar
TextChanged="SearchBar_TextChanged"
Placeholder="Search Bird"
PlaceholderColor="Gray"
HorizontalTextAlignment="Center"
FontSize="Small"
FontAttributes="Italic"
VerticalOptions="Center" HorizontalOptions="Start"/>
<ListView x:Name="blistview" BackgroundColor ="AliceBlue" HasUnevenRows="True" ItemSelected="blistview_ItemSelected">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Orientation="Horizontal" Padding="5">
<Label Text="{Binding BirdNames}" HorizontalOptions="StartAndExpand" VerticalOptions="Center"/>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</ScrollView>
when item is clicked on list it displays that info in a separate page
the contentpage
<ContentPage.Content>
<StackLayout>
<Label x:Name="BirdNameCall" FontSize="30" FontAttributes="Bold"
VerticalOptions="StartAndExpand"
HorizontalOptions="CenterAndExpand" />
<Button Text="+" x:Name="AddToList" VerticalOptions="Center" HorizontalOptions="Center" WidthRequest="200" HeightRequest="100"
FontSize="30" BackgroundColor="Transparent" Clicked="AddToList_Clicked"/>
</StackLayout>
</ContentPage.Content>
</ContentPage>
So this is what i have done. I know the filewritealltext makes a new file each time. how can i just add to that file so a new file is not created?
public BirdPages(string BirdNames, Button BirdSelect)
{
InitializeComponent();
BirdNameCall.Text = BirdNames;
AddToList = BirdSelect;
localPath = Path.Combine(FileSystem.AppDataDirectory, birdfile);
}
const string birdfile = "birdlist.txt";
string localPath;
private void AddToList_Clicked(object sender, EventArgs e)
{
string BirdNames = BirdNameCall.Text;
File.WriteAllText(localPath, BirdNames);
DisplayAlert(BirdNames, "added to list", "Ok");
}
So it works when i populate the list view but it will be a letter per row and not the entire string in a row
public partial class myBirdList : ContentPage
{
public myBirdList()
{
InitializeComponent();
localPath = Path.Combine(FileSystem.AppDataDirectory, birdfile);
birdlistview.ItemsSource = File.ReadAllText(localPath);
}
const string birdfile = "birdlist.txt";
string localPath;
}
So this is what I have done. I had to change a bit.
The added Bird Name needs to go to a blank list. So I created a new Observable Collection here. And this is where the Bird Name needs to be added.
public partial class myBirdList : ContentPage
{
public ObservableCollection<string> Birdsadded { get; set; } = new ObservableCollection<string>();
public myBirdList()
{
InitializeComponent();
BindingContext = this;
MessagingCenter.Subscribe<BirdPages, birdlistmodel>(this, "Add", (sender, arg) =>
{
Birdsadded.Add(arg.ToString());
});
}
}
}
Then the sender is where I am having issues. And can't figure out how to send the bird name.
public partial class BirdPages : ContentPage
{
public BirdPages(string BirdNames, Button BirdSelect)
{
InitializeComponent();
BirdNameCall.Text = BirdNames;
AddToList = BirdSelect;
}
private void AddToList_Clicked(object sender, EventArgs e)
{
birdlistmodel bird = xxx// this is what i don't understand, what should be added here
MessagingCenter.Send<BirdListAZ, birdlistmodel>(this, "Add", bird );
}
}
}
thanks for your time and input I appreciate it.
You could use MessagingCenter to achieve this.
Using MessagingCenter.Send to pass the new data in your AddToList_Clicked method of BirdPages
then you will get the callback in another page which you want to add the new items with MessagingCenter.Subscribe method.In the callback method,you could add the new data to the new listview.
For example:
In the listview page which you want display a list and add the new data.
public partial class BirdListAZ : ContentPage
{
public ObservableCollection<string> Birdsadded { get; set; } = new ObservableCollection<string>();
public BirdListAZ()
{
InitializeComponent();
blistview.ItemsSource = GetBirds();
MessagingCenter.Subscribe<BirdListAZ, string>(this, "Add", async (sender, arg) =>
{
Birdsadded.Add(arg);// when you click add button in other page,it will handle this
});
}
}
in the page which you want to add the data:
public partial class BirdPages : ContentPage
{
public BirdPages(string BirdNames, Button BirdSelect)
{
InitializeComponent();
BirdNameCall.Text = BirdNames;
AddToList = BirdSelect;
}
private void AddToList_Clicked(object sender, EventArgs e)
{
string birdname = xxxx;
MessagingCenter.Send<BirdListAZ, string>(this, "Add",birdname );
}
}
OK so i got it to work to some extent. I am not creating and writing to a txt file and then reading from it in mybirdlist page. This is where i write to text file
public BirdPages(string BirdNames, Button BirdSelect)
{
InitializeComponent();
BirdNameCall.Text = BirdNames;
AddToList = BirdSelect;
localPath = Path.Combine(FileSystem.AppDataDirectory, birdfile);
}
const string birdfile = "birdlist.txt";
string localPath;
private void AddToList_Clicked(object sender, EventArgs e)
{
string BirdNames = BirdNameCall.Text;
using (var writer = new StreamWriter(localPath, true))
{
writer.WriteLine(BirdNames);
}
DisplayAlert(BirdNames, "added to list", "Ok");
}
Then i read from it into a list. Last question i have is how can i read each name into a lable. Now all the added birds displays in one label. And is it possible to not duplicate a name? Here is the code
public myBirdList()
{
localPath = Path.Combine(FileSystem.AppDataDirectory, birdfile);
string text = "";
using (var reader = new System.IO.StreamReader(localPath))
{
text = reader.ReadToEnd();
}
InitializeComponent();
birdlistview.ItemsSource = new List<birdlistmodel>
{
new birdlistmodel {Voellist = text }
};
}
const string birdfile = "birdlist.txt";
string localPath;
}
I have a CarouselPage having 5 children and every child has a horizontal collection view. When selecting an item in Collectionview or swiping the pages, I need to give a different text color and need to add an underline for the selected item. I have tried like below:
CarouselHomePage.cs
public partial class CarouselHomePage : CarouselPage
{
public List<Activity> activityList { get; set; }
public CarouselHomePage()
{
InitializeComponent();
activityList = new List<Activity>();
AddActivities();
MessagingCenter.Subscribe<App, string>((App)Xamarin.Forms.Application.Current, "child", (s, child) =>
{
CurrentPage = Children[Int32.Parse(child)];
});
}
private void AddActivities()
{
activityList.Add(new Activity() { Title = "PageNumber1" });
activityList.Add(new Activity() { Title = "PageNumber2" });
activityList.Add(new Activity() { Title = "PageNumber3" });
activityList.Add(new Activity() { Title = "PageNumber4" });
activityList.Add(new Activity() { Title = "PageNumber5" });
AddChild(activityList);
}
public void AddChild(List<Activity> activityList)
{
this.Children.Add(new PageNumber1(activityList));
this.Children.Add(new PageNumber2(activityList));
this.Children.Add(new PageNumber3(activityList));
this.Children.Add(new PageNumber4(activityList));
this.Children.Add(new PageNumber5(activityList));
}
}
Activity.cs
public class Activity
{
public string Title { get; set; }
public bool visibility { get; set; }
public bool Visibility
{
set
{
if (value != null)
{
visibility = value;
NotifyPropertyChanged();
}
}
get
{
return visibility;
}
}
private Color textColor;
public Color TextColor
{
set
{
if (value != null)
{
textColor = value;
NotifyPropertyChanged();
}
}
get
{
return textColor;
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
PageNumber1.xaml
<ContentPage.Content>
<StackLayout Orientation="Vertical">
<CollectionView
SelectionMode="Single"
x:Name="ActivityList"
Margin="5,10,5,10"
SelectionChanged="TagItemTapped"
ItemsLayout="HorizontalList">
<CollectionView.ItemTemplate>
<DataTemplate>
<StackLayout
Orientation="Vertical"
Margin="15">
<Label
TextColor="{Binding TextColor}"
HorizontalTextAlignment="Center"
VerticalTextAlignment="Center"
Text="{Binding Title}">
<Label.FontSize>
<OnIdiom x:TypeArguments="x:Double">
<OnIdiom.Phone>18</OnIdiom.Phone>
<OnIdiom.Tablet>27</OnIdiom.Tablet>
<OnIdiom.Desktop>18</OnIdiom.Desktop>
</OnIdiom>
</Label.FontSize>
</Label>
<BoxView
HeightRequest="2"
IsVisible="{Binding Visibility}"
BackgroundColor="{Binding TextColor}"
HorizontalOptions="CenterAndExpand"
VerticalOptions="Start"/>
</StackLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
<CollectionView.HeightRequest>
<OnIdiom x:TypeArguments="x:Double">
<OnIdiom.Phone>30</OnIdiom.Phone>
<OnIdiom.Tablet>60</OnIdiom.Tablet>
<OnIdiom.Desktop>30</OnIdiom.Desktop>
</OnIdiom>
</CollectionView.HeightRequest>
</CollectionView>
<Label Text="Welcome to PageNumber1"
VerticalOptions="CenterAndExpand"
HorizontalOptions="CenterAndExpand" />
</StackLayout>
</ContentPage.Content>
PageNumber1.xaml.cs
public partial class PageNumber1 : ContentPage
{
public PageNumber1(List<Activity> activityList)
{
InitializeComponent();
if (activityList == null)
{
ActivityList.IsVisible = false;
}
else
{
for (int i = 0; i < activityList.Count; i++)
{
if (activityList[i].Title == "PageNumber1")
{
activityList[i].TextColor = Color.FromHex("#26b4d8");
activityList[i].Visibility = true;
}
else
{
activityList[i].TextColor = Color.Gray;
activityList[i].Visibility = false;
}
}
ActivityList.ItemsSource = activityList;
}
}
public void TagItemTapped(object sender, SelectionChangedEventArgs e)
{
var selectedItem = (e.CurrentSelection.FirstOrDefault() as Activity);
if (selectedItem != null)
{
string childnumber = "";
if (selectedItem.Title == "PageNumber1")
{
childnumber = "0";
}
else if (selectedItem.Title == "PageNumber2")
{
childnumber = "1";
}
else if (selectedItem.Title == "PageNumber3")
{
childnumber = "2";
}
else if (selectedItem.Title == "PageNumber4")
{
childnumber = "3";
}
else if (selectedItem.Title == "PageNumber5")
{
childnumber = "4";
}
MessagingCenter.Send<App, string>((App)Xamarin.Forms.Application.Current, "child", childnumber);
}
}
}
I have added the same code on all the other child pages with the corresponding title in the if statement. But the selected page title color is not working and underline is not showing.
Screenshot:
Also if I select the last item in the collectionview, I need to scroll the collection on the last child to the last item. For this I have used ScrollTo feature of Collectioview. But that is also not working.
protected override void OnAppearing()
{
ActivityList.ScrollTo(4);
}
The above code will work if I manually swipe the pages. When directly tap the collectionview item, the scrolling is not working.
I have uploaded a sample project here.
About underline not showing , the reason is HeightRequest of CollectionView setted too small with 30 .
Modify that to above 35 , it will show correcttly . Such as :
<CollectionView.HeightRequest>
<OnIdiom x:TypeArguments="x:Double">
<OnIdiom.Phone>40</OnIdiom.Phone>
<OnIdiom.Tablet>60</OnIdiom.Tablet>
<OnIdiom.Desktop>30</OnIdiom.Desktop>
</OnIdiom>
</CollectionView.HeightRequest>
The effect :
About selected problem , this is the sample project here .
I am working on an Android app with Xamarin, using Telerik UI.
The following error is raised when trying to bind a property to a Telerik ListViewTextCell in a RadListView:
[0:] Binding: 'Author' property not found on 'Book', target property: 'Telerik.XamarinForms.DataControls.ListView.ListViewTextCell.Detail'
This happens in even the most minimal cases. Below is an example, drawn largely from the ListView documentation itself.
PageTest.cs:
using System.Collections.Generic;
using System.ComponentModel;
using Xamarin.Forms;
using Telerik.XamarinForms.DataControls;
using Telerik.XamarinForms.DataControls.ListView;
namespace MyTelerikApp
{
[DesignTimeVisible(false)]
public partial class PageTest : ContentPage
{
public PageTest()
{
InitializeComponent();
}
protected override void OnAppearing()
{
base.OnAppearing();
var listView = new RadListView
{
ItemsSource = new ViewModel().Source,
ItemTemplate = new DataTemplate(() =>
{
var cell = new ListViewTextCell
{
TextColor = Color.Black,
DetailColor = Color.Gray,
};
cell.SetBinding(ListViewTextCell.TextProperty, new Binding(nameof(Book.Title)));
cell.SetBinding(ListViewTextCell.DetailProperty, new Binding(nameof(Book.Author)));
return cell;
}),
LayoutDefinition = new ListViewLinearLayout { ItemLength = 70 }
};
MainPageContent.Children.Add(listView);
}
}
}
public class Book
{
public string Title { get; set; }
public string Author { get; set; }
}
public class ViewModel
{
public ViewModel()
{
this.Source = new List<Book>{
new Book{ Title = "The Fault in Our Stars ", Author = "John Green"},
new Book{ Title = "Divergent", Author = "Veronica Roth"},
new Book{ Title = "Gone Girl", Author = "Gillian Flynn"},
new Book{ Title = "Clockwork Angel", Author = "Cassandra Clare"},
new Book{ Title = "The Martian", Author = "Andy Weir"},
new Book{ Title = "Ready Player One", Author = "Ernest Cline"},
new Book{ Title = "The Lost Hero", Author = "Rick Riordan"},
new Book{ Title = "All the Light We Cannot See", Author = "Anthony Doerr"},
new Book{ Title = "Cinder", Author = "Marissa Meyer"},
new Book{ Title = "Me Before You", Author = "Jojo Moyes"},
new Book{ Title = "The Night Circus", Author = "Erin Morgenstern"},
};
}
public List<Book> Source { get; set; }
}
PageText.xaml:
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:d="http://xamarin.com/schemas/2014/forms/design"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
x:Class="GeoGIS.views.PageTest">
<StackLayout x:Name="MainPageContent">
</StackLayout>
</ContentPage>
After some searching, it seems that a BindingContext is necessary, but I couldn't get that to work either.
I didn't found BindingContext from your code.And I guess you confused the two usages of ContentPage(XAML and C# ).
When we created a contentpage,we have two choices(XAML and C#) as follows:
1.When we choose the ContentPage(c#),in this case, there is no xaml.And we can do like this:
public class TestPage1 : ContentPage
{
public TestPage1 ()
{
var listView = new RadListView
{
BackgroundColor = Color.White,
ItemsSource = new ViewModel().Source,
ItemTemplate = new DataTemplate(() =>
{
var cell = new ListViewTextCell
{
TextColor = Color.Black,
DetailColor = Color.Gray,
};
cell.SetBinding(ListViewTextCell.TextProperty, new Binding(nameof(Book.Title)));
cell.SetBinding(ListViewTextCell.DetailProperty, new Binding(nameof(Book.Author)));
return cell;
}),
LayoutDefinition = new ListViewLinearLayout { ItemLength = 70 },
};
Content = new StackLayout {
Children = {
listView
}
};
}
}
2.When we choose the ContentPage,in this case, code has xaml.We can do like this.
Put the followinging code in your xaml
<StackLayout>
<telerikDataControls:RadListView ItemsSource="{Binding Source}" BackgroundColor="White" x:Name="listView">
<telerikDataControls:RadListView.BindingContext>
<local:ViewModel />
</telerikDataControls:RadListView.BindingContext>
<telerikDataControls:RadListView.ItemTemplate>
<DataTemplate>
<telerikListView:ListViewTextCell Text="{Binding Title}" Detail="{Binding Author}" TextColor="Black" DetailColor="Gray" />
</DataTemplate>
</telerikDataControls:RadListView.ItemTemplate>
<telerikDataControls:RadListView.LayoutDefinition>
<telerikListView:ListViewLinearLayout ItemLength="70" />
</telerikDataControls:RadListView.LayoutDefinition>
</telerikDataControls:RadListView>
</StackLayout>
And remove the method OnAppearing() from your code.
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
//BindingContext = new ViewModel();
}
protected override void OnAppearing()
{
base.OnAppearing();
}
}
From above code,we can found the BindingContext,it is necessary.
<telerikDataControls:RadListView.BindingContext>
<local:ViewModel />
</telerikDataControls:RadListView.BindingContext>
And we can also BindingContext like this(Any one is ok.):
BindingContext = new ViewModel();
The result is the same: