This question is very similar to Picker not showing value in Xamarin.Forms on Windows Phone and UWP however there are some different aspects to this issue. Also the workaround selected as an answer to that question does not work in this case.
I have a ListView with an ItemTemplate that contains a ContentView. The ContentView contains a bindable picker. When the picker is selected the selected value is not displayed. This is an obvious bug because (1) you can resize the window and the value will appear and (2) this problem only occurs on UWP...iOS and Android versions are fine.
Here is the simplified issue. First the main window XAML...
<StackLayout Padding="10,40">
<Label>First List</Label>
<ListView Margin="20" x:Name="listView1" ItemsSource="{Binding ItemContexts}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<local:ContentView1
QuantityRows="{Binding Source={x:Reference listView1}, Path=BindingContext.QuantityRows}"
/>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<Label>Second List</Label>
<ListView Margin="20" x:Name="listView2" ItemsSource="{Binding ItemContexts}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Orientation="Horizontal">
<Picker x:Name="quantity" ItemsSource="{Binding Source={x:Reference listView2}, Path=BindingContext.QuantityView}" ItemDisplayBinding="{Binding FullName}"
SelectedItem="{Binding QuantityRow, Converter={StaticResource QuantityValueConverter}}"
WidthRequest="200">
</Picker>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<Label>End</Label>
</StackLayout>
There are two list views. The second one works fine and the first one illustrates the problem.
Here is the XAML for the content view...
<ContentView xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="XamarinFormsBench.ContentView1" x:Name="contextView1">
<ContentView.Content>
<StackLayout Orientation="Horizontal">
<Picker x:Name="quantity" ItemsSource="{Binding Source={x:Reference contextView1}, Path=QuantityRows}" ItemDisplayBinding="{Binding Name}"
SelectedItem="{Binding QuantityRow}"
WidthRequest="200">
</Picker>
</StackLayout>
</ContentView.Content>
</ContentView>
Code behind for content view...
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class ContentView1 : ContentView
{
public static BindableProperty QuantityRowsProperty = BindableProperty.Create("QuantityRows", typeof(ObservableCollection<QuantityRow>), typeof(SummaryDetailView), null, BindingMode.TwoWay, null);
public ObservableCollection<QuantityRow> QuantityRows
{
get
{
return GetValue(QuantityRowsProperty) as ObservableCollection<QuantityRow>;
}
set
{
SetValue(QuantityRowsProperty, value);
}
}
public ContentView1 ()
{
InitializeComponent ();
}
}
}
Finally here is the view model...
public class QuantityRow
{
public int ID { get; set; }
public string Name { get; set; }
}
public class ViewModel : INotifyPropertyChanged
{
public ViewModel()
{
QuantityRows = new ObservableCollection<QuantityRow>();
QuantityRows.Add(new QuantityRow() { ID = 1, Name = "Length" });
QuantityRows.Add(new QuantityRow() { ID = 2, Name = "Diameter" });
QuantityRows.Add(new QuantityRow() { ID = 3, Name = "Temperature" });
QuantityRows.Add(new QuantityRow() { ID = 4, Name = "Pressure" });
QuantityRows.Add(new QuantityRow() { ID = 5, Name = "Angle" });
}
public ObservableCollection<QuantityRow> QuantityRows { get; set; }
public event PropertyChangedEventHandler PropertyChanged;
}
}
I am using Xamarin Forms 2.3.4.247 which is the last stable release as of this writing. I tried the latest pre-release which might fix the problem..it is impossible to say because it created a host of other issues.
I've tried invalidating the layout of the content view when the picker's selected index changes, but again, this seems to fix the one problem and create a host of other problems.
So it seems that this will be fixed in the next stable release of Xamarin Forms. What I need now is an effective workaround so I can work with what I have.
I have tested your code and reproduced your issue. The problem is that your BindingContext of ContentView1 has never been set value. And this design is inconsequent, although it can work in the ios and andriod. For your requirement, you could realize it via custom ViewCell.
<ViewCell xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="XamarinPickerTest.CustomViewCell">
<ViewCell.View>
<StackLayout>
<Picker x:Name="quantity" ItemsSource="{Binding QuantityRows}"
ItemDisplayBinding="{Binding Name}"
SelectedItem="{Binding SelectedQuantityRow}"
WidthRequest="200">
</Picker>
</StackLayout>
</ViewCell.View>
</ViewCell>
ViewModel.cs
public class ViewModel : ViewModelBase
{
public ViewModel()
{
QuantityRows = new ObservableCollection<QuantityRow>();
QuantityRows.Add(new QuantityRow() { ID = 1, Name = "Length" });
QuantityRows.Add(new QuantityRow() { ID = 2, Name = "Diameter" });
QuantityRows.Add(new QuantityRow() { ID = 3, Name = "Temperature" });
QuantityRows.Add(new QuantityRow() { ID = 4, Name = "Pressure" });
QuantityRows.Add(new QuantityRow() { ID = 5, Name = "Angle" });
}
private ObservableCollection<QuantityRow> quantityRows;
public ObservableCollection<QuantityRow> QuantityRows
{
get
{
return quantityRows;
}
set
{
quantityRows = value;
OnPropertyChanged();
}
}
private QuantityRow selectedQuantityRow;
public QuantityRow SelectedQuantityRow
{
get { return selectedQuantityRow; }
set
{
if (selectedQuantityRow != value)
{
selectedQuantityRow = value;
OnPropertyChanged();
}
}
}
}
public class QuantityRow : ViewModelBase
{
public int ID { get; set; }
public string Name { get; set; }
}
Usage
<ListView Margin="20" x:Name="listView1" ItemsSource="{Binding ItemContexts}" >
<ListView.ItemTemplate>
<DataTemplate>
<local:CustomViewCell/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
And the above solution works well in ios and android.
Related
I'm trying to make CollectionView in Shell but it's not updating.
I have one view model connected to Page and AppShell but when I update Collection view only page is updationg.
`public class AppShellViewModel : INotifyPropertyChanged
{
public Command Load { get; }
public ObservableCollection<ListData> _lists { get; set; }
public ObservableCollection<ListData> Lists
{
get { return _lists; }
set
{
_lists = value;
OnPropertyChanged();
}
}
public AppShellViewModel()
{
Lists = new ObservableCollection<ListData>()
{
new ListData(){id=0,name="test",UserId=0},
new ListData(){id=1,name="test1",UserId=1},
new ListData(){id=2,name="test2",UserId=2},
new ListData(){id=3,name="test3",UserId=3},
new ListData(){id=4,name="test4",UserId=4}
};
Load = new Command(async () => await GetUserLists());
}
async Task GetUserLists()
{
for (int i = 5; i < 15; i++)
{
Lists.Add(new ListData {id=i, name=$"test{ i }", UserId=i });
}
}
public event PropertyChangedEventHandler PropertyChanged;
void OnPropertyChanged([CallerMemberName] string name = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
}`
Then i have App Shell Collection View
`<Shell.FlyoutContent>
<StackLayout BackgroundColor="#34495e">
<Label Text="YOUR LISTS" FontSize="50" />
<CollectionView ItemsSource="{Binding Lists}" >
<CollectionView.ItemTemplate>
<DataTemplate>
<StackLayout Padding="10" x:DataType="model:ListData">
<Label Text="{Binding name}"
LineBreakMode="NoWrap"
FontSize="13" />
</StackLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</StackLayout>
</Shell.FlyoutContent>`
And There is Page CollectionView
`<?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="ToDoApp.Views.AboutPage"
xmlns:model="clr-namespace:ToDoApp.Models">
<StackLayout>
<Button Text="Load" Command="{Binding Load}"/>
<Label Text="{Binding error}"/>
<CollectionView ItemsSource="{Binding Lists}">
<CollectionView.ItemTemplate>
<DataTemplate>
<StackLayout Padding="10" x:DataType="model:ListData">
<Label Text="{Binding name}"
LineBreakMode="NoWrap"
FontSize="13" />
</StackLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</StackLayout>
</ContentPage>`
before update it looks like this
Page before update
Shell before update
And after update the only what changed is content page and shell is the same as before
Page after update
Shell after update
Related to Jason's comment.
WON'T CHANGE TOGETHER
NOT the same instance - BindingContexts similar to these:
// In AppShell.xaml.cs.
public AppShell()
{
InitializeComponent();
BindingContext = new AppShellViewModel();
}
// In AboutPage.xaml.cs.
public AboutPage()
{
InitializeComponent();
BindingContext = new AppShellViewModel();
}
GOOD (SHARED BETWEEN TWO PLACES)
BindingContexts are SAME instance:
// In AppShellViewModel.cs.
public class AppShellViewModel ...
{
private static AppShellViewModel _it;
public static AppShellViewModel It
{
get {
if (_it == null)
_it = new AppShellViewModel();
return _it;
}
}
}
// In AppShell.xaml.cs.
public AppShell()
{
InitializeComponent();
BindingContext = AppShellViewModel.It;
}
// In AboutPage.xaml.cs.
public AboutPage()
{
InitializeComponent();
BindingContext = AppShellViewModel.It;
}
I have a Xamarin project for Android and UWP. This issue seems to only happen on UWP.
In my Xamarin project I have ContentPage with a view model bound as context. In this ViewModel there's an ObservableCollection with another kind of view model. When I create a new instance of this underlying ViewModel and add to my ObservableCollection, sometimes the ContentPage works as expected, showing an item in my ListView. But sometimes there's an empty element added, that I can see when hovering over the list. When this happens I get a bunch of warnings in the Output tab.
My DownloadsPage:
<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"
xmlns:local="clr-namespace:Downloader.Converters"
mc:Ignorable="d"
x:Class="Downloader.Views.DownloadsPage">
<ContentPage.Resources>
<ResourceDictionary>
<local:DownloadStatusToColorConverter x:Key="downloadStatusToColor" />
</ResourceDictionary>
</ContentPage.Resources>
<RefreshView IsRefreshing="{Binding IsBusy, Mode=TwoWay}" Command="{Binding LoadItemsCommand}">
<ListView x:Name="DownloadsListView" SelectionMode="None" ItemsSource="{Binding Downloads}" RowHeight="70">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Padding="10" BackgroundColor="{Binding DownloadStatus, Converter={StaticResource downloadStatusToColor}}">
<Label Text="{Binding Name}"
d:Text="{Binding .}"
LineBreakMode="NoWrap"
Style="{DynamicResource ListItemTextStyle}"
FontSize="16" />
<Grid Grid.Row="0" Grid.Column="0" Padding="10,0,10,0">
<ProgressBar BackgroundColor="Transparent" Progress="{Binding PercentDownloaded}" HorizontalOptions="FillAndExpand" HeightRequest="20">
</ProgressBar>
<Label Text="{Binding PercentString}" HorizontalTextAlignment="Center"></Label>
</Grid>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</RefreshView>
</ContentPage>
DownloadsViewModel is set as context in the code-behind like this:
public partial class DownloadsPage : ContentPage
{
private readonly DownloadsViewModel _viewModel;
public DownloadsPage()
{
InitializeComponent();
BindingContext = _viewModel = new DownloadsViewModel();
Device.StartTimer(TimeSpan.FromSeconds(1), () =>
{
Device.BeginInvokeOnMainThread(() => _viewModel.RefreshDownloads());
return true;
});
}
}
The bound DownloadsViewModel:
public class DownloadsViewModel : BaseViewModel
{
public ObservableCollection<DownloadViewModel> Downloads { get; set; } = new ObservableCollection<DownloadViewModel>();
public Command LoadItemsCommand { get; set; }
public DownloadsViewModel()
{
Title = "Downloads";
LoadItemsCommand = new Command(() => {
IsBusy = true;
Downloads.Clear();
RefreshDownloads();
IsBusy = false;
});
}
public void RefreshDownloads()
{
foreach (var download in DownloadManager.GetDownloads())
{
var existingDownload = Downloads.FirstOrDefault(d => d.Id == download.Id);
if (existingDownload != null)
{
existingDownload.UpdateValues(download);
}
else
{
Downloads.Add(new DownloadViewModel(download));
}
}
}
}
And the ObservableCollection contains DownloadViewModel that looks like this:
public class DownloadViewModel : BaseViewModel
{
private IDownload _download;
public DownloadViewModel(IDownload download)
{
UpdateValues(download);
}
private string _id;
public string Id
{
get { return _id; }
set { SetProperty(ref _id, value); }
}
private string _name;
public string Name
{
get { return _name; }
set { SetProperty(ref _name, value); }
}
private DownloadStatus _status;
public DownloadStatus DownloadStatus
{
get { return _status; }
set { SetProperty(ref _status, value); }
}
public double PercentDownloaded
{
get
{
return _download.DownloadedBytes == -1
? 0f
: (double)_download.DownloadedBytes / _download.TotalBytes;
}
}
public string PercentString { get => $"{(int)(PercentDownloaded * 100)} %"; }
public void UpdateValues(IDownload download)
{
_download = download;
Id = _download.Id;
Name = _download.Name;
DownloadStatus = _download.Status;
}
}
The error I sometimes get which causes items in my ListView to be empty:
Binding: 'DownloadStatus' property not found on 'Downloader.ViewModels.DownloadsViewModel', target property: 'Xamarin.Forms.StackLayout.BackgroundColor'
Binding: 'Name' property not found on 'Downloader.ViewModels.DownloadsViewModel', target property: 'Xamarin.Forms.Label.Text'
Binding: 'PercentDownloaded' property not found on 'Downloader.ViewModels.DownloadsViewModel', target property: 'Xamarin.Forms.ProgressBar.Progress'
Binding: 'PercentString' property not found on 'Downloader.ViewModels.DownloadsViewModel', target property: 'Xamarin.Forms.Label.Text'
When debugging I've confirmed that the item is added to my ObservableCollection as expcted.
How come sometimes it's looking for DownloadStatus, Name, PercentDownloaded and PercentString on DownloadsViewModel instead of DownloadViewModel?
Xamarin UWP seems to bind to the wrong view model
I checked your code sample and it works as expect. But I found the progress value does not update automatically that cause the listview item can't display, I have update the IDownload interface add PercentDownloaded property. For the testing it could works in uwp platform.
The problem was that the ViewModels did not have setters with INotifyPropertyChanged implemented for all properties. The source code is available on Github, and the commit that fixes the issue is this one.
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.
Im having a hard time trying to figure out how to set up a two-way binding for a control inside a listview.
Im using ReactiveUI and Xamarin.Forms.
In this case i would like to load a list of objects that have a quantity. This is set initially when the page loads. However i would like to be able to change these quantity values in the view when the program is run. I used an Entry for that.
Setting up a two-way Binding for the List itself (done in code behind, the reactive way) is not possible. It will error.
Is there another way to observe changes done to the Text property in the Entry control and reflect them to the according item from the list in my viewmodel?
I've been having trouble finding a solution for this and don't really know how to go about this.
Here is my XAML code:
<CustomControls:AutoLoadListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Margin="20,0,0,0" Orientation="Vertical" HorizontalOptions="StartAndExpand">
<Label Margin="0,5,0,-5" Style="{StaticResource ViewCellPrimaryLabelStyle}" x:Name="txt" Text="{Binding itemname}" />
<Label Margin="0,-5,0,5" Style="{StaticResource ViewCellSecondaryLabelStyle}" x:Name="barcode" Text="{Binding productcode}" />
</StackLayout>
<Entry Margin="5,0,5,0" x:Name="quantity" Text="{Binding quantity}">
<Entry.BindingContext>
<ViewModel:AankoopEditViewModel />
</Entry.BindingContext>
</Entry>
<Image Margin="5,5,5,5" x:Name="delete" Source="{Mobile:ImageResource tbin_pos.png}">
<Image.GestureRecognizers>
<TapGestureRecognizer
Command="{Binding Path=BindingContext.DeleteCommand,Source={x:Reference Name=AankoopEditPage}}"
CommandParameter="{Binding}" />
</Image.GestureRecognizers>
</Image>
</ViewCell>
</DataTemplate>
</CustomControls:AutoLoadListView.ItemTemplate>
My Viewmodel:
public class AankoopEditViewModel : BaseViewModel
{
private VmPurchase Purchase;
public AankoopEditViewModel()
{
PurchaseList = new ReactiveObservableCollection<AankoopEditListItem>()
{
ChangeTrackingEnabled = true
};
this.WhenAnyValue(x => x.PurchaseID).SubscribeOn(RxApp.MainThreadScheduler).Subscribe((x) =>
{
this.Purchase = DatabaseHelper.Purchase.LoadSingleById<VmPurchase>(PurchaseID);
if (Purchase != null)
{
this.Title = Purchase.supplier.name;
using (PurchaseList.SuppressChangeNotifications())
{
foreach (var detail in Purchase.purchasedetails)
{
PurchaseList.Add(new AankoopEditListItem { productcode = detail.item.code, itemname = detail.item.namenl, identifier = detail.key, quantity = detail.quantity.ToString() });
}
}
}
});
try
{
this.WhenAnyValue(x => x.PurchaseList).SubscribeOn(RxApp.MainThreadScheduler).Subscribe((x) =>
{
Console.WriteLine("The List has changed");
});
}
catch (Exception e)
{
return;
}
}
private string _purchaseID;
public string PurchaseID
{
get { return _purchaseID; }
set { this.RaiseAndSetIfChanged(ref _purchaseID, value); }
}
private ReactiveObservableCollection<AankoopEditListItem> _purchases;
public ReactiveObservableCollection<AankoopEditListItem> PurchaseList
{
get
{
return this._purchases;
}
set
{
this.RaiseAndSetIfChanged(ref _purchases, value);
}
}
My Model :
public class AankoopEditListItem : ReactiveObject
{
public string identifier { get; set; }
public string itemname { get; set; }
public string productcode { get; set; }
public string quantity { get; set; }
}
Be careful, when you do this
<Entry.BindingContext>
<ViewModel:AankoopEditViewModel />
</Entry.BindingContext>
you create a new instance of your view model for each item and you bind your Entry to it. Just remove it and keep the binding as it is (Text="{Binding quantity}") if you want to bind your entry to the row view model
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...