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.
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 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; }
}
I'm very new to Xamarin.Forms and MVVM and posting questions here on StackOverflow so bear with me please. I'm trying to fill a listview in Xamarin.Forms. I first programmed it without MVVM and it all worked like I wanted it to, but now I wanted to get in in MVVM and that is where it went wrong, now my list won't fill up anymore.
I made a viewmodel and only put all the binding in the viewmodel, I have not yet implemented eventhandlers.
This is a part of the code behind (I have a couple more eventhandlers but that is not relevant right now):
namespace CCXamarinApp
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class PatientsWithTagPage : ContentPage
{
public PatientsWithTagPage()
{
BindingContext = new PatientsWithTagViewModel();
InitializeComponent();
(BindingContext as PatientsWithTagViewModel).GetAllPatients();
if((BindingContext as PatientsWithTagViewModel).IsEmptyPatientList)
HandleEmptyList();
else
(BindingContext as PatientsWithTagViewModel).SortAndShowPatients();
}
private void SearchBar_OnTextChanged(object sender, TextChangedEventArgs e)
{
(BindingContext as PatientsWithTagViewModel).Searching(e.NewTextValue);
}
...
This is my XAML page:
<SearchBar x:Name="SearchBar" Placeholder="Zoek op naam of plaats..." HeightRequest="25" Margin="10"
TextChanged="SearchBar_OnTextChanged"/>
<Label Text="{Binding LastRefreshed}" FontAttributes="Italic" FontSize="15" />
<Label x:Name="LabelEmptyList" FontSize="17" Text="Geen gegevens gevonden" FontAttributes="Bold"
IsVisible="False" />
<ListView x:Name="PatientListView" HasUnevenRows="True" SeparatorColor="Accent"
VerticalOptions="FillAndExpand" IsPullToRefreshEnabled="True" IsRefreshing="{Binding IsFetchingData, Mode=TwoWay}"
Refreshing="PatientListView_OnRefreshing" SelectedItem="{Binding SelectedPatient, Mode=TwoWay}"
ItemSelected="PatientListView_OnItemSelected" ItemsSource="{Binding Patients}"
IsVisible="True" BackgroundColor="Aqua">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Spacing="4">
<StackLayout Orientation="Horizontal" Margin="10,7,10,1">
<Label Text="{Binding FullName}" FontAttributes="Bold" FontSize="16" />
<Label Text="{Binding DisplayTimeOfLastScan, StringFormat='{0}'}"
HorizontalOptions="EndAndExpand" />
</StackLayout>
<StackLayout Orientation="Horizontal" Margin="10,0,10,7">
<Label Text="{Binding LastLocation}" HorizontalOptions="Start" />
<Label Text="{Binding DisplayDurationSinceLastScan, StringFormat='al {0}'}"
HorizontalOptions="EndAndExpand" />
</StackLayout>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</ContentPage.Content>
This is my viewmodel (not all the code but the code that is most relevant). The BaseViewModel it derives from is from the nuget package "Refractored.Mvvmhelpers":
class PatientsWithTagViewModel : BaseViewModel
{
public ObservableCollection<PatientViewModel> Patients { get; private set; } = new ObservableCollection<PatientViewModel>();
private PatientViewModel selectedPatient;
public PatientViewModel SelectedPatient
{
get => selectedPatient;
set => SetProperty(ref selectedPatient, value);
}
private readonly JsonSerializerSettings jsonSerializerSettings = new JsonSerializerSettings
{
DateFormatString = "dd-MM-yyyTH:mm",
DateTimeZoneHandling = DateTimeZoneHandling.Utc,
};
public bool IsEmptyPatientList => Patients.Count == 0;
private string testJson = "[{\"firstName\":\"P.\",\"lastName\":\"Selie\",\"tag\":{\"tagId\":\"124\",\"tagSerialNumber\":\"ABC135\"},\"scans\":[{\"location\":\"Tuin\",\"dateTime\":\"May01,2018,10:10\"},{\"location\":\"Eetzaal\",\"dateTime\":\"May02,2018,10:15\"},{\"location\":\"Gang\",\"dateTime\":\"May02,2018,11:10\"},{\"location\":\"Kamer23\",\"dateTime\":\"May02,2018,12:09\"}],\"id\":\"dcc4fe9929b3681f\"}," +
"{\"firstName\":\"W.\",\"lastName\":\"Janssens\",\"tag\":{\"tagId\":\"132\",\"tagSerialNumber\":\"ABC167\"},\"scans\":[{\"location\":\"Kamer23\",\"dateTime\":\"May01,2018,23:39\"},{\"location\":\"Gang\",\"dateTime\":\"May02,2018,04:10\"},{\"location\":\"Eetzaal\",\"dateTime\":\"May02,2018,04:11\"},{\"location\":\"Gang\",\"dateTime\":\"May02,2018,04:20\"},{\"location\":\"Kamer23\",\"dateTime\":\"May02,2018,04:22\"}],\"id\":\"a6dac28475327922\"}]";
public void GetAllPatients()
{
IsFetchingData = true;
try
{
Patients = new ObservableCollection<PatientViewModel>(
JsonConvert.DeserializeObject<ObservableCollection<PatientViewModel>>(testJson,
jsonSerializerSettings));
}
catch(Exception e)
{
Console.WriteLine("*****ERROR kon API niet ophalen");
Console.WriteLine(e.Message);
}
finally
{
IsFetchingData = false;
}
}
This is the model I use:
public class Patient : ObservableObject
{
public string FirstName { get; set; }
public string LastName { get; set; }
public Tag Tag { get; set; }
public List<Scan> Scans { get; set; }
public string Id { get; set; }
public override string ToString()
{
return LastName + ", " + FirstName;
}
}
It also has its own viewmodel with properties like DisplayDurationSinceLastScan, but I don't think it is relevant here, if you think it is, let me know.
So with this code I get my page but there seems to be no items in the list, if I debug, Patients is filled with items so it is not empty at all, but something goes wrong with the binding I guess but no error is given.
Here is a picture of what I get: the listview is shown (I added a blue background so I would know if the listview was visible or not), but there are no items in there. Still Patients is filled when I debug the app.
Does someone see the mistake I made?
I see some issues with your code here from a maintainability point of view. Try to keep all your code inside the view model instead of both the view model and code behind. Ideally, your code behind contains nothing and if anything it strictly has to do with visual things.
Anyway, in regard to you problem: you are creating a new ObservableCollection each time. That breaks the binding. Just keep the new ObservableCollection at the top and then when new data comes in, clear that and repopulate it. Like this:
public void GetAllPatients()
{
IsFetchingData = true;
try
{
var resultPatients = JsonConvert.DeserializeObject<ObservableCollection<PatientViewModel>>(testJson, jsonSerializerSettings);
Patients.Clear();
foreach (var patient in resultPatients)
Patients.Add(patient);
}
catch(Exception e)
{
Console.WriteLine("*****ERROR kon API niet ophalen");
Console.WriteLine(e.Message);
}
finally
{
IsFetchingData = false;
}
}
Your data should now show up.
I'm trying to understand the issue of this, bit it doens't work at all...
So what I'm trying to do is to make an menu with a listview as it's content. Now, I have the view, with binding properties, and I have a class in which I make the list. Here is the code:
public class MenuList
{
public ImageSource Icon { get; set; }
public String Title { get; set; }
// Initialize the Pokemon object thing :p
//public MenuList() { }
// Here we make the pokemon list :D
public static List<MenuList> GetMenuItems()
{
return new List<MenuList>()
{
new MenuList() { Icon="RadioApp.Assets.Icons_menu.account.png", Title="Radio" },
new MenuList() { Icon="RadioApp.Assets.Icons_menu.account.png", Title="Shout/request lijn" },
new MenuList() { Icon="RadioApp.Assets.Icons_menu.account.png", Title="Rooster" },
new MenuList() { Icon="RadioApp.Assets.Icons_menu.account.png", Title="Geschiedenis" },
new MenuList() { Icon="RadioApp.Assets.Icons_menu.account.png", Title="Medewerkers" },
new MenuList() { Icon="RadioApp.Assets.Icons_menu.account.png", Title="Over deze app" },
};
}
}
<ListView x:Name="menuItemsLVW" Grid.Row="0">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout>
<StackLayout Orientation="Horizontal">
<Image Source="{Binding Icon}" />
<Label Text="{Binding Title}" TextColor="Black" />
</StackLayout>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Now, I get the errors : [0:] Binding: 'Icon' property not found on 'RadioApp.Model.MenuList', target property: 'Xamarin.Forms.Image.Source'
I have no idea why it returns the error, because as far as I can see, tis should work?
The class I generate the page:
public partial class Menu : ContentPage
{
private List<MenuList> lstOfAllMenuItems;
public Menu()
{
InitializeComponent();
lstOfAllMenuItems = MenuList.GetMenuItems();
menuItemsLVW.ItemsSource = lstOfAllMenuItems;
//Debug.WriteLine(lstOfAllMenuItems[0].Title);
//Debug.WriteLine(lstOfAllMenuItems[0].Icon);
}
}
If I do the debug, it just returns the correct item...