in my xamarin forms application registration part i need to fill profession and expertise field from a local json.The profession field is a dropdown and then expertise is also a dropdown and subpart of profession.From expertise field i need to select minimum one and maximum 3 options.
ProfessionalRegistrationPage.xaml.cs
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class ProfessionalRegistrationPage : ContentPage
{
public List<Profession> professions { get; set; }
public List<Profession> expertises { get; set; }
public ProfessionalRegistrationPage()
{
InitializeComponent();
professions = GetJsonDataProfession();
BindingContext = this;
professionPicker.ItemsSource = professions;
professionPicker.SelectedItem = professions[0];
}
private List<Profession> GetJsonDataProfession()
{
string jsonFileName = "profession.json";
ProfessionList ObjProfessionList = new ProfessionList();
var assembly = typeof(MainPage).GetTypeInfo().Assembly;
Stream stream = assembly.GetManifestResourceStream($"{ assembly.GetName().Name}.{ jsonFileName}");
using (var reader = new StreamReader(stream))
{
var jsonString = reader.ReadToEnd();
ObjProfessionList = JsonConvert.DeserializeObject<ProfessionList>(jsonString);
}
return ObjProfessionList.professions;
}
private void professionPicker_SelectedIndexChanged(object sender, EventArgs e)
{
Picker picker = (Picker)sender;
int selectedIndex = picker.SelectedIndex;
if (selectedIndex != -1)
{
expertises = professions[selectedIndex].expertises;
expertisePicker.ItemsSource = expertises;
expertisePicker.SelectedItem = expertises[0];
}
}
}
public partial class ProfessionList
{
[JsonProperty("professions")]
public List<Profession> professions { get; set; }
}
public partial class Profession
{
[JsonProperty("expertises")]
public List<Profession> expertises { get; set; }
[JsonProperty("professionname")]
public string ProfessionName { get; set; }
[JsonProperty("expertisename")]
public string ExpertiseName { get; set; }
}
ProfessionalRegistrationPage.xaml
<StackLayout Orientation="Vertical">
<Label Text="Profession"
TextColor="{StaticResource BackgroundGradientStart}">
</Label>
<Frame BackgroundColor="Transparent"
BorderColor="{StaticResource BackgroundGradientStart}"
Padding="0"
Margin="10"
CornerRadius="15"
HorizontalOptions="FillAndExpand">
<Picker
x:Name="professionPicker"
SelectedIndexChanged="professionPicker_SelectedIndexChanged"
ItemDisplayBinding="{Binding ProfessionName}"
ItemsSource="{Binding profession}"
TextColor="{StaticResource White}"/>
</Frame>
</StackLayout>
<StackLayout Orientation="Vertical">
<Label Text="Expertise"
TextColor="{StaticResource BackgroundGradientStart}">
</Label>
<Frame
BackgroundColor="Transparent"
BorderColor="{StaticResource BackgroundGradientStart}"
Padding="0"
Margin="10"
CornerRadius="15"
HorizontalOptions="FillAndExpand">
<Picker x:Name="expertisePicker"
ItemDisplayBinding="{Binding ExpertiseName}"
ItemsSource="{Binding profession}"
TextColor="{StaticResource White}"/>
</Frame>
</StackLayout>
profession.json
{
"professions": [
{
"professionname": "Doctor",
"expertises": [
{
"expertisename": "Pediatric"
},
{
"expertisename": "Ortho"
}
]
},
{
"professionname": "Engineer",
"expertises": [
{
"expertisename": "Software"
},
{
"expertisename": "Civil"
}
]
}
]
}
i used picker here.but picker doesnot support more than one item selection.
otherwise its works perfectly.
i think i need to place a popup and in pop up page i need to fix a listview and checkbox. but i dont now how to do that. I am new to xamarin.
I am trying to bind a ObservableCollection on a ListView ItemsSource but it doesn't show anything to me, tried binding inside code, on the xaml..
public partial class ReadPage : ContentPage
{
private CarregarClientes _CClientes = new CarregarClientes();
private MySQLCon _db = new MySQLCon();
private MySQLConOverloads _over = new MySQLConOverloads();
private MySQLiteCon _dbSqLiteCon = new MySQLiteCon();
private MySQLiteConOverloads _oversqlite = new MySQLiteConOverloads();
//MY OBSERVABLECOLLECTION DEFINITION -----------------------------
public ObservableCollection<Clientes> _ClientesList { get; set; }
private string _tabela = "Clientes";
public ReadPage()
{
InitializeComponent();
backBtn.Clicked += async (s, o) => await Navigation.PopModalAsync();
//Method used to populate the ObservableCollection (_ClientesList);
PopularObservableCollection();
}
I am defining the ObservableCollection inside my ReadPage class, then populating it with a method called PopularObservableCollection.
public void PopularObservableCollection()
{
_ClientesList = new ObservableCollection<Clientes>();
int quantidadeDados = _CClientes.CNumeroItems() -1;
List<string> id = _CClientes.Cid();
List<string> debito = _CClientes.CDebito();
List<string> endereco = _CClientes.CEndereco();
List<string> nome = _CClientes.CNome();
List<string> observacao = _CClientes.CObservacao();
List<string> saldo = _CClientes.CSaldo();
List<string> telefone = _CClientes.CTelefone();
for (int i = 0; i <= quantidadeDados; i++)
{
_ClientesList.Add(new Clientes
{
id = id[i],
Debito = debito[i],
Endereco = endereco[i],
Nome = nome[i],
Observacao = observacao[i],
Saldo = saldo[i],
Telefone = telefone[i]
});
}
}
Clientes.cs:
public class Clientes : BindableObject
{
public string id { get; set; }
public string Nome { get; set; }
public string Endereco { get; set; }
public string Telefone { get; set; }
public string Debito { get; set; }
public string Saldo { get; set; }
public string Observacao { get; set; }
}
XAML:
<ListView
BindingContext="{Binding Source={x:Reference MyPage}, Path=.}"
x:Name="readListView"
BackgroundColor="PaleVioletRed"
HasUnevenRows="True"
CachingStrategy="RecycleElement"
HorizontalOptions="FillAndExpand"
ItemsSource="{Binding _ClientesList}"
VerticalOptions="FillAndExpand"
ItemTapped="ReadListView_OnItemTapped">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid>
<Label Text="Id:" Grid.Row="0"/>
<Label Text="{Binding id}" Grid.Row="0" Margin="10,0,0,0"/>
<Label Text="{Binding Nome}" Grid.Row="1" />
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
I have implemented a slider menu as ListView and can easily assign the color to any icon in the menu. However, I am trying to change the color of the ListView row that was selected (specifically the icon). I have tried using converter, but the value never changes.
Here is my xaml:
<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"
mc:Ignorable="d"
x:Class="SycretBeauty.Screens.MainMenuMaster"
Title="Master"
xmlns:controls="clr-namespace:SycretBeauty;assembly=SycretBeauty"
xmlns:converters="clr-namespace:SycretBeauty.Converters;assembly=SycretBeauty"
BackgroundColor="{StaticResource color_menu_item_background}"
IconImageSource="images/menu.png">
<StackLayout
BackgroundColor="{StaticResource color_header_banner_background}">
<Image
VerticalOptions="Center"
HorizontalOptions="FillAndExpand"
Source="images/bannerVialang.png"
Margin="0,30,0,20">
</Image>
<controls:SuperListView
x:Name="MenuItemsListView"
SeparatorVisibility="Default"
HasUnevenRows="False"
Margin="0,0,0,0"
RowHeight="120"
IsScrollingEnable="False"
SelectedItem="{Binding SelectedItem}"
ItemsSource="{Binding MenuItems}"
BackgroundColor="{StaticResource color_menu_item_background}">
<d:ListView.ItemsSource>
<x:Array Type="{x:Type x:String}">
<x:String>Записаться</x:String>
<x:String>Акции</x:String>
<x:String>Уведомления</x:String>
<x:String>Личный кабинет</x:String>
<x:String>Контакты</x:String>
<x:String>Отзывы</x:String>
<x:String>Галерея</x:String>
<x:String>Поделиться</x:String>
</x:Array>
</d:ListView.ItemsSource>
<controls:SuperListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid
VerticalOptions="FillAndExpand"
ColumnSpacing="0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="60"/>
<ColumnDefinition Width="10"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<StackLayout
Grid.Column="0"
BackgroundColor="{StaticResource color_menu_item_background}"
VerticalOptions="FillAndExpand"
HorizontalOptions="FillAndExpand">
<controls:IconView
VerticalOptions="CenterAndExpand"
HeightRequest="35"
Foreground="{Binding ForegroundColor}"
Source="{Binding ImgSource}">
</controls:IconView>
</StackLayout>
<Label
Grid.Column="0"
Text="{Binding PushCount}"
IsVisible="{Binding PushUnread}"
d:Text="23"
d:IsVisible="True"
HorizontalOptions="FillAndExpand"
VerticalOptions="FillAndExpand"
HorizontalTextAlignment="Center"
VerticalTextAlignment="Center"
TextColor="White"/>
<StackLayout Grid.Column="1"
BackgroundColor="{StaticResource color_menu_item_background}"
VerticalOptions="CenterAndExpand"
HorizontalOptions="FillAndExpand">
</StackLayout>
<Label Grid.Column="2"
BackgroundColor="{StaticResource color_menu_item_background}"
VerticalOptions="FillAndExpand"
VerticalTextAlignment="Center"
Text="{Binding Title}"
d:Text="{Binding .}"
Style="{StaticResource font_menu_item_text}"/>
</Grid>
</ViewCell>
</DataTemplate>
</controls:SuperListView.ItemTemplate>
</controls:SuperListView>
</StackLayout>
Here is the model:
public class MainMenuItem
{
public MainMenuItem()
{
TargetType = typeof(MainMenuItem);
}
public int Id { get; set; }
public string ImgSource { get; set; }
public string Title { get; set; }
public Type TargetType { get; set; }
public Action ItemSelected { get; set; }
public string PushCount { get; set; }
public bool PushUnread { get; set; }
public Color ForegroundColor { get; set; }
}
And here is cs:
public partial class MainMenuMaster : ContentPage
{
public ListView ListView;
public AppContext Context { get; set; }
private float rowHeight;
public MainMenuMaster()
{
InitializeComponent();
BindingContext = new ViewModel();
ListView = MenuItemsListView;
ListView.SizeChanged += ListView_SizeChanged;
}
private void ListView_SizeChanged(object sender, EventArgs e)
{
var h = ListView.Height;
rowHeight = (float)(h / 8);
ListView.RowHeight = (int)rowHeight;
}
protected override void OnAppearing()
{
base.OnAppearing();
(BindingContext as ViewModel).UpdatePushCount(Context.UnreadPushCount);
}
public class ViewModel : INotifyPropertyChanged
{
public ObservableCollection<MainMenuItem> MenuItems { get; set; }
public AppContext Context { get; set; }
public ViewModel()
{
MenuItems = new ObservableCollection<MainMenuItem>(new[]
{
new MainMenuItem {
Id = 0,
ImgSource = "images/signup.png",
Title = "Записаться",
TargetType = typeof(OnlineSignupScreen),
ItemSelected = () => {
Context.SelectSalonStart(typeof(OnlineSignupScreen));
},
ForegroundColor = Color.Gray
},
new MainMenuItem {
Id = 1,
ImgSource = "images/promos",
Title = "Акции",
TargetType = typeof(PromosScreen),
ForegroundColor = Color.Gray,
},
new MainMenuItem {
Id = 2,
ImgSource = "images/notify",
Title = "Уведомления",
TargetType = typeof(NotificationsScreen),
ForegroundColor = Color.Gray
},
new MainMenuItem {
Id = 3,
ImgSource = "images/personal",
Title = "Личный кабинет",
TargetType = typeof(PersonalInfoScreen),
ForegroundColor = Color.Gray
},
new MainMenuItem {
Id = 4,
ImgSource = "images/contacts",
Title = "Контакты",
TargetType = typeof(ContactsScreen),
ItemSelected = () => {
Context.SelectSalonStart(typeof(ContactsScreen));
},
ForegroundColor = Color.Gray
},
new MainMenuItem {
Id = 5,
ImgSource = "images/feedback.png",
Title = "Отзывы",
TargetType = typeof(FeedbackScreen),
ItemSelected = () => {
Context.SelectSalonStart(typeof(FeedbackScreen));
},
ForegroundColor = Color.Gray
},
new MainMenuItem {
Id = 6,
ImgSource = "images/gallery.png",
Title = "Галерея",
TargetType = typeof(GalleryScreen),
ItemSelected = () => {
Context.SelectSalonStart(typeof(GalleryScreen));
},
ForegroundColor = Color.Gray
},
new MainMenuItem {
Id = 7,
ImgSource = "images/share",
Title = "Поделиться",
TargetType = typeof(ShareWithFriendScreen),
ForegroundColor = Color.Gray
}
});
}
public void UpdatePushCount(int count)
{
MenuItems[2].ImgSource = count > 0 ? "images/badge" : "images/notify";
MenuItems[2].PushCount = count.ToString();
MenuItems[2].PushUnread = count > 0;
}
#region INotifyPropertyChanged Implementation
public event PropertyChangedEventHandler PropertyChanged;
void OnPropertyChanged([CallerMemberName] string propertyName = "")
{
if (PropertyChanged == null)
return;
PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
}
}
I also have MainMenu where I control the navigation and have ListView_onSelected method, but even there I can't change the color of the icon.
Please achieve INotifyPropertyChanged interface for MainMenuItem.cs
Then change the ForegroundColor attribute like following code.
public class MainMenuItem: INotifyPropertyChanged
{
public MainMenuItem()
{
TargetType = typeof(MainMenuItem);
}
public int Id { get; set; }
public string ImgSource { get; set; }
public string Title { get; set; }
public Type TargetType { get; set; }
public Action ItemSelected { get; set; }
public string PushCount { get; set; }
public bool PushUnread { get; set; }
private Color _foregroundColor;
public Color ForegroundColor
{
get { return _foregroundColor; }
set
{
_foregroundColor = value;
OnPropertyChanged("ForegroundColor");
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
I do not what is achievement about controls:SuperListView and controls:IconView, I used listview and ImageButton to replace it, If item was selected. We can change the ImageButton's background color for testing.
<ImageButton
Source="{Binding ImgSource}"
VerticalOptions="CenterAndExpand"
HeightRequest="35"
BackgroundColor="{Binding ForegroundColor}"
>
</ImageButton>
private void MenuItemsListView_ItemSelected(object sender, SelectedItemChangedEventArgs e)
{
// MainMenuItem mainMenuItem = sender as MainMenuItem;
MainMenuItem mainMenuItem = viewModel.MenuItems[e.SelectedItemIndex];
mainMenuItem.ForegroundColor = Color.Red;
}
Here is running GIF.
I have created in my viewmodel Dictionary<string, string>.
public ObservableCollection<Dictionary<string, string>> ObjectDetailsRows { get; set; } = new ObservableCollection<Dictionary<string, string>>();
public void SomeMethod()
{
...
//add some items to a dictionary..
...
OnPropertyChanged(nameof(ObjectDetailsRows));
}
On my XAML part Im trying to do this:
<ListView
ItemsSource="{Binding Path=ObjectDetailsRows}">
<ListView.ItemTemplate>
<DataTemplate>
<TextCell TextColor="Black" Text="{Binding Key}" Detail="{Binding Value}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
I can clearly see that I binded correctly my dictionary, I can see lines on my page (in emulator).
If I remove binding for example Key and put just Text="some text" it works and populates all 26 rows, based on provided dictionary (which has 26 objects).
But when I set just like this Text="{Bindings Key}" or Text="{Bindings Value}" it gives me nothing.
UPDATE:
public class CustomPin : Pin
{
//string base64
public string PinIcon { get; set; }
public Color Color { get; set; }
public InfoBoxMapModel InfoBox { get; set; } = new InfoBoxMapModel();
public int Id { get; set; }
}
public class InfoBoxMapModel
{
//base64
public string ImageString { get; set; }
public List<string> Items { get; set; } = new List<string>();
public Dictionary<string, string> ItemsTest { get; set; } = new Dictionary<string, string>();
}
private async Task GetObjectInstancesList()
{
var objectsResponse = await ApiServiceProvider.GetObjectInstances();
Device.BeginInvokeOnMainThread(() =>
{
ListOfObjects = new ObservableCollection<CustomPin>();
if (objectsResponse.Succeeded)
{
foreach (var item in objectsResponse.ObjectInstances)
{
CustomPin pinData = new CustomPin();
pinData.Id = item.IdObjectInstance;
pinData.Label = item.ObjectClassName;
if (item.Points != null)
{
pinData.Position = new Position(item.Points.FirstOrDefault().Latitude, item.Points.FirstOrDefault().Longitude);
}
else
{
//add polygon
}
Guid id = Guid.NewGuid();
foreach (var s in item.Strings)
{
pinData.InfoBox.ItemsTest.Add(s.ClassParameterName+id + ": ", s.StringValue);
}
foreach (var i in item.Integers)
{
if (i.IntValue.HasValue)
{
pinData.InfoBox.ItemsTest.Add(i.ClassParameterName+id +": ", i.IntValue.Value.ToString());
}
}
foreach (var date in item.Dates.Take(1))
{
pinData.InfoBox.ItemsTest.Add(date.ClassParameterName + id + ": ", date.DateValue.ToString());
}
ListOfObjects.Add(pinData);
}
}
TemporalData.ObjectsData = ListOfObjects;
OnPropertyChanged(nameof(ListOfObjects));
OnPropertyChanged(nameof(TemporalData.ObjectsData));
});
}
Ive tried this xaml:
<ListView
ItemsSource="{Binding ListOfObjects}">
<ListView.ItemTemplate>
<DataTemplate>
<TextCell TextColor="Black" Text="{Binding InfoBox.ItemsTest}" Detail="{Binding Value}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
I update ObservableCollection List but UI is not updating from Tab Page
I also clear List then Assign new list, Value of list is change but UI is not updated
public ObservableCollection<Dashboard> DetailsList { get; set; } = new ObservableCollection<Dashboard>();
//API Call
details = await _clientAPI.getDashboardDetails(id);
if (details != null)
{
DetailsList.Clear();
foreach (var item in details)
{
DetailsList.Add(item);
}
}
I think you miss to binding the context. Add the code below.
this.BindingContext = this;
I make a code sample for your reference. I am not sure what your Model, I use a simple model to test.
Page1.xaml.cs
public partial class Page1 : ContentPage
{
public ObservableCollection<Dashboard> DetailsList { get; set; }
public Page1()
{
InitializeComponent();
DetailsList = new ObservableCollection<Dashboard>()
{
new Dashboard(){ Name="AA", Country="CountryA"},
new Dashboard(){ Name="BB", Country="CountryB"},
};
this.BindingContext = this;
}
private void btnUpdate_Clicked(object sender, EventArgs e)
{
List<Dashboard> details = new List<Dashboard>();
details.Add(new Dashboard() { Name = "CC", Country = "CountryC" });
details.Add(new Dashboard() { Name = "DD", Country = "CountryD" });
if (details != null)
{
DetailsList.Clear();
foreach (var item in details)
{
DetailsList.Add(item);
}
}
}
}
public class Dashboard
{
public string Name { get; set; }
public string Country { get; set; }
}
Xaml:
<ContentPage.Content>
<StackLayout>
<Button
x:Name="btnUpdate"
Clicked="btnUpdate_Clicked"
Text="Update" />
<ListView ItemsSource="{Binding DetailsList}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Orientation="Horizontal">
<Label Text="{Binding Name}" />
<Label Text="{Binding Country}" />
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</ContentPage.Content>
Updated:
public ObservableCollection<Dashboard> DetailsList { get; set; } = new ObservableCollection<Dashboard>();
//API Call
details = await _clientAPI.getDashboardDetails(id);
if (details != null)
{
DetailsList.Clear();
foreach (var item in details)
{
DetailsList.Add(item);
}
}
YourGridView.ItemSource =DetailsList;
YourGridView.ItemSource =DetailsList
You are missing this line. This code - it just assigns ObservableCollection to gridview (which you want to display the data)
Thanks!!!