Show CollectionView Grouping not working in Xamarin - xamarin.forms

I have an article here about showing Data Groups from Preferences . As per everyone's input I switched to CollectionView. I have consulted the article https://learn.microsoft.com/en-us/xamarin/xamarin-forms/user-interface/collectionview/grouping. This is what I have:
public class CartUser
{
public int IDProduct { get; set; }
public string NameProduct { get; set; }
public string SupplierID { get; set; }
}
SupplierIDGrouping.cs
public class SupplierIDGrouping : ObservableCollection<CartUser>
{
public string SupplierID { get; private set; }
public SupplierIDGrouping(string supplierID)
: base()
{
SupplierID = supplierID;
}
public SupplierIDGrouping(string supplierID, IEnumerable<CartUser> source)
: base(source)
{
SupplierID = supplierID;
}
}
PageOne.xaml
<CollectionView ItemsSource="{Binding SupplierList}" IsGrouped="true">
<CollectionView.ItemTemplate>
<DataTemplate>
<Label Text="{Binding NameProduct}"/>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
PageOne.xaml.cs
public ObservableCollection<SupplierIDGrouping> SupplierList { get; private set; } = new ObservableCollection<SupplierIDGrouping>();
List<CartUser> cartUsers = new List<CartUser>();
var mycart = Preferences.Get("CartUserAdds", "_mycart");
var getcart = JsonConvert.DeserializeObject<List<CartUser>>(mycart);
cartUsers = getcart;
foreach (var item in cartUsers)
{
if (!SupplierList.Any(supplierid => supplierid.SupplierID == item.SupplierID))
{
SupplierList.Add(new SupplierIDGrouping(item.SupplierID));
}
SupplierList.Single(supplierid => supplierid.SupplierID== item.SupplierID).Add(item);
}
BindingContext = this;
The data I am taken from Preferences:
[{\"IDProduct\":1,\"NameProduct\":\"Name product 1\",\"SupplierID\":\"22379356\"},{\"IDProduct\":2,\"NameProduct\":\"Name product 2\",\"SupplierID\":\"22379356\"},{\"IDProduct\":3,\"NameProduct\":\"Name product 3\",\"SupplierID\":\"12336544\"}]
However my results are still not grouped by SupplierID
This is what I want:
Looking forward to everyone's help. Thank you very much!
Update
Data corresponds to 2 groups. Group 1: 2 products, group 2: 1 product
foreach (var item in cartUsers)
{
if (!SupplierList.Any(supplierid => supplierid.SupplierID == item.SupplierID))
{
SupplierList.Add(new SupplierIDGrouping(item.SupplierID));
}
SupplierList.Single(supplierid => supplierid.SupplierID== item.SupplierID).Add(item);
}
var getresult = SupplierList;
foreach(var i in getresult)
{
}
BindingContext = this;
Update 2
public class SupplierIDGrouping : ObservableCollection<CartUser>
{
public string SupplierID { get; private set; }
public string Name { get { return SupplierID; } }
public SupplierIDGrouping(string supplierID)
: base()
{
SupplierID = supplierID;
}
public SupplierIDGrouping(string supplierID, IEnumerable<CartUser> source)
: base(source)
{
SupplierID = supplierID;
}
}
PageOne.xaml
<CollectionView ItemsSource="{Binding SupplierList}" IsGrouped="true" Header="{Binding Name}">
<CollectionView.ItemTemplate>
<DataTemplate>
<Label Text="{Binding NameProduct}"/>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>

I had to provide a GroupHeaderTemplate to make it work. Not sure why - according to the docs it should not be necessary
<CollectionView.GroupHeaderTemplate>
<DataTemplate>
<Label Text="{Binding SupplierID}"
BackgroundColor="LightGray"
FontSize="Large"
FontAttributes="Bold" />
</DataTemplate>
</CollectionView.GroupHeaderTemplate>

Related

TreeListView/DataGrid in .NET 5

I am trying to implement a TreeListView/DataGrid in .Net 5.
What I need is extendible columns (meaning I can adapt the width in the GUI) and also fold-out rows (like in a tree, each parent and subnode should have data in multiple columns).
For example like this:
What I tried so far:
TreeView: Doesn't have extendible columns
DataGrid and grouping: The header=parent does not have columns like its childrows.
I tried many useful packages like "objectListView", but they do not run on .Net5.
I downloaded DotNetProjects.Extended.Wpf.Toolkit, but don't find a good documentation on how to use it.
Which would be the best way to get ahead with this?
Thanks for any hints!
I ended up writing my own expander button.
It's just a prototype, intended to be used only with one sublevel and without column-sorting.
But it can be extended for other use cases. Hope it might help someone who bumps over the same issue.
I'm still looking forward to getting any hints or ideas for improvement.
thx!
Example outcome:
View (XAML)
<DataGrid Name="dgUsers" Grid.Row="0" Visibility="Visible" AutoGenerateColumns="False" ItemsSource="{Binding Users}"
CanUserAddRows="False" CanUserDeleteRows="False" CanUserSortColumns="False">
<DataGrid.Columns>
<DataGridTemplateColumn Header="Name">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<StackPanel>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Name="Expander" Width="Auto"></ColumnDefinition>
<ColumnDefinition Name="Content" Width="Auto"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Button Grid.Column="0" HorizontalAlignment="Left" Background="GhostWhite" BorderBrush="GhostWhite"
Visibility="{Binding ExpanderVisibility}"
Command="{Binding ExpandCommand}" CommandParameter="{Binding RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type DataGrid}}}"
Content="{Binding ExpanderSign}">
</Button>
<CheckBox Grid.Column="1" Margin="{Binding CheckboxMargin}"/>
<TextBlock Grid.Column="1" Text="{Binding Name}" Margin="{Binding JobNameMargin}"/>
</Grid>
</StackPanel>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTextColumn Header="Birthday" Binding="{Binding Birthday}" />
</DataGrid.Columns>
</DataGrid>
ViewModel (C#):
public class JobViewModel : BindableBase
{
private ObservableCollection<User> _users = new ObservableCollection<User>();
private static string _isExpandedSign = "^";
private static string _expandableSign = ">";
public JobViewModel()
{
var cori = ((new User() { Name = "Cori", Birthday = new DateTime(1982, 8, 10), ExpanderVisibility = "Hidden" }));
var penny = ((new User() { Name = "Penny", Birthday = new DateTime(1976, 7, 31), ExpanderVisibility = "Hidden" }));
var john = ((new User() { Id = 10, Name = "John Doe", Birthday = new DateTime(1971, 7, 23) } ));
var samy = ((new User() { Id = 20, Name = "Sammy Doe", Birthday = new DateTime(1991, 9, 2) }));
var jane = ((new User() { Id = 30, Name = "Jane Doe", Birthday = new DateTime(1974, 1, 17) }));
var anny = ((new User() { Id = 40, Name = "Anny Doe", Birthday = new DateTime(1931, 1, 26) }));
john.AddChild(cori);
john.AddChild(penny);
jane.AddChild(cori);
jane.AddChild(penny);
anny.AddChild(cori);
anny.AddChild(penny);
_users.Add(john);
_users.Add(samy);
_users.Add(jane);
_users.Add(anny);
}
public class User : BindableBase
{
public int Id { get; set; }
public string ExpanderVisibility { get; set; }
public string CheckboxMargin { get; set; }
public string JobNameMargin { get; set; }
public bool IsExpanded { get; set; }
public string Name { get; set; }
public DateTime Birthday { get; set; }
public List<User> Children { get; set; }
public bool IsChild { get; set; }
public ICommand ExpandCommand { get; private set; }
public bool HasChildren()
{
return true;
}
public User(){
ExpandCommand = new DelegateCommand<DataGrid>(ExecuteExpandCommand);
ExpanderVisibility = "Hidden";
CheckboxMargin = "3,0,0,0";
JobNameMargin = "25,0,5,0";
Children = new List<User>();
}
public string ExpanderSign
{
get {
if (this.IsExpanded) return (_isExpandedSign);
else return (_expandableSign);
}
}
public void AddChild(User child)
{
child.CheckboxMargin = "23,0,0,0";
child.JobNameMargin = "45,0,5,0";
child.IsChild = true;
Children.Add(child);
ExpanderVisibility = "Visible";
}
private void ExecuteExpandCommand(DataGrid dg)
{
ObservableCollection<User> items = (ObservableCollection<User>)dg.ItemsSource;
int parentIndex=items.IndexOf(this);
if (!IsExpanded)
{
//expand
for (int i = 0; i < Children.Count; ++i)
{
items.Insert(parentIndex + 1 + i, Children.ElementAt(i));
}
}
else
{
int childrenCount = Children.Count;
for (int i=0; i< childrenCount; ++i)
{
if(parentIndex + 1 < items.Count && items.ElementAt(parentIndex + 1).IsChild) //just to be sure
{
items.RemoveAt(parentIndex + 1);
}
}
}
IsExpanded = !IsExpanded;
RaisePropertyChanged("ExpanderSign");
}
}
public ObservableCollection<User> Users
{
get { return _users; }
set { _users = value; }
}
}

Value Converter is executed before the data is updated in View Model property in Xamarin Forms

I have a very basic need, but it seems quite challenging to achieve such a simple thing in Xamarin Forms, especially when I compare it with the way the React Native let us do the same thing.
Anyways, so I am trying to highlight a frame's background color based on the selected Id. For that, I have created a value converter, and passing Id to check and convert to the desired background color.
Below is my XAML Code:
<Frame CornerRadius="6" Padding="10" Margin="5" WidthRequest="110" HeightRequest="80"
BackgroundColor="{Binding TitleId, Converter={StaticResource
selectedGuidelineToColorConverter},ConverterParameter={x:Reference Guidelines}}">
<StackLayout>
<Label Style="{StaticResource MaterialIcons}" Text="󰠆" FontSize="20"/>
<Label Text="{Binding Title}" FontSize="13" HorizontalTextAlignment="Start" TextColor="#333d47"/>
<StackLayout.GestureRecognizers>
<TapGestureRecognizer NumberOfTapsRequired="1" Command="{Binding Path=BindingContext.SelectedGuidelineCommand, Source={x:Reference Guidelines}}" CommandParameter="{Binding}">
</TapGestureRecognizer>
</StackLayout.GestureRecognizers>
</StackLayout>
</Frame>
Below is my Converter Code:
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
var page = parameter as ContentPage;
GuidelinesViewModel model = null;
if(page != null)
{
model = page.BindingContext as GuidelinesViewModel;
}
if(model != null && model.CurrentVisibleGuideline != null && model.CurrentVisibleGuideline.TitleId == (int)value)
{
return "#808080";
}
return "#fff";
}
My Model Code:
public class Guideline
{
public int TitleId { get; set; }
public string Title { get; set; }
public Section Section { get; set; }
public List<Content> Content { get; set; }
public List<QnA> QnA { get; set; }
}
Here is my View Model Code:
Guideline guideline = null;
public Guideline CurrentVisibleGuideline
{
get { return guideline; }
set { SetProperty(ref guideline, value); }
}
public ICommand SelectedGuidelineCommand
{
get
{
return new Command<Guideline>((guideline) => ExecuteSelectedGuidelineCommand(guideline));
}
}
void ExecuteSelectedGuidelineCommand(Guideline guideline)
{
CurrentVisibleGuideline = guideline;
}
async void GetGuidelines()
{
IsBusy = true;
Guidelines = new ObservableCollection<Guideline>();
try
{
var guidelines = await DataStore.GetGuidelinesAsync(CurrentVisibleSection);
foreach (var guideline in guidelines)
{
Guidelines.Add(guideline);
}
CurrentVisibleGuideline = Guidelines[0];
TotalGuidelines = Guidelines.Count;
}
catch (Exception ex)
{
Debug.WriteLine(ex);
}
finally
{
IsBusy = false;
}
}
"CurrentVisibleGuideline" is a property in my View Model which contains the TitleId and other details of the selected guideline.
Problem is that, the converter code is executed before the CurrentVisibleGuideline = Guidelines[0] in the view model, and therefore, I get null in CurrentVisibleGuideline in the converter.
I believe that once the data is updated in the view model upon command execution, the XAML code should re-render the view and re-run the converter, but in my case it doesn't seem to happen.
Add an IsSelected boolean to you Guideline View Model.
Update the convertor to take in a bool and return a string that will return
your Hex color value.
When you change the CurrentVisibleGuideline Set the IsSelected flag on your Guideline View Model.
ViewModel
public class Guideline
{
private bool _isSelected;
public bool IsSelected
{
get { return _isSelected; }
set
{
_isSelected = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("IsSelected"));
}
}
public int TitleId { get; set; }
public string Title { get; set; }
public Section Section { get; set; }
public List<Content> Content { get; set; }
public List<QnA> QnA { get; set; }
}
ObservableCollection<Guideline> Guidelines { get; set; }
Guideline guideline = null;
public Guideline CurrentVisibleGuideline
{
get { return guideline; }
set { SetProperty(ref guideline, value); }
}
public ICommand SelectedGuidelineCommand
{
get
{
return new Command<Guideline>((guideline) => ExecuteSelectedGuidelineCommand(guideline));
}
}
void ExecuteSelectedGuidelineCommand(Guideline guideline)
{
CurrentVisibleGuideline = guideline;
}
async void GetGuidelines()
{
IsBusy = true;
Guidelines = new ObservableCollection<Guideline>();
try
{
var guidelines = await DataStore.GetGuidelinesAsync(CurrentVisibleSection);
foreach (var guideline in guidelines)
{
Guidelines.Add(guideline);
}
CurrentVisibleGuideline = Guidelines[0];
TotalGuidelines = Guidelines.Count;
}
catch (Exception ex)
{
Debug.WriteLine(ex);
}
finally
{
IsBusy = false;
}
}
void SetCurrentGuideline(Guideline guideline)
{
CurrentVisibleGuideline = guideline;
foreach (var gl in Guidelines)
gl.IsSelected = gl.TitleId == CurrentVisibleGuideline.TitleId;
}
Converter
public class BooleanToStringConverter : IValueConverter
{
public string TrueValue { get; set; } = "#808080"
public string FalseValue { get; set; } = "#FFF"
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is bool)
{
if ((bool)value)
return TrueValue;
else
return FalseValue;
}
return "";
}
}
XAML
<Frame CornerRadius="6" Padding="10" Margin="5" WidthRequest="110" HeightRequest="80"
BackgroundColor="{Binding IsSelected, Converter={StaticResource BooleanToString}}">
<StackLayout>
<Label Style="{StaticResource MaterialIcons}" Text="󰠆" FontSize="20"/>
<Label Text="{Binding Title}" FontSize="13" HorizontalTextAlignment="Start" TextColor="#333d47"/>
<StackLayout.GestureRecognizers>
<TapGestureRecognizer NumberOfTapsRequired="1" Command="{Binding Path=BindingContext.SelectedGuidelineCommand, Source={x:Reference Guidelines}}" CommandParameter="{Binding}">
</TapGestureRecognizer>
</StackLayout.GestureRecognizers>
</StackLayout>
</Frame>
On a side note you will also need to turn the guideline(s) you get back from your DataStore into a ViewModel version.

