How to bind values from viewmodel to listview - xaml

I have ViewModel with proporties and method to populate values:
public class MRateReportViewModel : HeaderViewModel
{
public ICommand ChangeReportPeriodCommand { get; }
public ICommand BackToHomePageCommand { get; }
public string Hashtag { get; set; }
public string Rating { get; set; }
public decimal? mTP { get; set; }
public string Image { get; set; }
public string Date { get; set; }
public DateTime MinimumDate { get; set; }
public DateTime MaximumDate { get; set; }
public DateTime PickedDate { get; set; }
public ObservableCollection<UserEventModel> UserEventsCollection { get; set; }
private UserEventsModel userEventsModel;
private ObservableCollection<EventTypeAtributtes> EventTypes;
public string EventType;
public List<String> EvtList { get; set; }
public MRateReportViewModel()
{
UserEventsCollection = new ObservableCollection<UserEventModel>();
userEventsModel = new UserEventsModel();
ChangeReportPeriodCommand = new Command((dailyOrTotal) => ChangeReportPeriod(dailyOrTotal.ToString()));
BackToHomePageCommand = new Command(() => BackToHomePage());
InitData();
}
private async void InitData()
{
ShowDialog();
userEventsModel = await EventService.GetEvents();
EventTypes = await EventService.GetEventType();
foreach (var item in userEventsModel.Events)
{
UserEventsCollection.Add(item);
}
HideDialog();
Page++;
}
}
By debugging I checked EventDetails methods and proporties get correct values.
In View I have page with ListView which I should populate with values from viewmodel:
<ListView ItemsSource="{Binding EventsList}"
CachingStrategy="RecycleElement"
x:Name="EventsDiary"
ItemAppearing="EventsDiary_ItemAppearing"
SelectionMode="None"
HasUnevenRows="True"
Margin="0,0,0,10">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<material:MaterialCard HorizontalOptions="FillAndExpand"
VerticalOptions="FillAndExpand"
CornerRadius="2"
Margin="10,0,10,15"
HeightRequest="178"
Padding="0"
BackgroundColor="#f4f4f4">
<Grid RowSpacing="0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto" />
<ColumnDefinition Width="auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="auto" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="6" />
<RowDefinition Height="auto" />
<RowDefinition Height="auto" />
<RowDefinition Height="auto" />
<RowDefinition Height="auto" />
</Grid.RowDefinitions>
<BoxView Grid.Column="0"
Grid.ColumnSpan="5"
Grid.Row="0"
BackgroundColor="{StaticResource CustomizedRedColor}"
CornerRadius="4"
Margin="0" />
<RelativeLayout Grid.Column="0"
Grid.Row="1"
Margin="10,10,0,0">
<controls:CircleImage HeightRequest="90"
WidthRequest="90"
Source="serpa1.png"
Aspect="AspectFill">
</controls:CircleImage>
<material:MaterialCard HeightRequest="30"
WidthRequest="30"
CornerRadius="50"
BackgroundColor="#525252"
Margin="0"
Padding="0"
Opacity="0.9">
<Label Text="1"
TextColor="White"
HorizontalOptions="CenterAndExpand"
VerticalOptions="CenterAndExpand" />
</material:MaterialCard>
</RelativeLayout>
<StackLayout Grid.Column="1"
Grid.ColumnSpan="3"
Grid.Row="1"
Padding="0"
Margin="0"
Orientation="Vertical"
Spacing="0">
<Label Text="Ključne reči"
FontSize="18"
Margin="0,5,0,0"
TextColor="#03414e"
FontFamily="{StaticResource BalooBhai}" />
<Label Text="{Binding Hashtag}"
FontSize="12"
Margin="0"
VerticalOptions="StartAndExpand"
TextColor="#030303" />
This is part of xaml code. In this example I should bind Hashtag value but it just remain blank.
Here is my service for UserEventsModel:
public static async Task<UserEventsModel> GetEvents()
{
UserEventsModel userEventModel = new UserEventsModel();
try
{
//string url = UrlConstants.GET_USER_EVENTS;
string url = UrlConstants.USER_DIARY;
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.TryAddWithoutValidation("Cookie", LocalDataHelper.RestoreCookie());
string content = Newtonsoft.Json.JsonConvert.SerializeObject(userEventModel);
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
using (var result = await client.PostAsync(url, new StringContent(content, Encoding.UTF8, "application/json")))
{
string resultContent = await result.Content.ReadAsStringAsync();
if (result.StatusCode == System.Net.HttpStatusCode.OK)
{
userEventModel = (UserEventsModel)JsonConvert.DeserializeObject<UserEventsModel>(resultContent);
}
}
}
}
catch (Exception ex)
{
throw;
}
return userEventModel;
}

