I am trying to put together a selectableItemsView to populate with a list of objects and for some reason, I'm not getting any items to show in the SelectableItemsView; I only get a white blank space where the items are supposed to be. TermView is inserted into the mainPage and is supposed to contain Term information as well as a Class list that is displayed via SelectableItemsView. I've also tried using a ListView and its giving me the same problem.
TermView.xaml.cs constructor
public TermView(int termId)
{
InitializeComponent();
this.Term = new Term(termId);
this.BindingContext = this.Term;
}
TermView.xaml
<ContentView 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="TermManager1.TermView">
<StackLayout VerticalOptions="Start" >
<FlexLayout AlignItems="Center" Direction="Row" JustifyContent="SpaceBetween" VerticalOptions="Start">
<DatePicker Date="{Binding TermStartDate}" />
<Editor Text="{Binding TermName}" />
<DatePicker Date="{Binding TermEndDate}" />
</FlexLayout>
<SelectableItemsView x:Name="ClassesCollectionView" ItemsSource="{Binding classes}" >
<SelectableItemsView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout>
<Label Text="{Binding ClassName}"/>
</StackLayout>
</ViewCell>
</DataTemplate>
</SelectableItemsView.ItemTemplate>
</SelectableItemsView>
<FlexLayout>
<Button Text="Add Class" Clicked="AddClassButton_OnClicked" />
<Button Text="Delete Class" Clicked="DeleteClassButton_OnClicked" />
</FlexLayout>
</StackLayout>
</ContentView>
Term class constructor & Class list
public List<Class> classes = new List<Class>();
public Term(int termID)
{
this.TermId = termID;
this.TermName = String.Concat("TermName", termID);
this.classes.Add(new Class());
this.classes.Add(new Class());
this.classes.Add(new Class());
this.classes.Add(new Class());
}
Class class constructor
public Class()
{
this.ClassName = "ClassName";
this.ClassId = 0;
this.ClassStatus = "Unset Status";
}
You probably just have to use INPC on this to work.
Change Classes to be an ObservableCollection instead of a List (note there's a ToObservableCollection extension available too).
Then for the Class object, just inherit from BindableObject and use OnPropertyChanged() in the setter for the properties you want to be updated, e.g.:
private string _className;
public string ClassName;
{
get => _className;
set
{
_className = value;
OnPropertyChanged();
}
}
So I fixed my issue with a variety of things. Firstly, I replaced the SelectableItemsView with a CollectionView. Then I changed my List of Classes to an ObservableCollection. And Lastly, I replaced the ViewCell in my TermView xaml with a StackLayout.
I've also tried using a ListView and its giving me the same problem.
According to your code, I see you add some Class in List classes, but you don't assign ClassName value, here is the sample about ListView:
public partial class Page30 : ContentPage
{
public Page30 (int Id)
{
InitializeComponent ();
this.BindingContext = new Term(Id);
}
}
public class Term
{
public List<Class1> classes { get; set; }
public int TermId { get; set; }
public string TermName { get; set; }
public DateTime TermStartDate { get; set; }
public DateTime TermEndDate { get; set; }
public Term(int TermId)
{
this.TermId = TermId;
this.TermName = String.Concat("TermName", TermId);
TermStartDate = new DateTime(2017,7,24);
TermEndDate = new DateTime(2019,01,01);
classes = new List<Class1>()
{
new Class1(){ClassName="class a"},
new Class1(){ClassName="class b"},
new Class1(){ClassName="class c"},
new Class1(){ClassName="class d"},
new Class1(){ClassName="class e"},
new Class1(){ClassName="class f"},
new Class1(){ClassName="class g"},
};
}
}
public class Class1
{
public string ClassName { get; set; }
}
Related
I would like to slightly modify the code generated when creating a maui project to implement the following
add an object to Meetings in MainPage.xaml.cs when the button is clicked
display the contents of that Meetings
I wrote the following code for this purpose, but there is no change in the output content. One possible reason for this is that adding data to the object does not re-render the screen. How can I solve this problem?
Views/MainPage.xaml
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:App.Views"
x:Class="App.Views.MainPage">
<ScrollView>
<VerticalStackLayout
Spacing="25"
Padding="30,0"
VerticalOptions="Center">
<Image
Source="dotnet_bot.png"
SemanticProperties.Description="Cute dot net bot waving hi to you!"
HeightRequest="200"
HorizontalOptions="Center" />
<Label
Text="Hello, World!"
SemanticProperties.HeadingLevel="Level1"
FontSize="32"
HorizontalOptions="Center" />
<Label
Text="Welcome to .NET Multi-platform App UI"
SemanticProperties.HeadingLevel="Level2"
SemanticProperties.Description="Welcome to dot net Multi platform App U I"
FontSize="18"
HorizontalOptions="Center" />
<Button
x:Name="CounterBtn"
Text="Click me"
SemanticProperties.Hint="Counts the number of times you click"
Clicked="OnCounterClicked"
<ListView ItemsSource="{Binding Meetings}" />
</VerticalStackLayout>
</ScrollView>
</ContentPage>
Views/MainPage.xaml.cs
namespace App.Views;
using App.Models;
public partial class MainPage : ContentPage
{
int count = 0;
public MainPage()
{
InitializeComponent();
BindingContext = new Models.AllMeetings();
}
private void OnCounterClicked(object sender, EventArgs e)
{
count++;
if (count == 1)
CounterBtn.Text = $"Clicked {count} time";
else
CounterBtn.Text = $"Clicked {count} times";
SemanticScreenReader.Announce(CounterBtn.Text);
((Models.AllMeetings)BindingContext).Meetings.Add(new Models.Meeting() { Name = "foo" });
}
}
Modes/AllMeetings
namespace App.Models;
internal class AllMeetings
{
public List<Meeting> Meetings { get; set; }
}
Models/Meetings.cs
namespace App.Models;
internal class Meeting
{
public string Name { get; set; }
}
Updates
Models/AllMeetings.cs
using System.Collections.ObjectModel;
namespace ailia_speech_gui.Models;
internal class AllMeetings
{
public ObservableCollection<Meeting> Meetings { get; set; }
public void Add_Meeting(Meeting meeting)
{
this.Meetings.Add(meeting);
}
}
I made a demo on my side. You can refer to my demo to change your project.
Here is the code in my Model named Products.cs:
namespace ListViewDelete.Models
{
public class Products
{
public string Name
{
get; set;
}
public double Price
{
get; set;
}
}
}
Then you need to create a viewmodel to realize the delete and add method and create the ObservableCollection to load the data.
Here is the code in my ViewModel:
namespace ListViewDelete.ViewModels
{
internal class ProductsViewModels
{
public ObservableCollection<Products> Products
{
get; set;
}
public Command<Products> RemoveCommand
{
get
{
return new Command<Products>((Product) => {
Products.Remove(Product);
});
}
}
public Command<Products> AddCommand
{
get
{
return new Command<Products>((Product) => {
Products.Add(Product);
});
}
}
public ProductsViewModels()
{
Products = new ObservableCollection<Products> {
new Products {
Name = "name1",
Price = 100
},
new Products {
Name = "name2",
Price = 100
},
new Products {
Name = "name3",
Price = 100
}
};
}
}
}
Last, you need to create the ListView or the CollectionView in the MainPage.xaml. Here is the code in the MainPage.xaml:
<StackLayout>
<Button Text="add" Clicked="Button_Clicked"></Button>
<CollectionView ItemsSource="{Binding Products}">
<CollectionView.ItemTemplate>
<DataTemplate>
<StackLayout>
<Label Text="{Binding Name}" />
<Label Text="{Binding Price}" />
<Button Text="Remove" Clicked="Remove_Clicked" />
</StackLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</StackLayout>
Here is the code in MainPage.xaml.cs:
namespace ListViewDelete
{
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
// bind the viewmodel to the Mainpage
BindingContext = new ProductsViewModels();
}
//delete the item from the observablecollection
public void Remove_Clicked(object sender, EventArgs e)
{
var button = sender as Button;
var product = button.BindingContext as Products;
var vm = BindingContext as ProductsViewModels;
vm.RemoveCommand.Execute(product);
}
//add the new item to the observablecollection
private void Button_Clicked(object sender, EventArgs e)
{
var product = new Products()
{
Name =" new name",
Price = 100
};
var vm = BindingContext as ProductsViewModels;
vm.AddCommand.Execute(product);
}
}
}
Meeting collection must be somewhere initialized before calling any operation on collestion (be it on property level or in constructor):
public class AllMeetings
{
public ObservableCollection<Meeting> Meetings { get; } = new ObservableCollection<Meeting>();
public void Add_Meeting(Meeting meeting)
{
this.Meetings.Add(meeting);
}
}
And ListView must have some data template to tell UI how data should be presented:
<ListView ItemsSource="{Binding Meetings}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Label Text="{Binding Name}"/>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
I have already created all of the controls, and have tested that the controls are added as needed without using the binding.
The issue is as soon as I add the binding which is supposed to determine which control to add, the controls stop working as needed.
The list view control will be populated from a collection of a class, which will have an indicator field to determine which control needs to be loaded. The list view contains a 2nd user control which basically acts as a placeholder for the correct control, it has a bindable property of type text which is set to determine the correct control to be loaded.
Here is the XAML Code for the list view control
<ContentView.Content>
<StackLayout>
<Label Text="Binding Control Type"/>
<Entry x:Name="cntName"/>
<ListView x:Name="GroupedView" GroupDisplayBinding="{Binding Title}" HasUnevenRows="True" GroupShortNameBinding="{Binding ShortName}" IsGroupingEnabled="True">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<ViewCell.ContextActions>
<MenuItem Text="Add Comment"/>
<MenuItem Text="Add Attachment"/>
</ViewCell.ContextActions>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="3*"/>
<ColumnDefinition Width="7*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="3*"/>
<RowDefinition Height="7*"/>
</Grid.RowDefinitions>
<Label Text="{Binding QUESTION_ID}" Grid.Row="0" Grid.Column="0" VerticalTextAlignment="Center" FontSize="Medium"/>
<Label Text="{Binding QUESTION_DETAILS}" Grid.Row="1" Grid.Column="0" VerticalTextAlignment="Center" FontSize="Medium"/>
<con:ucListViewControls ControlType="{Binding QUESTION_ANSWERCONTROL}" Grid.Row="1" Grid.Column="1"/>
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
<ListView.GroupHeaderTemplate>
<DataTemplate>
<ViewCell>
<ViewCell.ContextActions>
<MenuItem Text="Add Comment"/>
<MenuItem Text="Add Attachment"/>
</ViewCell.ContextActions>
<StackLayout Orientation="Horizontal" Padding="5,5,5,5" BackgroundColor="#E2F5F9">
<StackLayout.GestureRecognizers>
<TapGestureRecognizer Command="{Binding Source={x:Reference this}, Path=Tapped}" CommandParameter="{Binding .}"/>
</StackLayout.GestureRecognizers>
<Button Image="{Binding StateIcon}" BackgroundColor="Transparent" BorderColor="Transparent" BorderWidth="0"/>
<Label Text="{Binding Title}" TextColor="#005569" FontSize="15" VerticalOptions="Center"/>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.GroupHeaderTemplate>
</ListView>
</StackLayout>
</ContentView.Content>
And the code behind for the control
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class ucExpandibleListView : ContentView
{
private ObservableCollection<dbQuestionGroup> _allGroups;
private ObservableCollection<dbQuestionGroup> _expandedGroups;
public ucExpandibleListView()
{
InitializeComponent();
Tapped = new Command(x => HeaderTapped(x));
_allGroups = new ObservableCollection<dbQuestionGroup>()
{
new dbQuestionGroup("Category 1", "C1", false)
{
new dbQuestionModel() { QUESTION_ID = 1, QUESTION_DETAILS = "Testing Question 1", QUESTION_ANSWERCONTROL = "RBL" },
new dbQuestionModel() { QUESTION_ID = 2, QUESTION_DETAILS = "Testing Question 2", QUESTION_ANSWERCONTROL = "" }
}
};
UpdateListContent();
}
private void UpdateListContent()
{
_expandedGroups = new ObservableCollection<dbQuestionGroup>();
foreach (dbQuestionGroup group in _allGroups)
{
dbQuestionGroup newGroup = new dbQuestionGroup(group.Title, group.ShortName, group.Expanded);
newGroup.QuestionCount = group.Count;
if (group.Expanded)
{
foreach (dbQuestionModel question in group)
{
newGroup.Add(question);
}
}
_expandedGroups.Add(newGroup);
}
GroupedView.ItemsSource = _expandedGroups;
}
public Command Tapped { get; set; }
private void HeaderTapped(object group)
{
var groupCat = (dbQuestionGroup)group;
int selectedIndex = _expandedGroups.IndexOf(groupCat);
if (groupCat.Expanded)
{
_allGroups[selectedIndex].Expanded = false;
}
else
{
_allGroups.ToList().ForEach(x => x.Expanded = false);
_allGroups[selectedIndex].Expanded = !_allGroups[selectedIndex].Expanded;
}
UpdateListContent();
}
}
Here is the XAML Code for the placeholder control
<ContentView.Content>
<StackLayout x:Name="stkPlaceholder">
</StackLayout>
</ContentView.Content>
And the code behind for the placeholder control
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class ucListViewControls : ContentView, INotifyPropertyChanged
{
public ucListViewControls()
{
InitializeComponent();
}
#region Control Attributes
public event PropertyChangedEventHandler PropertyChanged;
protected void NotifyPropertyChanged(string info)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(info));
}
#endregion
#region Bindable Properties
public static readonly BindableProperty ControlTypeProperty = BindableProperty.Create(nameof(ControlType), typeof(string), typeof(ucListViewControls));
public string ControlType
{
get
{
return (string)GetValue(ControlTypeProperty);
}
set
{
SetValue(ControlTypeProperty, value);
AddControl();
NotifyPropertyChanged("ControlType");
}
}
#endregion
public void AddControl()
{
switch (ControlType)
{
case "RBL":
ucRadiobuttons radiobuttons = new ucRadiobuttons();
radiobuttons.lblTitle1 = "Yes";
radiobuttons.lblTitle2 = "No";
radiobuttons.lblTitle3 = "N/A";
radiobuttons.OnColor1 = Color.Green;
radiobuttons.OnColor2 = Color.Red;
radiobuttons.OnColor3 = Color.Transparent;
stkPlaceholder.Children.Add(radiobuttons);
break;
default:
Entry placeholder = new Entry();
stkPlaceholder.Children.Add(placeholder);
break;
}
}
}
I have tested that the controls are added without the binding, which works perfectly.
I have tried to rewrite the bindable property multiple times in case I missed something, I also could not find any post relating to something similar which wouldve helped me.
Any clues?
The first screenshot shows the expected output, and the seconds screenshots shows what happens when the binding is applied.
dbQuestionModel:
using System.Collections.Generic;
namespace PivotMobile_BusinessLayer.Models
{
public class dbQuestionModel
{
public int QUESTION_PK { get; set; }
public int QUESTION_ID { get; set; }
public string QUESTION_CATEGORY { get; set; }
public string QUESTION_DETAILS { get; set; }
public string QUESTION_TYPE { get; set; }
public string QUESTION_ANSWERCONTROL { get; set; }
public string QUESTION_COMMENT { get; set; }
public List<string> QUESTION_ATTACHMENTS { get; set; }
}
}
dbQuestionGroup:
using System.Collections.ObjectModel;
using System.ComponentModel;
namespace PivotMobile_BusinessLayer.Models
{
public class dbQuestionGroup : ObservableCollection<dbQuestionModel>, INotifyPropertyChanged
{
public static ObservableCollection<dbQuestionGroup> All { private set; get; }
private bool _expanded;
public string Title { get; set; }
public string ShortName { get; set; }
public bool Expanded
{
get
{
return _expanded;
}
set
{
if (_expanded != value)
{
_expanded = value;
OnPropertyChanged("Expanded");
OnPropertyChanged("StateIcon");
}
}
}
public string StateIcon
{
get
{
return Expanded ? "expanded_blue.png" : "collapsed_blue.png";
}
}
public int QuestionCount { get; set; }
public dbQuestionGroup(string title, string shortName, bool expanded = true)
{
Title = title;
ShortName = shortName;
Expanded = expanded;
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}
ListView Page 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"
x:Class="PivotMobile.Views.ObservationsView"
xmlns:con="clr-namespace:PivotMobile.Controls">
<ContentPage.Content>
<StackLayout Margin="5">
<con:ucExpandibleListView/>
</StackLayout>
</ContentPage.Content>
</ContentPage>
ListView Page Code Behind:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
namespace PivotMobile.Views
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class ObservationsView : ContentPage
{
public ObservationsView ()
{
InitializeComponent ();
}
}
}
I have created view AddonPickerControl that is a horizontal StackLayout with AddonControls. The problem is that Pages that includes AddonPickerListView loads about 2sec, its too long.
I have tried to achive same result with binding addons to a ListView, but the problem is that each cell have to have a counter that describes how much specific addon has been picked. I have no Idea how to do this in ViewCell, so I decided to StackLayout.
public partial class AddonPickerControl : ContentView
{
public AddonPickerControl (AddonPicker addonPicker)
{
InitializeComponent ();
_addonPicker = addonPicker;
BindingContext = _addonPicker;
}
private readonly AddonPicker _addonPicker;
protected override void OnAppearing()
{
foreach (var addon in _addonPicker.AvailableAddons)
{
var addonControl = new AddonControl(addon);
addonControl.AddonPicked += OnAddonPicked;
AddonContainer.Children.Add(addonControl);
}
}
...
}
public partial class AddonControl : ContentView
{
public AddonControl (Addon addon)
{
InitializeComponent ();
_addon = addon;
this.BindingContext = _addon;
}
private readonly Addon _addon;
...
}
How should I display an AddonPickerControl? Filling StackLayout with other views takes too much time. Or maybe it is possible to create a ViewCell that will have a counter that describes how much binded addon has been picked.
Here is an example of how you can have buttons in every item in a list view to update a count for that item.
First, here is a simple list view with a view cell with 3 labels and two buttons:
<ListView x:Name="listView" ItemsSource="{Binding Items}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Orientation="Horizontal">
<Label Text="{Binding ItemName}" />
<Label Text="Count:" />
<Label Text="{Binding Count}" />
<Button Text="+" Command="{Binding BtnClickPlusCommand}" />
<Button Text="-" Command="{Binding BtnClickMinusCommand}" />
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Then in the code behind:
public partial class MainPage : ContentPage
{
public ObservableCollection<Item> Items { get; set; } = new ObservableCollection<Item>();
public MainPage()
{
InitializeComponent();
for (int i=1; i<11; i++)
{
Item item = new Item { ItemName = $"Item {i}", Count = "5" };
Items.Add(item);
}
BindingContext = this;
}
}
And the Item class which will have your click handlers and is a simple view model as it implements INotifyPropertyChanged:
public class Item : INotifyPropertyChanged
{
public string ItemName { get; set; }
int _count;
public ICommand BtnClickPlusCommand { get; private set; }
public ICommand BtnClickMinusCommand { get; private set; }
public Item()
{
BtnClickPlusCommand = new Command(btnClickPlus);
BtnClickMinusCommand = new Command(btnClickMinus);
}
void btnClickPlus()
{
Count = (++_count).ToString();
}
void btnClickMinus()
{
Count = (--_count).ToString();
}
public string Count
{
get
{
return _count.ToString();
}
set
{
int j;
if (Int32.TryParse(value, out j))
{
_count = j;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Count"));
}
else
Console.WriteLine("value could not be parsed to int");
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
So, in this case we have essentially created a view model for each item so we can have the command that will handle the button click in the actual Item object that is associated with the button, so we just have to update the count. And using bindings, the UI is updated automatically with the new count. The results:
I have model with 3 fields : TItle, Body, Status.
public class Names
{ [PrimaryKey]
public string Title { get; set; }
public string Body { get; set; }
public string Status{ get; set; }}
When user opens the page he can see list of names with fields (Title, Body).
Code of page looks like:
xaml.cs
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class HomePage : ContentPage
{
public ObservableCollection<Models.Names> items { get; set; }
public HomePage()
{
items = new ObservableCollection<Models.Names>();
this.BindingContext = this;
InitializeComponent();
List.ItemSelected += (sender, e) => {
((ListView)sender).SelectedItem = null;
};
List.Refreshing += (sender, e) => {
LoadUsersData();
};
LoadUsersData();
}
public async void LoadUsersData()
{
List.IsRefreshing = true;
var Names= await App.Database.Names.GetItemsAsync();
items.Clear();
foreach (var item in Names)
items.Add(item);
List.IsRefreshing = false;
}
}
xaml
<StackLayout>
<ListView x:Name="List"
HasUnevenRows="True"
ItemsSource="{Binding items}"
IsPullToRefreshEnabled="True">
<ListView.ItemTemplate>
<DataTemplate>
<TextCell
Text="{Binding Title}"
Detail="{Binding Body}"
TextColor="Black"
DetailColor="Gray">
</TextCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
In the begin of page I want to add string which shows amount of all items with Status = "New".
How I can do it?
Add a Label that binds to the Count property of your ObservableCollection (it will be notified each time items are added/deleted from your collection):
<Label Text="{Binding items.Count, StringFormat='Status = {0}'}"/>
Update
If you need custom properties, like the number of Names objects with a Status of "new", there are multiple ways to create bindable properties, but one way is to subclass ObservableCollection and add your custom property:
public class MyObservableCollection : ObservableCollection<Names>
{
public MyObservableCollection()
{
CollectionChanged += (object sender, NotifyCollectionChangedEventArgs e) =>
{
OnPropertyChanged(new PropertyChangedEventArgs("NewCount"));
};
}
public int NewCount
{
get { return this.Count((Names arg) => arg.Status == "new"); }
}
}
Now replace your use of ObservableCollection with MyObservableCollection.
public MyObservableCollection items { get; set; }
In your XAML, you can now bind on NewCount:
<Label Text="{Binding items.Count, StringFormat='Status = {0}'}"/>
<Label Text="{Binding items.NewCount, StringFormat='Status = {0}'}"/>
In terms using a BindableProperty instead, there are other SO question/answers already posted and a great blog post:
https://xamarinhelp.com/bindable-properties-xamarin-forms/
When I run the app, I get two tabs (Im using Tabbed Page) but they are blank.
I have a somewhat complex ViewModel:
public partial class NowPlayingView
{
const string NowPlayingUrl = "http://api.myserver.com";
public static List<MoviesItem> MoviesLst { get; set; }
public NowPlayingView()
{
InitializeComponent();
BindingContext = new MoviesViewModel();
}
public class MoviesViewModel
{
public MoviesViewModel()
{
Action<Dictionary<string, string>> initAction = initialize;
initAction(new Dictionary<string, string>()
{
{"$format", "json"},
{"AccessKey", "f54tg5gf54g-fgs3452-324asdf4"},
{"CineplexLanguage", "en-us"}
});
}
public async void initialize(Dictionary<string,string> parameters)
{
var data = await (new ApiUtilities().CallGetData<MoviesNowPlaying>(NowPlayingUrl, "/api.svc/MoviesNowPlaying", parameters));
MoviesLst = data.d.results.Select(x => new MoviesItem() {Header = x.Title, Text = x.MediumPosterImageURL}).ToList();
}
}
public class MoviesItem
{
public string Header { get; set; }
public string Text { get; set; }
}
}
My XAML file look like this:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="XamPlex.MainCategories.NowPlayingView"
Title="Now Playing">
<ListView x:Name="MoviesListView" RowHeight="80" BackgroundColor="Transparent" ItemsSource="{Binding MoviesLst}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<ViewCell.View>
<StackLayout Orientation="Vertical" Spacing="0" Padding="10">
<Label Font="Bold,20" Text="{Binding Header}" TextColor="Indigo"/>
<Label Font="16" Text="{Binding Text}" TextColor="Indigo"/>
</StackLayout>
</ViewCell.View>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</ContentPage>
I checked the contents of MoviesLst and it contains plenty of data, any ideas what could be wrong?
I do not do a lot of MVC, but I believe the View should have this form:
public ActionResult Index() {
return View();
}
I would think your View should be structured something like...
public ActionResult Index() {
var data = await (new ApiUtilities().CallGetData<MoviesNowPlaying>(NowPlayingUrl, "/api.svc/MoviesNowPlaying", parameters));
var list = data.d.results.Select(x => new MoviesItem() {Header = x.Title, Text = x.MediumPosterImageURL}).ToList();
return View(list);
}
Again, though, I have only worked through the basic tutorials on MVC. I could be misunderstanding your model.
I don't see where you are posting your View anywhere. What I see appears to be the Model.