Xamarin forms: How to add a contentpage having arguments into a list?

I am implementing the Navigation Drawer on my project. I am following this blog for this feature.
Mainpage.xsml.cs:
public partial class NavigationDrawerPage : MasterDetailPage
{
public List<MasterPageItem> menuList { get; set; }
public MainPage()
{
InitializeComponent();
menuList = new List<MasterPageItem>();
// Adding menu items to menuList and you can define title ,page and icon
menuList.Add(new MasterPageItem() { Title = "Home", Icon = "home.png", TargetType = typeof(HomePage) });
menuList.Add(new MasterPageItem() { Title = "Setting", Icon = "setting.png", TargetType = typeof(SettingPage) });
menuList.Add(new MasterPageItem() { Title = "LogOut", Icon = "logout.png", TargetType = typeof(LogoutPage) });
navigationDrawerList.ItemsSource = menuList;
Detail = new NavigationPage((Page)Activator.CreateInstance(typeof(HomePage)));
}
}
Mainpage.xaml
<StackLayout Grid.Row="1" Spacing="15">
<ListView x:Name="navigationDrawerList"
RowHeight="60"
SeparatorVisibility="None"
BackgroundColor="#e8e8e8"
ItemSelected="OnMenuItemSelected">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout>
<!-- Main design for our menu items -->
<StackLayout VerticalOptions="FillAndExpand"
Orientation="Horizontal"
Padding="20,10,0,10"
Spacing="20">
<Image Source="{Binding Icon}"
WidthRequest="30"
HeightRequest="30"
VerticalOptions="Center" />
<Label Text="{Binding Title}"
FontSize="Medium"
VerticalOptions="Center"
TextColor="Black"/>
</StackLayout>
<BoxView HeightRequest="1" BackgroundColor="Gray"/>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
MasterPageItem.cs
public class MasterPageItem
{
public string Title { get; set; }
public string Icon { get; set; }
public Type TargetType { get; set; }
}
My problem is when adding my content pages to list. The above code working perfect:
menuList.Add(new MasterPageItem() { Title = "Home", Icon = "home.png", TargetType = typeof(SettingPage) });
But I have a page having one argument, I can't add the argument inside of the TargetType. See the below code:
menuList.Add(new MasterPageItem() { Title = "Help", Icon = "help.png", TargetType = typeof(HelpPage(false)) }); //showing syntax errors for this line
How can I add a content page having arguments into the list item? Should I change the TargetType datatype?
You could pass parameters with the method public static object CreateInstance(Type type, params object[] args);
Item
public class MasterPageItem
{
public string Title { get; set; }
public string Icon { get; set; }
public Type TargetType { get; set; }
public object[] args { get; set; } //
}
MasterDetailPage
menuList.Add(new MasterPageItem() { Title = "Home", Icon = "home.png", TargetType = typeof(HomePage), args = new object[] {"string", 1 , false} } ); // pass parameters whatever you want
private void OnMenuItemSelected(object sender, SelectedItemChangedEventArgs e)
{
var item = (MasterPageItem)e.SelectedItem;
Type page = item.TargetType;
Detail = new NavigationPage((Page)Activator.CreateInstance(page,item.args)); //this line
IsPresented = false;
}
Add the constructor with corresponding parameters
public HomePage() //remain the default constructor
{
InitializeComponent();
}
public HomePage (string s , int i , bool b) //add this
{
InitializeComponent ();
}