Do your class or base class implements the INotifyPropertyChanged interface?
like this:
public abstract class BaseViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new
PropertyChangedEventArgs(propertyName));
}
}
public class YOURViewModel : BaseViewModel
{
private string _Hashtag;
public string Hashtag
{
get { return _Hashtag; }
set { _Hashtag = value; OnPropertyChanged(); }
}
}

According to your code, you want to bind ViewModel to ListView, firstly, you should need to know ListView is collection control, so you shoule bind collection to ListView's itemsource.
From your code, you want to use EventsList to bind ListView, but I don't see where you populate data into EventsList?
I see there is userEventsModel ViewModel, Events collection in this, but why you foreach this collection?
I change you Viewmodel to do one sample for you, please take a look:
public partial class Page9 : ContentPage
{
public ObservableCollection<UserEventModel> EventsList { get; set; }
public Page9 ()
{
InitializeComponent ();
//populate data in collection EventsList.
EventsList = new ObservableCollection<UserEventModel>()
{
new UserEventModel(){Hashtag="test1",Rating="test1",mTP=0, Image="test1",Date="test1"}
};
this.BindingContext = this;
}
}
public class UserEventModel
{
public string Hashtag { get; set; }
public string Rating { get; set; }
public decimal? mTP { get; set; }
public string Image { get; set; }
public string Date { get; set; }
}
The ListView is in Page 9,
<ListView ItemsSource="{Binding EventsList}"
CachingStrategy="RecycleElement"
x:Name="EventsDiary"
ItemAppearing="EventsDiary_ItemAppearing"
SelectionMode="None"
HasUnevenRows="True"
Margin="0,0,0,10">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<material:MaterialCard HorizontalOptions="FillAndExpand"
VerticalOptions="FillAndExpand"
CornerRadius="2"
Margin="10,0,10,15"
HeightRequest="178"
Padding="0"
BackgroundColor="#f4f4f4">
<Grid RowSpacing="0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto" />
<ColumnDefinition Width="auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="auto" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="6" />
<RowDefinition Height="auto" />
<RowDefinition Height="auto" />
<RowDefinition Height="auto" />
<RowDefinition Height="auto" />
</Grid.RowDefinitions>
<BoxView Grid.Column="0"
Grid.ColumnSpan="5"
Grid.Row="0" BackgroundColor="{StaticResource CustomizedRedColor}"
CornerRadius="4"
Margin="0" />
<RelativeLayout Grid.Column="0"
Grid.Row="1"
Margin="10,10,0,0">
<controls:CircleImage HeightRequest="90"
WidthRequest="90"
Source="serpa1.png"
Aspect="AspectFill">
</controls:CircleImage>
<material:MaterialCard HeightRequest="30"
WidthRequest="30"
CornerRadius="50"
BackgroundColor="#525252"
Margin="0"
Padding="0"
Opacity="0.9">
<Label Text="1"
TextColor="White"
HorizontalOptions="CenterAndExpand"
VerticalOptions="CenterAndExpand" />
</material:MaterialCard>
</RelativeLayout>
<StackLayout Grid.Column="1"
Grid.ColumnSpan="3"
Grid.Row="1"
Padding="0"
Margin="0"
Orientation="Vertical"
Spacing="0">
<Label Text="Ključne reči"
FontSize="18"
Margin="0,5,0,0"
TextColor="#03414e"
FontFamily="{StaticResource BalooBhai}" />
<Label Text="{Binding Hashtag}"
FontSize="12"
Margin="0"
VerticalOptions="StartAndExpand"
TextColor="#030303" />
</StackLayout>
</Grid>
</material:MaterialCard>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
There are one article about bind to ListView, you can take a look:
https://learn.microsoft.com/en-us/xamarin/xamarin-forms/user-interface/listview/data-and-databinding
https://almirvuk.blogspot.com/2017/02/xamarinforms-listview-simple-mvvm.html

