I'm getting data from api via async task:
public async Task<PostModel.Post[]> GetPostsAsync()
{
var client = new HttpClient();
var uri = new Uri("link here");
var response = await client.GetAsync(uri);
if (response.IsSuccessStatusCode)
{
var jsonString = await response.Content.ReadAsStringAsync();
var rootObject = JsonConvert.DeserializeObject<PostModel.Post[]>(jsonString);
return rootObject;
}
else
return null;
}
Also I've created a simple vertical view:
<ContentPage.Content>
<ListView x:Name="MainView">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Orientation="Vertical" HorizontalOptions="Fill" VerticalOptions="Fill" BackgroundColor="WhiteSmoke">
<Frame OutlineColor="Black">
<Label x:Name="Title" Text="{Binding Name}"/>
<Image x:Name="Image" Source="{Binding path}" />
</Frame>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</ContentPage.Content>
Wrote a custom cell for displaying data:
public CustomCell()
{
//instantiate items in views
var Image = new Image();
var NameLabel = new Label();
var horizontalLayout = new StackLayout() { BackgroundColor = Color.WhiteSmoke };
//set bindings
NameLabel.SetBinding(Label.TextProperty, new Binding("Name"));
Image.SetBinding(Image.SourceProperty, new Binding("path"));
Image.HorizontalOptions = LayoutOptions.Center;
Image.HeightRequest = 600;
Image.WidthRequest = 600;
NameLabel.FontSize = 24;
//add views to the view hierarchy
horizontalLayout.Children.Add(NameLabel);
horizontalLayout.Children.Add(Image);
//add to parent view
View = horizontalLayout;
}
Now I'd like to populate layout from the async task dynamically. For example if task gets 6 items - create 6 cells with data from each of the async task items. Any suggestions how can i do it? I'm completely green in xamarin.forms and just started trying it.
in OnAppearing, just set the source for your ListView
MainView.ItemSource = await GetPostsAsync();
Related
I have a gridview with the name "majorGridView" inside a gridview with the name "assessmenGridView" whose data is data binding
XAML:
<GridView x:Name="asesmenGridView">
<GridView.ItemTemplate>
<DataTemplate>
<UserControl>
<Grid>
<StackPanel
x:Name="judulStack"
Height="40">
<TextBlock
x:Name="judulT"
Text="{Binding Title}"/>
</StackPanel>
<GridView
x:Name="majorGridView">
<GridView.ItemTemplate>
<DataTemplate>
<UserControl>
<Grid>
<TextBlock
x:Name="kelasT"
Text="{Binding Major}"/>
</Grid>
</UserControl>
</DataTemplate>
</GridView.ItemTemplate>
</GridView>
</Grid>
</UserControl>
</DataTemplate>
</GridView.ItemTemplate>
</GridView>
How to display binding text on "majorGridView" ? Because if I use the code below, I will get an error message: "The name 'majorGridView' does not exist in the current context"
Code:
ObservableCollection<Ujian> ujiandatasource = new ObservableCollection<Ujian>();
ObservableCollection<Ujian> majordatasource = new ObservableCollection<Ujian>();
string urlPath = "https://pto.study.id/api/" + ((App)(App.Current)).AsesmenCode + "-do/s2/choose-exam/" + guru.ID;
var httpClient = new HttpClient(new HttpClientHandler());
httpClient.DefaultRequestHeaders.Add("Authorization",
string.Format("Bearer {0}", tkn));
var response = await httpClient.GetAsync(urlPath);
string jsonText = await response.Content.ReadAsStringAsync();
try
{
JsonArray jsonArray = JsonArray.Parse(jsonText);
foreach (JsonValue groupValue in jsonArray)
{
JsonObject groupObject = groupValue.GetObject();
JsonArray majorArray = groupObject["majors"].GetArray();
foreach(JsonValue majorValue in majorArray)
{
JsonObject majorObject = majorValue.GetObject();
string major = majorObject["major"].GetString();
Ujian ujian1 = new Ujian();
ujian1.Major = major + ", ";
majordatasource.Add(ujian1);
majorGridView.ItemsSource = majordatasource;
}
Ujian ujian = new Ujian();
ujian.Title = title;
ujiandatasource.Add(ujian);
asesmenGridView.ItemsSource = ujiandatasource;
}
Ujian.cs
class Ujian
{
public string Title { get; set; }
public string Major { get; set; }
}
}
The name 'majorGridView' does not exist in the current context"
majorGridView in the parent DataTemplate, so we can't access majorGridView with name directly. For this scenario, we often use nested collection apply the value generally. And here is similar case that you could refer to.
As described in the title, I'm working on a xamarin app, something like a dynamic image gallery. What I did so far works in uwp, but Android gives this error: "A unhandled exception occurred. No compatible code running. The selected debug engine does not support any code executing on the current thread". I suppose it is some bug in a code because a newly created app works fine both in uwp and in android.
Xaml code:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:Inżynierka"
x:Class="Inżynierka.MainPage">
<ContentPage.Content>
<ListView x:Name="MainView">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Orientation="Vertical" HorizontalOptions="Fill" VerticalOptions="Fill" BackgroundColor="White">
<Frame OutlineColor="Black">
<Label Text="{Binding Name}"/>
<Image Source="{Binding Image}" />
</Frame>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</ContentPage.Content>
code behind:
public class MainPageCode : ContentPage
{
public ObservableCollection<ViewModel.CellViewModel> Cells { get; set; }
public MainPageCode ()
{
Cells = new ObservableCollection<ViewModel.CellViewModel>();
ListView MainView = new ListView();
this.Title = "Inżynierka";
MainView.ItemTemplate = new DataTemplate(typeof(CustomCell));
Cells.Add(new ViewModel.CellViewModel { Name = "Test 1", Type = "Image", Image = "Test1.jpg" });
Cells.Add(new ViewModel.CellViewModel { Name = "Test 2", Type = "Image", Image = "Test2.png" });
Cells.Add(new ViewModel.CellViewModel { Name = "Test 3", Type = "Image", Image = "Test3.jpg" });
MainView.ItemsSource = Cells;
Content = MainView;
}
public class CustomCell : ViewCell
{
public CustomCell()
{
//instantiate items in views
var Image = new Image();
var NameLabel = new Label();
var Frame = new Frame() { OutlineColor = Color.Black };
var horizontalLayout = new StackLayout() { BackgroundColor = Color.WhiteSmoke };
//set bindings
NameLabel.SetBinding(Label.TextProperty, new Binding("Name"));
Image.SetBinding(Image.SourceProperty, new Binding("Image"));
Image.HorizontalOptions = LayoutOptions.Center;
Image.HeightRequest = 600;
Image.WidthRequest = 600;
NameLabel.FontSize = 24;
//add views to the view hierarchy
horizontalLayout.Children.Add(NameLabel);
horizontalLayout.Children.Add(Image);
//add to parent view
View = horizontalLayout;
}
}
}
app.xaml.cs:
public App ()
{
InitializeComponent();
MainPage = new NavigationPage();
MainPage.Navigation.PushAsync(new MainPage());
MainPage.Navigation.PushAsync(new MainPageCode());
}
Did you add that images to each platform location? e.g. drawable folder in android
The issue has been caused by using "ż" - polish diacritic character in assembly name.
I have an image binding on gridview with XAML below:
<Border x:Name="coverBox" Grid.Row="0" Margin="5,10,0,0" Width="230" Height="170" VerticalAlignment="Top" HorizontalAlignment="Left" BorderBrush="Gray" BorderThickness="1" Background="{x:Null}">
<Image x:Name="cover" Source="{Binding Thumbnail}" HorizontalAlignment="Center" Stretch="Uniform" AutomationProperties.Name="{Binding Title}" Width="230" Height="170"/>
</Border>
Code:
string urlPath1 = "http://..../API/sekolah";
var httpClient1 = new HttpClient(new HttpClientHandler());
var values1 = new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>("api_key", "...."),
new KeyValuePair<string, string>("limit", limit++.ToString()),
new KeyValuePair<string, string>("hal", noHal++.ToString())
};
var response1 = await httpClient1.PostAsync(urlPath1, new FormUrlEncodedContent(values1));
response1.EnsureSuccessStatusCode();
if (!response1.IsSuccessStatusCode)
{
busyIndicator.IsActive = false;
RequestException();
}
string jsonText1 = await response1.Content.ReadAsStringAsync();
JsonObject jsonObject1 = JsonObject.Parse(jsonText1);
JsonArray jsonData1 = jsonObject1["data"].GetArray();
foreach (JsonValue groupValue1 in jsonData1)
{
JsonObject groupObject2 = groupValue1.GetObject();
string thumbnail = groupObject2.ContainsKey("thumbnail") && groupObject2["thumbnail"] != null ? groupObject2["thumbnail"].GetString() : string.Empty;
ListingClass file1 = new ListingClass();
file1.Thumbnail = thumbnail;
listingDatasourceDetail.Add(file1);
}
listingGridView.ItemsSource = listingDatasourceDetail;
I want while still loading to take the image data from JSON, then show the paceholder images/SEKOLAH-place-holder-600.png first
How to add placeholder while still loading?
Wrap your cover Image within a Grid, then create another Image to display the placeholder png and place it behind cover.
Try add Loading event to Image :
private void myimage_Loading(FrameworkElement sender, object args)
{
Image myimage = (Image)sender;
myimage.Source = new BitmapImage(new Uri("ms-appx:///images/SEKOLAH-place-holder-600.png"));
}
I have a JSON like this:
I want to show the "rating" of data in gridview using the image below:
For example, the rating value is 5, it will be displayed as follows:
and if the rating is 3, it will be displayed as follows:
and if the rating is 0, it will be displayed as follows:
code:
try
{
loading.Visibility = Visibility.Visible;
string urlPath1 = "http://.../results.json?module=listing&page=1&token=3f63-dc43-c8d5-eb45-8cbf-b72d-9d98-800f";
var httpClient1 = new HttpClient(new HttpClientHandler());
var values1 = new List<KeyValuePair<string, string>>
{
};
HttpResponseMessage response1 = await httpClient1.GetAsync(urlPath1);
response1.EnsureSuccessStatusCode();
if (!response1.IsSuccessStatusCode)
{
busyIndicator.IsActive = false;
RequestException();
}
string jsonText1 = await response1.Content.ReadAsStringAsync();
JsonObject jsonObject1 = JsonObject.Parse(jsonText1);
JsonArray jsonData1 = jsonObject1["data"].GetArray();
foreach (JsonValue groupValue1 in jsonData1)
{
JsonObject groupObject2 = groupValue1.GetObject();
string title = groupObject2["title"].GetString();
double rating = groupObject2["rating"].GetNumber();
ListingClass file1 = new ListingClass();
file.Title = title;
file1.Rating = Convert.ToInt32(rating);
listingDatasource.Add(file1);
}
itemGridView.ItemsSource = listingDatasource;
busyIndicator.IsActive = false;
}
catch (HttpRequestException ex)
{
busyIndicator.IsActive = false;
RequestException();
}
How do you show the rating using the picture?
Note:
The maximum value of the rating is 5
It seems you should be able to use the third-party control, such as the UWP-Composition-Rating-Control.
W should be able to set the your images to the FilledImage and EmptyImage property of the Rating control. Then we can bind the number of the Rating in ListingClass class to the Value of the Rating control.
For example:
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<GridView Name="itemGridView">
<GridView.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Title}"></TextBlock>
<controls:Rating x:Name="Devils"
Value="{Binding Rating}"
Maximum="5"
ItemHeight="60"
ItemPadding="24"
StepFrequency="1"
EmptyImage="ms-appx:///Assets/empty.png"
FilledImage="ms-appx:///Assets/filled.png" />
</StackPanel>
</DataTemplate>
</GridView.ItemTemplate>
</GridView>
</Grid>
I'm having a problem with a ListView for Windows Phone:
I'm using a databinding to display all items in a folder, but when I try to iterate through them, I don't get a control, but the class I use to get the items in the LocalFolder of the app (The subjectpicker class)!
SubjectPicker class:
class SubjectPicker {
public static async Task<List<SubjectPicker>> SubjectData() {
List<string> Names = new List<string>();
List<Brush> Colors = new List<Brush>();
List<string> Items = new List<string>();
List<List<TestOrTask>> TestsAndTasks = new List<List<TestOrTask>>();
StorageFolder LocalFolder = ApplicationData.Current.LocalFolder;
var files = await LocalFolder.GetFilesAsync();
foreach (var file in files) {
//await file.DeleteAsync();
List<TestOrTask> TAT = new List<TestOrTask>();
Names.Add(file.DisplayName);
bool readItems = false;
var contents = await FileIO.ReadLinesAsync(file);
foreach (var content in contents) {
if (content.Contains("Subject Color")) {
string colorname = content.Replace("Subject Color: ", "");
Colors.Add(ColorConverter.fromString_Brush(colorname));
}
else if (content == "<Items>") readItems = true;
else if (content == "</Items>") readItems = false;
if (readItems == true && content != "") {
// Layout: <Name>: <Score>/<Maximum>|<YYYY>/<MM>/<DD>
string name = content.Split(':')[0];
string Score = content.Split(':')[1].Replace(" ", "");
string Date = content.Split('|')[1];
TestOrTask TOT = new TestOrTask(
name,
double.Parse(Score.Split('/')[0]),
double.Parse(Score.Split('/')[1]),
new DateTime(
Int32.Parse(Date.Split('/')[0]),
Int32.Parse(Date.Split('/')[1]),
Int32.Parse(Date.Split('/')[2])));
TAT.Add(TOT);
}
}
Items.Add("Aantal Testen & Taken: " + TAT.Count.ToString());
TestsAndTasks.Add(TAT);
}
var data = new List<SubjectPicker>();
for (int i = 0; i < Names.Count; i++) {
data.Add(new SubjectPicker(Names[i], Colors[i], Items[i], TestsAndTasks[i]));
}
return data;
}
public SubjectPicker(string name, Brush color, string itemstotal, List<TestOrTask> TestsAndTasks) {
PickerName = name;
PickerColor = color;
ItemTotal = itemstotal;
this.TestsAndTasks = TestsAndTasks;
}
public string PickerName { get; set; }
public Brush PickerColor { get; set; }
public string ItemTotal { get; set; }
public List<TestOrTask> TestsAndTasks = new List<TestOrTask>();
}
Xaml Code:
<Page.Resources>
<DataTemplate x:Key="SubjectTemplate">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Border Margin="0,9.5,0,0" Background="Transparent" >
<Rectangle Height="50" Width="50" Fill="{Binding PickerColor}" RadiusX="5" RadiusY="5"/>
</Border>
<StackPanel Grid.Column="1" Margin="14.5,0,0,0">
<TextBlock Text="{Binding PickerName}" Style="{ThemeResource ListViewItemTextBlockStyle}" />
<TextBlock Text="{Binding ItemTotal}" Style="{ThemeResource ListViewItemSubheaderTextBlockStyle}" />
</StackPanel>
</Grid>
</DataTemplate>
</Page.Resources>
<Page.BottomAppBar>
<CommandBar x:Name="AppBar" Visibility="Collapsed">
<AppBarButton x:Name="EditSubject" Icon="Edit" Label="Aanpassen" Click="EditSubject_Click"/>
<AppBarButton x:Name="DeleteSubject" Icon="Delete" Label="Verwijderen" Click="DeleteSubject_Click"/>
</CommandBar>
</Page.BottomAppBar>
<Grid x:Name="MainGrid" Loaded="MainGrid_Loaded">
<Controls:TopBarControl x:Name="TopBarControl" Margin="0" VerticalAlignment="Top" PageName="Vakken" ControlsVisible="All" Width="Auto" BackButtonClicked="TopBar_BackButtonClicked" AddButtonClicked="TopBar_AddButtonClicked" EditButtonClicked="TopBar_EditButtonClicked"/>
<Grid x:Name="ControlsGrid" Margin="0,50,0,-60" Tapped="ControlsGrid_Tapped">
<ListView x:Name="SubjectList" ItemsSource="{Binding}" ItemTemplate="{StaticResource SubjectTemplate}"/>
</Grid>
</Grid>
Void to iterate through:
private async Task SelectSubjects() {
for (int i = 0; i < SubjectList.Items.Count; i++) {
var control = SubjectList.Items[i];
Grid subject = control as Grid;
if (subject != null) {
subject.Background = new SolidColorBrush(SchoolToolsColors.AppColor);
await Task.Delay(TimeSpan.FromMilliseconds(50));
}
}
isSelecting = true;
AppBarVisible = Visibility.Visible;
}
Thanks in advance!!!
When iterating on databinded control you'll always get its underlying data.
You should Style.Triggers to alter UI based on data (changing background, showing/hiding controls, etc.).
However, there is a way to go with altering UI from C# but that would make XAML and code-behind tightly coupled => that introduces more complexity into your code - simply believe me, it is not what you want/need.