UWP how to update a bound TextBox with changes in selected item of a bound ListView

I have a UWP Page, containing a form with textboxes and a ListView control. The ListView control is bound to a collection of Products. And I want that the bound textboxes should show the information regarding the product selected in the listview.
public class Product: INotifyPropertyChanged
{
public int ProductID { get; set; }
private string name;
public string Name {
get { return name; }
set
{
if (name==value)
return;
name = value;
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(nameof(Name)));
}
}
public event PropertyChangedEventHandler PropertyChanged;
public Product(int pid, string name)
{
ProductID = pid;
Name = name;
}
}
}
The XAML is as below:
<TextBox x:Name="txtProductId" Grid.Row="1" Grid.Column="1"
Text="{x:Bind CurrentProduct.ProductID}"/>
<TextBox x:Name="txtProductName" Grid.Row="2" Grid.Column="1"
Text="{x:Bind CurrentProduct.Name}" />
<ListView x:Name="lstProducts" Grid.Row="3" Grid.ColumnSpan="2"
ItemsSource="{x:Bind ProductList}"
SelectedItem="{x:Bind CurrentProduct, Mode=TwoWay}"
ItemTemplate="{StaticResource lstDataTemplate}"
>
</ListView>
The following code executes on Page_Loaded:
CurrentProduct = Products[0];
DataContext = CurrentProduct;
The ListView is bound to ProductList (Type ObservableCollection). I've noticed by executing the app in single step mode, the value of CurrentProduct is changing, but I think since it is the reference and not the property of the DataContext that changes, the PropertyChanged event is never fired and the TextBox doesn't get updated to show the name of the CurrentProduct.
I don't know how to proceed, any help would be appreciated.
The X:Bind default mode is OneTime, in your case, you need to set the mode to OneWay.
I made a code sample for your reference:
<TextBox x:Name="txtProductId" Grid.Row="1" Grid.Column="1"
Text="{x:Bind CurrentProduct.ProductID,Mode=OneWay}"/>
<TextBox x:Name="txtProductName" Grid.Row="2" Grid.Column="1"
Text="{x:Bind CurrentProduct.Name,Mode=OneWay}" />
<ListView x:Name="lstProducts" Grid.Row="3" Grid.ColumnSpan="2"
ItemsSource="{x:Bind ProductList}"
SelectedItem="{x:Bind CurrentProduct, Mode=TwoWay}"
>
</ListView>
public sealed partial class MainPage : Page, INotifyPropertyChanged
{
public MainPage()
{
this.InitializeComponent();
this.Loaded += MainPage_Loaded;
}
private void MainPage_Loaded(object sender, RoutedEventArgs e)
{
for (int i = 0; i < 10; i++)
{
ProductList.Add(new Product(i, "name " + i));
}
}
public ObservableCollection<Product> ProductList { get; set; } = new ObservableCollection<Product>();
private Product _CurrentProduct = new Product(100,"test");
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged(string PropertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this,new PropertyChangedEventArgs(PropertyName));
}
}
public Product CurrentProduct
{
get { return _CurrentProduct; }
set
{
if (_CurrentProduct != value)
{
_CurrentProduct = value;
RaisePropertyChanged("CurrentProduct");
}
}
}
}
public class Product : INotifyPropertyChanged
{
public int ProductID { get; set; }
private string name;
public string Name
{
get { return name; }
set
{
if (name == value)
return;
name = value;
RaisePropertyChanged("Name");
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged(string PropertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(PropertyName));
}
}
public Product(int pid, string name)
{
ProductID = pid;
Name = name;
}
public override string ToString()
{
return Name;
}
}