Related

Saving with SQL

Hi all I have a page that I'm trying to ADD to a list and save it with viewmodel and SQL. but my list is empty Can you tell me where am I wrong??
on my Xaml (Page1):
<Entry Margin="5" Text="{Binding Xname}" Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2" FontSize="16" x:Name="entry1" Placeholder="Enter X-rays (6 MV)" PlaceholderColor="White" BackgroundColor="Gray"/>
<Button Grid.Column="0"
Grid.Row="2"
FontAttributes="Bold"
Command="{Binding AddXrayCommand}"
Text="Add" />
<ListView Grid.Row="3" Grid.ColumnSpan="2" HasUnevenRows="True" Margin="40"
ItemsSource="{Binding energyX}" SelectedItem="{Binding selecteditemX}"
HorizontalOptions="Start" WidthRequest="150" >
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="30"></RowDefinition>
<RowDefinition Height="5"></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
</Grid.ColumnDefinitions>
<Label Grid.Row="0" BackgroundColor="White" Text="{Binding xray}" FontSize="Large" HorizontalTextAlignment="Center" TextColor="Black" WidthRequest="35"/>
<Frame Grid.Row="1" BackgroundColor="Gray"></Frame>
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
my Model (Energypage):
public class EnergyX
{
[PrimaryKey, AutoIncrement]
public int Id { get; set; }
public string xray { get; set; }
}
And on my EnergyViewModel:
public class EnergyViewModel
{
public SQLiteConnection conn;
public ObservableCollection<EnergyX> energyX { get; set; } = new ObservableCollection<EnergyX>();
public string Xname { get; set; }
public ICommand AddXrayCommand => new Command(AddX);
public SQLiteConnection GetSQLiteConnection()
{
var fileName = "Energys.db";
var documentPath = System.Environment.GetFolderPath(System.Environment.SpecialFolder.LocalApplicationData);
var path = Path.Combine(documentPath, fileName);
var connection = new SQLiteConnection(path);
return connection;
}
public void AddX()
{
if (Xname != null && Xname.Length > 0)
{
EnergyX XX = new EnergyX();
XX.xray = Xname;
conn = GetSQLiteConnection();
conn.CreateTable<EnergyX>();
var dataX = conn.Table<EnergyX>();
var resultX = conn.Insert(XX);
energyX = new ObservableCollection<EnergyX>(conn.Table<EnergyX>().ToList());
}
}
}
}
I did bond my page1 to Energyviewmodel, and it works find when I didn't use SQL service, I think my SQL has problem...
I have debug the viewmodel and program run to the end of the Viewmodel but my xaml page list is empty.
this line creates a completely new instance of energyX when your ListView is bound to the old instance
energyX = new ObservableCollection(conn.Table().ToList());
there are two ways you could fix this
option 1, use INotifyPropertyChanged and raise a PropertyChanged event in the setter of energyX
option 2, don't create a new instance of energyX. Instead just add the new item to the existing instance
energyX.Add(XX);

Stacklayout Inside Stackedlayout Binding IsVisible

I have a xaml view that is a simple listview which has a couple of stackedlayouts in the cells along with some simple binding of my model:
<?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:directory="clr-namespace:Directory;assembly=Directory"
xmlns:d="http://xamarin.com/schemas/2014/forms/design"
xmlns:models="clr-namespace:Directory.Models"
xmlns:controls="clr-namespace:ImageCircle.Forms.Plugin.Abstractions;assembly=ImageCircle.Forms.Plugin.Abstractions"
xmlns:viewModels="clr-namespace:Directory.ViewModels;assembly=Directory"
x:Class="Directory.Views.DirectoryList">
<ContentPage.BindingContext>
<viewModels:MasterViewModel/>
</ContentPage.BindingContext>
<ListView Margin="0,10"
ItemTapped="ListViewItem_Tabbed"
ItemsSource="{Binding PeopleCollectionGrouped}"
IsGroupingEnabled="True"
GroupDisplayBinding="{Binding Key}"
GroupShortNameBinding="{Binding Key}"
HasUnevenRows="True"
BackgroundColor="White">
<ListView.ItemTemplate>
<DataTemplate x:DataType="models:People">
<ViewCell>
<Grid
Padding="10"
ColumnSpacing="10"
RowSpacing="10">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<controls:CircleImage
Aspect="AspectFill"
BorderColor="Black"
BorderThickness="3"
HeightRequest="66"
HorizontalOptions="CenterAndExpand"
Source="{Binding PhotoUrl}"
VerticalOptions="CenterAndExpand"
WidthRequest="66" />
<StackLayout Grid.Column="1" VerticalOptions="Center">
<Label Text="{Binding FullName}" />
<Label Text="{Binding Location}" />
<StackLayout IsVisible="{Binding IsVisible}"
Orientation="Horizontal"
Margin="0,0,80,0">
<Button Text="Place Order"
WidthRequest="110"
FontSize="15"
BackgroundColor="Chocolate"
TextColor="White"/>
</StackLayout>
</StackLayout>
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
All the bindings work apart from the IsVisible binding which causes the app to crash with:
System.InvalidProgramException: Invalid IL code
If I change my Xaml so that the IsVisible property is not binded and just set to "True" then it compiles and loads.
I have no idea why this isn't working as the other values from the model are binded correctly.
Here is the People model, which "PeopleCollectionGrouped" is of:
public class People
{
[JsonProperty("photo_url")]
public string PhotoUrl { get; set; }
[JsonProperty("location")]
public string Location { get; set; }
[JsonProperty("id")]
public string Id { get; set; }
[JsonProperty("first_name")]
public string FirstName { get; set; }
[JsonProperty("middle_name")]
public string MiddleName { get; set; }
[JsonProperty("last_name")]
public string LastName { get; set; }
public string FullName => $"{FirstName} {LastName}";
public string NameSort
{
get
{
if (string.IsNullOrWhiteSpace(FullName) || FullName.Length == 0)
{
return "?";
}
return FullName[0].ToString().ToUpper();
}
}
public bool IsVisible { get; set; }
}
If anyone can spot where i have gone wrong it would help

How to bind image source to dynamic changable property?