Xamarin Forms connect products with user accounts

I'm making a shopping app, it has account for the user, and when the user purchases a product, it should be added to a listview in his account. So I tried to put a static object of the User Class that has a list of Products, and whenever the user clicks the buying button, it should be added to the list. At the same time, the user.xaml is binding to the same object. But it doesn't work. What's the error in my method?
Are there any better ideas to do this?
here's the static field in the App.xaml.cs file
private IDataService _dataService;
public static User TheUser;
public App(IDataService dataService)
{
TheUser = new User();
InitializeComponent();
var unity = new UnityContainer();
unity.RegisterType<IDataService, DataServices>();
ServiceLocator.SetLocatorProvider(() => new UnityServiceLocator(unity));
_dataService = dataService;
MainPage = new NavigationPage(new MainPage());
}
and here's the User.xaml.cs property
public User User
{
get { return App.TheUser; }
set
{
if(App.TheUser!= null)
App.TheUser = value;
}
//User class
public class User : Base //Base class implements INotifyPropertyChanged
{
public int Id { get; set; }
public string Name { get; set; }
public ObservableCollection<Product> Products = new ObservableCollection<Product>();
}
public class Base : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
Here's the User.Xaml file
<StackLayout>
<AbsoluteLayout>
<Image AbsoluteLayout.LayoutBounds="1 , 0 ,96 ,96" AbsoluteLayout.LayoutFlags="PositionProportional"/>
<Label AbsoluteLayout.LayoutBounds="0 , 50 , 100 , 20" AbsoluteLayout.LayoutFlags="XProportional" Text="First Name"/>
<Label AbsoluteLayout.LayoutBounds="0 , 100 , 100 , 20" AbsoluteLayout.LayoutFlags="XProportional" Text="Last Name"/>
</AbsoluteLayout>
<ListView x:Name="UserListView"
SelectedItem="{Binding SelectedItemCommand}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Spacing="3" FlowDirection="RightToLeft" >
<Image Source="{Binding ProductMainImage}" Aspect="AspectFill" Margin="3" HeightRequest="300" />
<Label Text="{Binding Name ,StringFormat=' الاسم : {0}'}"/>
<Label Text="{Binding Price ,StringFormat=' السعر : {0}'}"/>
<Label Text="{Binding Description ,StringFormat=' الوصف : {0}'}"/>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
ok so the property notification doesn't happen automatically. You need to invoke that code to raise the event. This should takes care of the code, but without seeing the xaml, I don't know if the binding is setup correctly.
public User User
{
get { return App.TheUser; }
set
{
if(App.TheUser!= null)
App.TheUser = value;
}
//User class
public class User : Base //Base class implements INotifyPropertyChanged
{
private int _id
public int Id {
get{
return this._id;
}
set{
this._id = value;
OnPropertyChanged("Id");
}
}
private string _name;
public string Name {
get{
return this._name;
}
set{
this._name = value;
OnPropertyChanged("Name");
}
}
private ObservableCollection<Product> _products;
public ObservableCollection<Product> Products
{
get{
return this._products;
}
set{
this._products = value;
OnPropertyChanged("Products");
}
}
}
}
so your listview is not bound to anything...
<ListView x:Name="UserListView"
ItemsSource={Binding Products}
SelectedItem="{Binding SelectedItemCommand}">

Resources