I'm trzuying to show diferent images in ListView frames, depending of ServiceName in my model.
So here is my model:
public class IrrigNetModelItem
{
public int ID { get; set; }
public string Message { get; set; }
public DateTime Date { get; set; }
public string DateText { get; set; }
public int StationId { get; set; }
public string StationName { get; set; }
public float StationLongitude { get; set; }
public float StationLatitude { get; set; }
public int ServiceId { get; set; }
public string ServiceName { get; set; }
}
And here is part of ViewModel
public ObservableCollection<IrrigNetModelItem> IrrigNetCollection { get; set; } = new ObservableCollection<IrrigNetModelItem>();
public async void GetData()
{
base.OnAppearing();
dialog.Show();
var token = LocalData.Token;
var data = await IrrigNetService.GetServices(token, "en");
var irrigNetModel = new IrrigNetModelItem();
foreach (var d in data.items)
{
IrrigNetCollection.Add(d);
if (d.ServiceName == "irrigNET")
{
IrrigCounter++;
//FrameImage = "service_irrig_img.png";
//FrameHeaderColor = Color.FromHex("#33A8F7");
}
else
{
AlertCounter++;
//FrameImage = "alert.png";
//FrameHeaderColor = Color.FromHex("#2BB24B");
}
}
dialog.Hide();
}
For now, Service name could be "irrigNET" and "alertNET" and depending of that I want to set diferent image source in my ListView in View.
Here is View:
<ListView
ItemsSource="{Binding IrrigNetCollection}"
IsVisible="{Binding IsListVisible}"
ItemSelected="FrameList_ItemSelected"
HasUnevenRows="False"
x:Name="FrameList"
Grid.Row="2"
RowHeight="190"
Margin="0,0,0,20"
SeparatorVisibility="None"
HeightRequest="0">
<ListView.ItemTemplate Padding="0">
<DataTemplate>
<ViewCell>
<Frame
HasShadow="True"
Grid.ColumnSpan="5"
HorizontalOptions="FillAndExpand"
VerticalOptions="FillAndExpand"
BackgroundColor="#f4f4f4"
BorderColor="LightGray"
CornerRadius="10"
Margin="25,10,25,10"
Padding="0">
<Grid
VerticalOptions="FillAndExpand"
HorizontalOptions="FillAndExpand"
IsEnabled="True">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="5"/>
<ColumnDefinition Width="40"/>
<ColumnDefinition Width="20"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="20"/>
<ColumnDefinition Width="5"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="13"/>
<RowDefinition Height="35"/>
<RowDefinition Height="*"/>
<RowDefinition Height="30"/>
</Grid.RowDefinitions>
<BoxView Color="{Binding Path=BindingContext.FrameHeaderColor, Source={x:Reference FrameList}}"
Grid.Row="0"
Grid.ColumnSpan="6"
HorizontalOptions="FillAndExpand"
VerticalOptions="StartAndExpand"/>
<Image Source="{Binding Path=BindingContext.FrameImage, Source={x:Reference FrameList}}"
Grid.Column="1"
Grid.Row="1"
Grid.RowSpan="3"
Margin="0,20,0,0"/>
<Image Source="{Binding Path=BindingContext.FrameIcon, Source={x:Reference FrameList}}"
Grid.Column="2"
Grid.Row="1"
HorizontalOptions="Start"
VerticalOptions="Center"
HeightRequest="17"
WidthRequest="17"/>
<Label
Text="{Binding StationName}"
VerticalTextAlignment="Start"
HorizontalTextAlignment="Start"
HorizontalOptions="Start"
VerticalOptions="Center"
Margin="3,3,0,0"
FontSize="18"
Grid.Column="3"
Grid.Row="1"
FontFamily="{StaticResource BalooBhai}"
TextColor="#262f41"/>
<Image Source="service_arrow.png"
Grid.Column="4"
Grid.Row="2"
VerticalOptions="Center"
HorizontalOptions="Center"
HeightRequest="18"
WidthRequest="18"/>
<Image Source="clock.png"
Grid.Column="2"
Grid.Row="3"
HorizontalOptions="Start"
VerticalOptions="Center"/>
<Label Text="{Binding DateText}"
FontSize="14"
FontFamily="{StaticResource SegoeUIB}"
Grid.Column="3"
Grid.Row="3"
HorizontalTextAlignment="Start"
VerticalTextAlignment="Start"
Margin="3,0,0,0"
TextColor="#262f41"/>
<Label Text="{Binding Message}"
Grid.Column="3"
Grid.Row="2"
VerticalTextAlignment="Start"
HorizontalOptions="Center"
VerticalOptions="Center"
FontFamily="{StaticResource SegoeUI}" FontSize="13"
TextColor="#262f41"
Margin="0,0,10,0"/>
</Grid>
</Frame>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
<ListView.GroupHeaderTemplate>
<DataTemplate>
<ViewCell Height="40">
<StackLayout Orientation="Horizontal"
BackgroundColor="#3498DB"
VerticalOptions="FillAndExpand">
<Label Text="TeStIrAnjE"
TextColor="White"
VerticalOptions="Center" />
<Button Text="Edit"
TextColor="White"
FontSize="20"/>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.GroupHeaderTemplate>
</ListView>
You'll se what I tried in Image tags, but for now any image ar not show.
This is proporties that I try to use in my ViewModel:
//public string FrameIrrigImage { get; set; } //= "service_irrig_img.png";
//public Color FrameIrrigHeaderColor { get; set; } //= Color.FromHex("#33A8F7");
//public string FrameAlertImage { get; set; } //= "alert.png";
//public Color FrameAlertHeaderColor { get; set; } // = Color.FromHex("#2BB24B");
//public string typeNet { get; set; }
//public Color typeNETcolortext { get; set; }
//public Color allertNETcolortext { get; set; }
This is what I want to achive:
But this is what I get:
(As you can see BoxView heder is also diferent color blue/color but I will get it how to change it on Image example)
Also I tried to achive it using properties:
public string FrameImage { get; set; }
public Color FrameHeaderColor { get; set; }
Set them values in for loop and Bind them in xaml, but then it's all set (image and color) as for the last element in ListView
As Jason said, there are two way to do this, one is use IValueConverter by ServiceName, another is add FrameImage in model, then change FrameImage by serviceName.
I do one simple that you can take a look,if you add FrameImage in model, please implement INotifyPropertyChanged interface.
<ContentPage
x:Class="App4.Page9"
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:converter="clr-namespace:App4">
<ContentPage.Resources>
<converter:convert1 x:Key="converterimage" />
</ContentPage.Resources>
<ContentPage.Content>
<StackLayout>
<ListView ItemsSource="{Binding model2s}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Orientation="Horizontal">
<Label Text="{Binding firstname}" />
<Image Source="{Binding imagepath}" />
<Image Source="{Binding Id, Converter={StaticResource converterimage}}" />
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</ContentPage.Content>
public partial class Page9 : ContentPage
{
public ObservableCollection<model2> model2s { get; set; }
public Page9 ()
{
InitializeComponent ();
model2s = new ObservableCollection<model2>()
{
new model2(){Id=1,firstname="cherry"},
new model2(){Id=2,firstname="mattew"},
new model2(){Id=3,firstname="annine"},
new model2(){Id=4,firstname="barry"}
};
foreach(model2 m in model2s)
{
if(m.Id%2==0)
{
m.imagepath = "a1.jpg";
}
else
{
m.imagepath = "a2.jpg";
}
}
this.BindingContext = this;
}
}
public class model2:ViewModelBase
{
public int Id { get; set; }
public string firstname { get; set; }
private string _imagepath;
public string imagepath
{
get { return _imagepath; }
set
{
_imagepath = value;
RaisePropertyChanged("imagepath");
}
}
}
Converter:
class convert1 : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
int id = (int)value;
if(id%2==0)
{
return "a1.jpg";
}
else
{
return "a2.jpg";
}
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}

Refresh data in TabbedPage using MVVM

I have a TabbedPage where I add entries and in the other tabs I list data. How can I refresh the data after I've added an entry to database using MVVM?
MainPage:
<?xml version="1.0" encoding="utf-8" ?>
<TabbedPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:myMood.Views"
x:Class="myMood.Views.MainPage"
BackgroundImage="logo.png">
<local:Register></local:Register>
<local:Entries></local:Entries>
<local:Statistics></local:Statistics>
<local:Settings></local:Settings>
<local:About></local:About>
</TabbedPage>
Entries:
<?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="myMood.Views.Entries"
Icon="ic_view_headline_white_24dp.png"
xmlns:viewModels="clr-namespace:myMood.ViewModels">
<ContentPage.BindingContext>
<viewModels:EntriesViewModel />
</ContentPage.BindingContext>
<ListView ItemsSource="{Binding MoodEntries}"
HasUnevenRows="True"
Margin="20">
<ListView.Header>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="30*" />
<ColumnDefinition Width="50*" />
<ColumnDefinition Width="50*" />
<ColumnDefinition Width="50*" />
</Grid.ColumnDefinitions>
<Image Source="ic_date_range_black_24dp.png" Grid.Column="0" Grid.Row="0" HorizontalOptions="Center"></Image>
<Image Source="ic_local_hotel_black_24dp.png" Grid.Column="1" Grid.Row="0" HorizontalOptions="Center"></Image>
<Image Source="ic_directions_run_black_24dp.png" Grid.Column="2" Grid.Row="0" HorizontalOptions="Center"></Image>
<Image Source="ic_done_all_black_24dp.png" Grid.Column="3" Grid.Row="0" HorizontalOptions="Center"></Image>
</Grid>
</ListView.Header>
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="30*" />
<ColumnDefinition Width="50*" />
<ColumnDefinition Width="50*" />
<ColumnDefinition Width="50*" />
</Grid.ColumnDefinitions>
<Label Text="{Binding EntryDate, StringFormat='{0:d/M}'}" Grid.Column="0" Grid.Row="0" HorizontalOptions="Center"></Label>
<Label Text="{Binding Sleep, StringFormat='{0:0.0}'}" Grid.Column="1" Grid.Row="0" HorizontalOptions="Center"></Label>
<Label Text="{Binding Stress, StringFormat='{0:0.0}'}" Grid.Column="2" Grid.Row="0" HorizontalOptions="Center"></Label>
<Label Text="{Binding AchivedGoals, StringFormat='{0:0.0}'}" Grid.Column="3" Grid.Row="0" HorizontalOptions="Center"></Label>
<Label Text="{Binding Comment, StringFormat='{0:0.0}'}" Grid.Column="0" Grid.ColumnSpan="4" Grid.Row="1"></Label>
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</ContentPage>
ViewModel:
using myMood.Models;
using System;
using System.Collections.Generic;
using System.Text;
namespace myMood.ViewModels
{
public class EntriesViewModel
{
public List<MoodEntry> MoodEntries { get; set; }
public EntriesViewModel()
{
MoodEntries = App.MoodDatabase.GetMoodEntries();
}
}
}
Register Viewmodel:
namespace myMood.ViewModels
{
public class RegisterViewModel : INotifyPropertyChanged
{
public MoodEntry MoodEntry { get; set; }
public DateTime LowerLimitDate { get; set; }
public DateTime HighLimitDate { get; set; }
public Command SaveEntry
{
get
{
return new Command(() =>
App.MoodDatabase.SaveMoodEntry(MoodEntry));
}
}
public RegisterViewModel()
{
MoodEntry = App.MoodDatabase.GetMoodEntry(DateTime.Today);
if (MoodEntry == null)
MoodEntry = new MoodEntry();
LowerLimitDate = new DateTime(2018, 1, 1);
HighLimitDate = DateTime.Today;
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}
You need to implement the INotifyPropertyChanged Interface in your viewmodel. Because Currently the viewmodel sends no signal to the UI that the data has changed.
So your viewmodel should look like this:
public class EntriesViewModel : INotifyPropertyChanged
{
private List<MoodEntry> _moodEntries;
public List<MoodEntry> MoodEntries
{
get { return _moodEntries; }
set { _moodEntries = value; OnPropertyChanged(); }
}
public EntriesViewModel()
{
MoodEntries = App.MoodDatabase.GetMoodEntries();
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}

Syncfusion Xamarin Listview not displaying any items

I want to insert a syncfusion linearlayout listview, but for some reason it's not displaying any items/data, and I'm not getting any errors at the same time, I tried changing binding syntax and a couple things, but I cannot seem to get it right.
This is my xaml:
<syncfusion:SfListView x:Name="listView"
ItemTemplate="{Binding Source={local2:BandInfoRepository}, Path=BandInfo, Mode=TwoWay}"
ItemSize="100"
AbsoluteLayout.LayoutBounds="1,1,1,1"
AbsoluteLayout.LayoutFlags="All" >
<syncfusion:SfListView.ItemTemplate>
<DataTemplate>
<Grid RowSpacing="0" Padding="0,12,8,0" ColumnSpacing="0" Margin="0">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="1" />
</Grid.RowDefinitions>
<Grid RowSpacing="0" Padding="8,0,8,10">
<Grid.RowDefinitions>
<RowDefinition Height="auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Image Source="{Binding Path=BandImage}"
Grid.Column="0"
Grid.Row="0"
HeightRequest="80"
WidthRequest="70"
HorizontalOptions="Start"
VerticalOptions="Start"
/>
<StackLayout Orientation="Vertical"
Padding="5,-5,0,0"
VerticalOptions="Start"
Grid.Row="0"
Grid.Column="1">
<Label Text="{Binding Path=BandName}"
FontAttributes="Bold"
FontSize="16"
BackgroundColor="Green"
TextColor="#000000" />
<Label Text="{Binding Path=BandDescription}"
Opacity="0.54"
BackgroundColor="Olive"
TextColor="#000000"
FontSize="13" />
</StackLayout>
</Grid>
<BoxView Grid.Row="1"
HeightRequest="1"
Opacity="0.75"
BackgroundColor="#CECECE" />
</Grid>
</DataTemplate>
</syncfusion:SfListView.ItemTemplate>
</syncfusion:SfListView>
And this is the class where I'm getting the data from:
public class BandInfo : INotifyPropertyChanged
{
private string bandName;
private string bandDesc;
private ImageSource _bandImage;
public string BandName
{
get { return bandName; }
set
{
bandName = value;
OnPropertyChanged("BandName");
}
}
public string BandDescription
{
get { return bandDesc; }
set
{
bandDesc = value;
OnPropertyChanged("BandDescription");
}
}
public ImageSource BandImage
{
get { return _bandImage; }
set
{
_bandImage = value;
OnPropertyChanged("BandImage");
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string name)
{
if (this.PropertyChanged != null)
this.PropertyChanged(this, new PropertyChangedEventArgs(name));
}
}
And just in case, this is how I'm filling the collection (BandInfoRepository.cs):
public class BandInfoRepository
{
private ObservableCollection<BandInfo> bandInfo;
public ObservableCollection<BandInfo> BandInfo
{
get { return bandInfo; }
set { this.bandInfo = value; }
}
public BandInfoRepository()
{
GenerateBookInfo();
}
internal void GenerateBookInfo()
{
string[] BandNames = new string[] {
"Nirvana",
"Metallica",
"Frank Sinatra"
};
string[] BandDescriptions = new string[] {
"Description",
"Description",
"Description"
};
bandInfo = new ObservableCollection<BandInfo>();
for (int i = 0; i < BandNames.Count(); i++)
{
var band = new BandInfo()
{
BandName = BandNames[i],
BandDescription = BandDescriptions[i],
BandImage = ImageSource.FromResource("Lim.Images.Image" + i + ".png")
};
bandInfo.Add(band);
}
}
}
I hope you guys can help me out as I've been stuck with this for a while now. Thanks in advance.
Looks like you unintentionally bind ItemTemplate twice and not bind any
ItemsSource even once.
We have looked into your code snippet and we have found that you have binded the underlying collection to ItemTemplate property instead of ItemsSource property. Further to bind the underlying collection you have to set your ViewModel(i.e. BandInfoRepository) as BindingContext for ContentPage. Please refer the below code snippets to know how to set BindingContext for your page and also to bind the underlying collection into the ItemsSource property.
Code Example:[XAML]
<ContentPage>
<ContentPage.BindingContext>
<local:BandInfoRepository/>
</ContentPage.BindingContext>
<ContentPage.Content>
<listView:SfListView x:Name="listView" ItemSize="70" ItemsSource="{Binding BandInfo}" >
<listView:SfListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<ViewCell.View>
<Grid x:Name="grid" RowSpacing="1">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="1" />
</Grid.RowDefinitions>
<Grid RowSpacing="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="50" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Image Source="{Binding BandImage}"
VerticalOptions="Center"
HorizontalOptions="Center"
HeightRequest="50" Aspect="AspectFit"/>
<Grid Grid.Column="1"
RowSpacing="1"
Padding="10,0,0,0"
VerticalOptions="Center">
<Label Text="{Binding ContactName}"/>
</Grid>
</Grid>
<StackLayout Grid.Row="1" BackgroundColor="Gray" HeightRequest="1"/>
</Grid>
</ViewCell.View>
</ViewCell>
</DataTemplate>
</listView:SfListView.ItemTemplate>
</listView:SfListView>
</ContentPage.Content>
</ContentPage>
For your assistance, we have attached the working sample link below.
Sample link: http://www.syncfusion.com/downloads/support/directtrac/186932/ze/ListViewSample905947849