I have a lazy loading in gridview whose data is taken from JSON.
Sample of JSON:
{
"error": false,
"total_data": 32,
"data_per_page": "16",
"current_page": 1,
"total_page": 2,
"current_total": 16,
"data": [
{
"id": "2613",
"judul": "Kamus ID EN",
"slug": "kamus-id-en",
"cover": "https://mhnkp2.com/src/umum/cover/kamus_ID_EN-thumb.jpg",
"path": "https://mhnkp2.com/school/dl/dodl/2613",
"ukuran": "3504835",
"formated_size": "3.34 MB",
"fname": "kamus_ID_EN.pdf",
"publish": "1",
"urgent": "400",
"kelas": "0",
"nama_kelas": "Umum"
},
XAML:
<Grid x:Name="content" Grid.Row="1" Loaded="MainGrid_Loaded">
<GridView
x:Name="itemGridView"
Loaded="itemGridView_Loaded">
<GridView.ItemTemplate>
<DataTemplate>
<Grid
Width="135"
Height="280"
Margin="5,5,5,5"
Background="White">
<TextBlock
x:Name="title"
Margin="0,0,10,10"
FontSize="14"
FontWeight="SemiBold"
Foreground="Black"
Style="{StaticResource TitleTextBlockStyle}"
Text="{Binding Judul}"
TextWrapping="Wrap" />
</Grid>
</DataTemplate>
</GridView.ItemTemplate>
</GridView>
Code:
ObservableCollection<Buku> datasource = new ObservableCollection<Buku>();
int offset = 0;
private void MainGrid_Loaded(object sender, RoutedEventArgs e)
{
itemGridView.ItemsSource = datasource;
Umum(1);
}
public class Buku
{
public string Judul { get; set; }
}
private async void Umum(int offset)
{
urlPath = "https://mhnkp2.com/school/api-v3/fetch/umum";
var httpClient = new HttpClient(new HttpClientHandler());
var values = new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>("halaman", offset.ToString()),
new KeyValuePair<string, string>("limit", "16"),
new KeyValuePair<string, string>("SCH-API-KEY", "SCH_KEnaBiDeplebt")
};
var response = await httpClient.PostAsync(urlPath, new FormUrlEncodedContent(values));
response.EnsureSuccessStatusCode();
string jsonText = await response.Content.ReadAsStringAsync();
try
{
double total = groupObject1["total_data"].GetNumber();
double pages = groupObject1["total_page"].GetNumber();
double page = groupObject1["current_page"].GetNumber();
Buku file = new Buku();
file.PageNo = Convert.ToInt32(page);
file.Pages = Convert.ToInt32(pages);
file.Total = Convert.ToInt32(total);
JsonArray jsonData1 = jsonObject["data"].GetArray();
foreach (JsonValue groupValue1 in jsonData1)
{
JsonObject groupObject2 = groupValue1.GetObject();
string title = groupObject2["judul"].GetString();
Buku file1 = new Buku();
file1.Judul = title;
datasource.Add(file1);
}
itemGridView.ItemsSource = datasource;
}
}
private void itemGridView_Loaded(object sender, RoutedEventArgs e)
{
ScrollViewer viewer = GetScrollViewer(this.itemGridView);
viewer.ViewChanged += Viewer_ViewChanged;
}
private void Viewer_ViewChanged(object sender, ScrollViewerViewChangedEventArgs e)
{
ScrollViewer view = (ScrollViewer)sender;
double progress = view.VerticalOffset / view.ScrollableHeight;
//Debug.WriteLine(progress);
if (progress > 0.7 && !incall && !endoflist)
{
incall = true;
busyindicator.IsActive = true;
Umum(++offset);
}
}
public static ScrollViewer GetScrollViewer(DependencyObject depObj)
{
if (depObj is ScrollViewer) return depObj as ScrollViewer;
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
{
var child = VisualTreeHelper.GetChild(depObj, i);
var result = GetScrollViewer(child);
if (result != null) return result;
}
return null;
}
I am having a problem, that the gridview should display data on pages 1 and 2, but in the gridview the data displayed on page 2 is a repetition of data on page 1, as shown below:
How to fix it?
Note:
The page uses the "offset" parameter
The page limit is "total_page" in JSON
you just need to pass the offset value to MainGrid_Loaded and set offset zero to one
ObservableCollection<Buku> datasource = new ObservableCollection<Buku>();
int offset = 1; // set offset zero to one
private void MainGrid_Loaded(object sender, RoutedEventArgs e)
{
itemGridView.ItemsSource = datasource;
Umum(offset); // just change 1 to offset
}
public class Buku
{
public string Judul { get; set; }
}
private async void Umum(int offset)
{
urlPath = "mhnkp2.com/school/api-v3/fetch/ktsp2006/kelas/1";
var httpClient = new HttpClient(new HttpClientHandler());
var values = new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>("halaman", offset.ToString()),
new KeyValuePair<string, string>("limit", "16"),
new KeyValuePair<string, string>("SCH-API-KEY", "SCH_KEnaBiDeplebt")
};
var response = await httpClient.PostAsync(urlPath, new FormUrlEncodedContent(values));
response.EnsureSuccessStatusCode();
string jsonText = await response.Content.ReadAsStringAsync();
try
{
double total = groupObject1["total_data"].GetNumber();
double pages = groupObject1["total_page"].GetNumber();
double page = groupObject1["current_page"].GetNumber();
Buku file = new Buku();
file.PageNo = Convert.ToInt32(page);
file.Pages = Convert.ToInt32(pages);
file.Total = Convert.ToInt32(total);
JsonArray jsonData1 = jsonObject["data"].GetArray();
foreach (JsonValue groupValue1 in jsonData1)
{
JsonObject groupObject2 = groupValue1.GetObject();
string title = groupObject2["judul"].GetString();
Buku file1 = new Buku();
file1.Judul = title;
datasource.Add(file1);
}
itemGridView.ItemsSource = datasource;
}
}
private void itemGridView_Loaded(object sender, RoutedEventArgs e)
{
ScrollViewer viewer = GetScrollViewer(this.itemGridView);
viewer.ViewChanged += Viewer_ViewChanged;
}
private void Viewer_ViewChanged(object sender, ScrollViewerViewChangedEventArgs e)
{
ScrollViewer view = (ScrollViewer)sender;
double progress = view.VerticalOffset / view.ScrollableHeight;
//Debug.WriteLine(progress);
if (progress > 0.7 && !incall && !endoflist)
{
incall = true;
busyindicator.IsActive = true;
Umum(offset++);
}
}
public static ScrollViewer GetScrollViewer(DependencyObject depObj)
{
if (depObj is ScrollViewer) return depObj as ScrollViewer;
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
{
var child = VisualTreeHelper.GetChild(depObj, i);
var result = GetScrollViewer(child);
if (result != null) return result;
}
return null;
}
Related
I am trying to disable a Tile when I start work on Azure.
As you can see, I am using Fody to handle all my PropertyChanged events, but for some reason, it doesn't want to disable and enable again when I am finished.
If you take a look, when I start my work, I put in the explicitly '''IsActive = false'''
UI
<Style x:Key="TileStyle" TargetType="{x:Type mah:Tile}">
<Setter Property="FontWeight" Value="Bold" />
<Style.Triggers>
<Trigger Property="IsEnabled" Value="True">
<Setter Property="Background" Value="{Binding TileColor}" />
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Background" Value="#9A9A9A" />
</Trigger>
</Style.Triggers>
</Style>
</Window.Resources>
<Border Background="#3700b3" CornerRadius="20">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition />
</Grid.RowDefinitions>
<Ellipse
Margin="10"
Fill="Crimson"
HorizontalAlignment="Right"
Width="30" Height="30">
<behaviours:Interaction.Triggers>
<behaviours:EventTrigger EventName="MouseLeftButtonDown">
<behaviours:InvokeCommandAction Command="{Binding ExitCommand}" PassEventArgsToCommand="True"/>
</behaviours:EventTrigger>
</behaviours:Interaction.Triggers>
</Ellipse>
<ItemsControl Grid.Row="1" ItemsSource="{Binding Tiles}" Grid.ColumnSpan="2">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Rows="2" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<mah:Tile
Title="{Binding TileTitle}"
Width="200"
Height="200"
Margin="10"
materialDesign:RippleAssist.RippleOnTop="True"
Command="{Binding TileCommand}"
CommandParameter="{Binding TileIdentifier}"
IsEnabled="{Binding IsTileActive}"
Style="{StaticResource TileStyle}"
TitleFontSize="14">
<Label
HorizontalContentAlignment="Center"
VerticalContentAlignment="Center"
Content="{Binding TileIcon}"
FontFamily="{StaticResource Material}"
FontSize="120"
Foreground="White" />
</mah:Tile>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
</Border>
And the view Model
[AddINotifyPropertyChangedInterface]
public class MainWindowViewModel {
public Command ExitCommand { get; set; }
public Command AzureCommand { get; set; }
public ObservableCollection<Tile>? Tiles { get; set; }
public List<char> Words { get; set; }
public MainWindowViewModel() {
AzureCommand = new Command(AzureActionAsync);
ExitCommand = new Command(ExiAction);
InitCollection();
Words = new List<char>();
}
private void InitCollection() {
Tiles = new ObservableCollection<Tile>()
{
new Tile(){
IsTileActive = true,
TileTitle = Lang.AudioToText,
TileIdentifier = (int)TilesIdentifiers.Audio,
TileCommand = AzureCommand,
TileIcon = IconFont.VolumeHigh
},
new Tile(){
IsTileActive = true,
TileIdentifier = (int)TilesIdentifiers.Video,
TileTitle = Lang.VideoToText,
TileCommand = AzureCommand,
TileIcon = IconFont.FileVideo
},
new Tile(){
IsTileActive = true,
TileTitle = Lang.ImageToText,
TileIdentifier = (int)TilesIdentifiers.Ocr,
TileCommand = AzureCommand,
TileIcon = IconFont.EyeCircle
},
new Tile(){
IsTileActive = true,
TileTitle = Lang.TranslateDocument,
TileIdentifier = (int)TilesIdentifiers.document,
TileCommand = AzureCommand,
TileIcon = IconFont.FileDocument
},
new Tile(){
IsTileActive = true,
TileIdentifier = (int)TilesIdentifiers.Account,
TileTitle = Lang.Account,
TileCommand = AzureCommand,
TileIcon = IconFont.Account
},
new Tile(){
IsTileActive = true,
TileIdentifier = (int)TilesIdentifiers.About,
TileTitle = Lang.About,
TileCommand = AzureCommand,
TileIcon = IconFont.Help
}
};
}
private void ExiAction() {
Application.Current.Shutdown();
}
private async void AzureActionAsync(object obj) {
OpenFileDialog dlg;
var AudioFolderPath = CreateFolder(ConstantsHelpers.AUDIO);
const string ext = ".wav";
switch (obj) {
case (int)TilesIdentifiers.Audio:
var AudioName = CreateDialog(out dlg, ConstantsHelpers.AUDIO);
var Audiofilename = Path.Combine(AudioFolderPath, $"{AudioName}{ext}");
Converter(dlg, Audiofilename, out _, out _);
await ConvertToTextAsync(Audiofilename);
break;
case (int)TilesIdentifiers.Video:
var VideoName = CreateDialog(out dlg, ConstantsHelpers.VIDEO);
var VideoFilename = Path.Combine(AudioFolderPath, $"{VideoName}{ext}");
var inputFile = new MediaFile { Filename = dlg.FileName };
var outputFile = new MediaFile { Filename = VideoFilename };
var options = new ConversionOptions {
AudioSampleRate = AudioSampleRate.Hz22050
};
var engine = new Engine();
if (!string.IsNullOrEmpty(inputFile.Filename)) {
engine.Convert(inputFile, outputFile, options);
}
break;
case (int)TilesIdentifiers.Ocr:
break;
case (int)TilesIdentifiers.Account:
Debug.WriteLine("Account", "Debug");
break;
case (int)TilesIdentifiers.document:
var storageService = new AzureStorageService();
var DocumentName = CreateDialog(out dlg, ConstantsHelpers.DOCUMENTS);
var path = CreateFolder(ConstantsHelpers.TRANSLATIONS);
if (!string.IsNullOrEmpty(dlg.FileName)) {
var sourceUri = await storageService.UploadToAzureBlobStorage(Path.GetFullPath(dlg.FileName));
var targetUri = await storageService.SaveFromdAzureBlobStorage(Path.GetFullPath(dlg.FileName), path);
await AzureTranslationService.TranslatorAsync(sourceUri, targetUri);
}
break;
case (int)TilesIdentifiers.About:
Debug.WriteLine("about", "Debug");
break;
}
}
private void Converter(OpenFileDialog dlg, string filename, out Mp3FileReader? mp3, out WaveStream? ws) {
if (!string.IsNullOrEmpty(dlg.FileName)) {
mp3 = new Mp3FileReader(dlg.FileName);
ws = WaveFormatConversionStream.CreatePcmStream(mp3);
WaveFileWriter.CreateWaveFile(filename, ws);
} else {
mp3 = null;
ws = null;
return;
}
}
private string? CreateDialog(out OpenFileDialog dlg, string type) {
var filter = string.Empty;
switch (type) {
case ConstantsHelpers.AUDIO:
filter = ConstantsHelpers.AUDIOFILES;
break;
case ConstantsHelpers.VIDEO:
filter = ConstantsHelpers.VIDEOFILES;
break;
case ConstantsHelpers.DOCUMENTS:
filter = ConstantsHelpers.DOCUMENTSFIILES;
break;
case ConstantsHelpers.IMAGES:
filter = ConstantsHelpers.IMAGEFILES;
break;
default:
break;
}
dlg = new OpenFileDialog {
Filter = filter,
};
var res = dlg.ShowDialog();
if (res == true) {
return Path.GetFileNameWithoutExtension(dlg.FileName);
}
return null;
}
private static string CreateFolder(string FolderName = ConstantsHelpers.AUDIO) {
var directoryPath = Directory.CreateDirectory(Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments),
ConstantsHelpers.TRANSCRIBEME, FolderName));
return directoryPath.FullName;
}
private async Task ConvertToTextAsync(string FilePath) {
//Configure speech service
var config = SpeechConfig.FromSubscription(ConstantsHelpers.AZURE_KEY, ConstantsHelpers.AZURE_REGION);
config.EnableDictation();
//Configure speech recognition
var taskCompleteionSource = new TaskCompletionSource<int>();
using var audioConfig = AudioConfig.FromWavFileInput(FilePath);
using var speechRecognizer = new SpeechRecognizer(config, audioConfig);
speechRecognizer.Recognizing += SpeechRecognizer_Recognizing;
speechRecognizer.Recognized += SpeechRecognizer_Recognized;
speechRecognizer.SessionStarted += SpeechRecognizer_SessionStarted;
speechRecognizer.SessionStopped += SpeechRecognizer_SessionStopped;
await speechRecognizer.StartContinuousRecognitionAsync().ConfigureAwait(false);
Task.WaitAny(new[] { taskCompleteionSource.Task });
await speechRecognizer.StopContinuousRecognitionAsync().ConfigureAwait(false);
}
private void SpeechRecognizer_SessionStopped(object? sender, SessionEventArgs e) {
Tiles![0].IsTileActive = true;
var filename = "Azure.docx";
var pathToSave = CreateFolder(ConstantsHelpers.TRANSCRIPTIONS);
Path.Combine(pathToSave, filename);
var sb = new StringBuilder();
foreach (var item in Words) {
sb.Append(item);
}
using var document = new WordDocument();
document.EnsureMinimal();
document.LastParagraph.AppendText(sb.ToString());
// Find all the text which start with capital letters next to period (.) in the Word document.
//For example . Text or .Text
TextSelection[] textSelections = document.FindAll(new Regex(#"[.]\s+[A-Z]|[.][A-Z]"));
for (int i = 0; i < textSelections.Length; i++) {
WTextRange textToFind = textSelections[i].GetAsOneRange();
//Replace the period (.) with enter(\n).
string replacementText = textToFind.Text.Replace(".", ".\n");
textToFind.Text = replacementText;
}
document.Save(filename);
MessageBox.Show("Created");
}
private void SpeechRecognizer_SessionStarted(object? sender, SessionEventArgs e) {
Tiles![0].IsTileActive = false;
Debug.WriteLine("Started");
}
private void SpeechRecognizer_Recognized(object? sender, SpeechRecognitionEventArgs e) {
if (e.Result.Reason == ResultReason.RecognizedSpeech) {
foreach (var item in e.Result.Text) {
Words.Add(item);
}
}
}
private void SpeechRecognizer_Recognizing(object? sender, SpeechRecognitionEventArgs e) {
When I start the transcription process, my Tile is supposed to be disabled and when I finished enable it, that is why I have `Tle[0]IsTileActive = false when I start working o the transcription process
I have a problem. I am using a CollectionView that receives data in a custom ViewModel from my webpage as long as it returns a JSON with the data. Once the Offset in the call >= num_of_rows the webpage prints "Nothing". If that happens I set a boolean HitBottomOfList = true;. Now everytime when it wants to do a webcall it checks if the HitBottomOfList == false.
Full Code
ViewModel:
public class TemplateListViewModel
{
public double WidthHeight { get; set; }
public ICommand LoadTemplates => new Command(LoadTemplateList);
public int CurrentTemplateCountReceived;
public bool HitBottomOfList = false;
public ObservableCollection<TemplateSource> sourceList { get; set; }
public TemplateListViewModel()
{
CurrentTemplateCountReceived = 0;
sourceList = new ObservableCollection<TemplateSource>();
var mainDisplayInfo = DeviceDisplay.MainDisplayInfo;
var width = mainDisplayInfo.Width;
var density = mainDisplayInfo.Density;
var ScaledWidth = width / density;
WidthHeight = (ScaledWidth / 2);
loadingTemplates += onLoadingTemplates;
LoadTemplateList();
}
private event EventHandler loadingTemplates = delegate { };
private void LoadTemplateList()
{
loadingTemplates(this, EventArgs.Empty);
}
private async void onLoadingTemplates(object sender, EventArgs args)
{
if (HitBottomOfList == false)
{
List<Template> templateList = await App.RestService.GetTemplates(App.User, CurrentTemplateCountReceived);
if (templateList != null)
{
foreach (var template in templateList)
{
ImageSource source = ImageSource.FromUri(new Uri("mysite.org/myapp/" + template.FileName));
TemplateSource templateSource = new TemplateSource { Id = template.Id, Source = source, WidthHeight = WidthHeight, FileName = template.FileName };
sourceList.Add(templateSource);
}
CurrentTemplateCountReceived = sourceList.Count;
}
else
{
HitBottomOfList = true;
}
}
}
}
The XAML:
<CollectionView ItemsSource="{Binding sourceList}" RemainingItemsThreshold="6"
RemainingItemsThresholdReachedCommand="{Binding LoadTemplates}">
<CollectionView.ItemsLayout>
<GridItemsLayout Orientation="Vertical"
Span="2" />
</CollectionView.ItemsLayout>
<CollectionView.ItemTemplate>
<DataTemplate>
<ff:CachedImage
Source="{Binding Source}"
VerticalOptions="Center"
HorizontalOptions="Center"
WidthRequest="{Binding WidthHeight}"
HeightRequest="{Binding WidthHeight}">
<ff:CachedImage.GestureRecognizers>
<TapGestureRecognizer Tapped="imgTemplate_Clicked" />
</ff:CachedImage.GestureRecognizers>
</ff:CachedImage>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
And finally the WebCall that I do:
public async Task<List<Template>> GetTemplates(User user, int offset)
{
var postData = new List<KeyValuePair<string, string>>();
postData.Add(new KeyValuePair<string, string>("un", user.Username));
postData.Add(new KeyValuePair<string, string>("pw", user.Password));
postData.Add(new KeyValuePair<string, string>("offset", offset.ToString()));
var content = new FormUrlEncodedContent(postData);
var weburl = "mysite.org/myapp/get_templates.php";
List<Template> response = await PostResponseTemplates(weburl, content);
return response;
}
public async Task<List<Template>> PostResponseTemplates(string weburl, FormUrlEncodedContent content)
{
var response = await client.PostAsync(weburl, content);
var json = await response.Content.ReadAsStringAsync();
if (json != "Nothing")
{
var jObject = JObject.Parse(json);
var templatePropery = jObject["Templates"] as JArray;
List<Template> templateList = new List<Template>();
foreach (var property in templatePropery)
{
List<Template> propertyList = new List<Template>();
propertyList = JsonConvert.DeserializeObject<List<Template>>(property.ToString());
templateList.AddRange(propertyList);
}
var sourcePropery = (JObject)jObject["Source"];
foreach (var property in sourcePropery)
{
string tempplateSource = property.Value.Value<string>();
App.TemplateSource = tempplateSource;
}
return templateList;
}
else
{
ErrorMessage = json;
return default(List<Template>);
}
}
Now the problem is that when it does trigger the RemainingItemsThresholdReachedCommand="{Binding LoadTemplates}"
it executes the command a lot of times after each other, thinking it needs more data, while there is already a command to get new data. This causes the app to get new data with the same offset a few times, so the app will the same data in the CollectionView a lot of times.
I want the app to call the webpage 1 time to receive more images and just let it load, without asking again for new data, so the duplicates in the list will disappear.
So how can I make sure it only asks the data once, when almost hit the bottom?
Update
Using #Jason his code the following is going wrong:
When the code goes through the MyHandler, it fires the LoadTemplateList(); But jumps to the handling = false; before it finished, so the next command is allowed to start, without finishing the other. Any idea how to wait for the method to finish?
use a bool to track if you are already handling the event and ignore any new ones
bool handling = false;
public void MyHandler()
{
// already handling an event, ignore the new one
if (handling) return;
handling = true;
// process event here
handling = false;
}
I got 2 problems in OnActivityResult method while trying to upload image accoding to this. How can I solve them?
The full code of the class is:
public class AddNewTourActivity : Activity
{
GettingCountry gettingCountry = new GettingCountry();
private static int idOfChosenCountry, IdOfChosenCategory;
private static string status, promptMessage;
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
SetContentView(Resource.Layout.AddNewTour);
//clearing lists
GettingCountry.listOfCountriesRoot.Clear();
GettingCountry.countriesList.Clear();
GettingCategories gc = new GettingCategories();
//Getting list of countries
gettingCountry.Fetch();
//clearing listCategoriesRoot
GettingCategories.categoriesList.Clear();
//getting categories method
gc.GetCategories();
Spinner categories_spinner = FindViewById<Spinner>(Resource.Id.categories_spinner);
Spinner countries = FindViewById<Spinner>(Resource.Id.countries);
//adapter
ArrayAdapter adapter = new ArrayAdapter<string>(this, Android.Resource.Layout.SimpleListItem1, GettingCategories.categoriesList);
ArrayAdapter adapterCountries = new ArrayAdapter<string>(this, Android.Resource.Layout.SimpleListItem1, GettingCountry.countriesList);
categories_spinner.Adapter = adapter;
countries.Adapter = adapterCountries;
countries.ItemSelected += Countries_ItemSelected;
categories_spinner.ItemSelected += Categories_spinner_ItemSelected;
//FindViewById<EditText>(Resource.Id.owner_id).Text = Login.user_id.ToString();
var title = FindViewById<EditText>(Resource.Id.title);
var image = FindViewById<ImageView>(Resource.Id.myImageView);
var location = FindViewById<EditText>(Resource.Id.location);
var description = FindViewById<EditText>(Resource.Id.description);
var price = FindViewById<EditText>(Resource.Id.price);
var min_capacity = FindViewById<EditText>(Resource.Id.min_capacity);
var max_capacity = FindViewById<EditText>(Resource.Id.max_capacity);
var duration = FindViewById<EditText>(Resource.Id.duration);
var meet_place_address = FindViewById<EditText>(Resource.Id.meet_place_address);
var meet_place_city = FindViewById<EditText>(Resource.Id.meet_place_city);
var lat = FindViewById<EditText>(Resource.Id.lat);
var lng = FindViewById<EditText>(Resource.Id.lng);
//uploading image
image.Click += Image_Click;
//uploading image ENDED
FindViewById<Button>(Resource.Id.add_tour_button).Click += delegate
{
//setting prompt message empty
promptMessage = "";
var client = new RestClient("http://api.locopal.com");
var request = new RestRequest("/experience", Method.POST);
//CHECKING THE CORRECTNESS OF THE USER'S INTRODUCTION TO ALL FIELDS
if (title.Text.Length < 3)
{
promptMessage += " Title must have at least 3 symbols.\n";
}
if (location.Text.Length < 3)
{
promptMessage += " Location must have at least 3 symbols.\n";
}
if (description.Text.Length < 30)
{
promptMessage += " Description length must be at least 30 symbols.\n";
}
//checking if price, capacity, etc... are integer values
int res;
bool priceIsInt = false;
priceIsInt = Int32.TryParse(price.Text, out res);
if (priceIsInt == false)
{
promptMessage += " Price must be an integer value.\n";
}
bool minCapacityIsInt = false;
minCapacityIsInt = Int32.TryParse(min_capacity.Text, out res);
if (minCapacityIsInt == false)
{
promptMessage += " Minimum capacity must be an integer value.\n";
}
bool maxCapacityIsInt = false;
maxCapacityIsInt = Int32.TryParse(max_capacity.Text, out res);
if (maxCapacityIsInt == false)
{
promptMessage += " Maximum capacity must be an integer value.\n";
}
bool durationIsInt = false;
durationIsInt = Int32.TryParse(duration.Text, out res);
if (durationIsInt == false)
{
promptMessage += " Duration must be an integer value.\n";
}
//checking if price, capacity, etc... are integer values ENDED
if (meet_place_address.Text.Length < 3)
{
promptMessage += " Address of meeting place must have at least 3 symbols.\n";
}
if (meet_place_city.Text.Length < 3)
{
promptMessage += " City of meeting place must have at least 3 symbols.\n";
}
//checking if lat and lng are doubles
double resDouble;
bool latIsDouble = false;
latIsDouble = Double.TryParse(lat.Text, out resDouble);
if (latIsDouble == false)
{
promptMessage += " Latitude must be a fractional value.\n";
}
bool lngIsDouble = false;
lngIsDouble = Double.TryParse(lng.Text, out resDouble);
if (lngIsDouble == false)
{
promptMessage += " Longitude must be a fractional value.";
}
//checking if lat and lng are doubles ENDED
//CHECKING THE CORRECTNESS OF THE USER'S INTRODUCTION TO ALL FIELDS ENDED
request.AddParameter("api_token", Login.token);
request.AddParameter("title", title.Text);
request.AddParameter("location", location.Text);
request.AddParameter("description", description.Text);
request.AddParameter("price", price.Text);
request.AddParameter("owner_id", Login.user_id);
request.AddParameter("min_capacity", min_capacity.Text);
request.AddParameter("max_capacity", max_capacity.Text);
request.AddParameter("duration", duration.Text);
request.AddParameter("duration_type", 1);
request.AddParameter("meet_place_address", meet_place_address.Text);
request.AddParameter("meet_place_city", meet_place_city.Text);
request.AddParameter("meet_place_country", idOfChosenCountry);
request.AddParameter("category_list[0]", IdOfChosenCategory);
request.AddParameter("lat", lat.Text);
request.AddParameter("lng", lng.Text);
try
{
IRestResponse response = client.Execute(request);
var content = response.Content;
var myContent = JObject.Parse(content);
status = myContent["status"].ToString();
}
catch { }
if (status == "success")
{
Toast.MakeText(this, "Tour added successfully", ToastLength.Short).Show();
//setting status variable to null to prevent issues with adding new places in future
status = null;
StartActivity(typeof(MainActivity));
}
else
{
Toast.MakeText(this, promptMessage, ToastLength.Long).Show();
}
};
}
private void Image_Click(object sender, EventArgs e)
{
var imageIntent = new Intent();
imageIntent.SetType("image/*");
imageIntent.SetAction(Intent.ActionGetContent);
StartActivityForResult(
Intent.CreateChooser(imageIntent, "Select photo"), 0);
}
private void Categories_spinner_ItemSelected(object sender, AdapterView.ItemSelectedEventArgs e)
{
IdOfChosenCategory = e.Position;
}
private void Countries_ItemSelected(object sender, AdapterView.ItemSelectedEventArgs e)
{
idOfChosenCountry = gettingCountry.retrievingChoosenCountryId(GettingCountry.countriesList[e.Position].ToString());
}
protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
{
base.OnActivityResult(requestCode, resultCode, data);
if (resultCode == Result.Ok)
{
var imageView = FindViewById<ImageView>(Resource.Id.myImageView);
imageView.SetImageURI(data.Data);
}
}
}
I changed the namespace from RecyclerViewSample to RecyclerViewSampl. I deleted only one letter. Then I added full path RecyclerViewSample.Resource.Id.min_capacity as an example to all elements of previous namespace.
For example:
SetContentView(RecyclerViewSample.Resource.Layout.AddNewTour);
In another classes I did analogical references to this new namespace.
Such as:
StartActivity(new Intent(this, typeof(RecyclerViewSampl.AddNewTourActivity)));
I have a picture slideshow that when the picture was tapped by the user and if the url in json no "#", it will go to the url address.
JSON:
XAML:
<Image x:Name="topBanner" Source="images/new (3.0)/banner/MI-W10-banner-1366-01.png" Tapped="topBanner_Tapped" />
Code:
DispatcherTimer playlistTimer1a = null;
List<string> Images1a = new List<string>();
protected override void OnNavigatedTo(NavigationEventArgs e)
{
ImageSource1a();
}
private async void ImageSource1a()
{
try
{
var httpClientHandler = new HttpClientHandler();
httpClientHandler.Credentials = new System.Net.NetworkCredential("username", "password");
var httpClient = new HttpClient(httpClientHandler);
string urlPath = "http://";
var values = new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>("platform","win"),
};
HttpResponseMessage response = await httpClient.PostAsync(urlPath, new FormUrlEncodedContent(values));
response.EnsureSuccessStatusCode();
string jsonText = await response.Content.ReadAsStringAsync();
JsonObject jsonObject = JsonObject.Parse(jsonText);
//JsonObject jsonData1 = jsonObject["data"].GetObject();
JsonArray jsonData1 = jsonObject["data"].GetArray();
foreach (JsonValue groupValue1 in jsonData1)
{
JsonObject groupObject1 = groupValue1.GetObject();
string image = groupObject1["image"].GetString();
string url = groupObject1["url"].GetString();
Images1a.Add(image);
}
playlistTimer1a = new DispatcherTimer();
playlistTimer1a.Interval = new TimeSpan(0, 0, 6);
playlistTimer1a.Tick += playlistTimer_Tick1a;
topBanner.Source = new BitmapImage(new Uri(Images1a[0]));
playlistTimer1a.Start();
}
}
catch (HttpRequestException ex)
{
RequestException();
}
}
int count1a = 0;
void playlistTimer_Tick1a(object sender, object e)
{
if (Images1a != null)
{
if (count1a < Images1a.Count)
count1a++;
if (count1a >= Images1a.Count)
count1a = 0;
ImageRotation1a();
}
}
private async void ImageRotation1a()
{
OpacityTrans1.Begin();
}
private void topBanner_Tapped(object sender, TappedRoutedEventArgs e)
{
//I have to confused to add this code
//Can anyone help me to add this code
}
How, when the slideshow image tapped by the user, it will go to url address on JSON (when the address url not '#')?
There are a lot of improvements to be made to the code. I recommend you read a bit more about DataBinding and MVVM.
However, I will try to help you with the code, as-is:
First, you need to ensure you maintain all the data from JSON so you can use it later. Instead of having a List for the image URLs you need to have a structure to hold both urls:
public struct DataItem
{
public string ImageUrl {get;set;}
public string Url {get;set;}
}
Then declare your list as:
List<DataItem> Images1a = new List<DataItem>();
When you build you list, create DataItem instances and add them to the list
foreach (JsonValue groupValue1 in jsonData1)
{
JsonObject groupObject1 = groupValue1.GetObject();
var dataItem = new DataItem();
dataItem.ImageUrl = groupObject1["image"].GetString();
dataItem.Url = groupObject1["url"].GetString();
Images1a.Add(dataItem);
}
Finally, when you tap an image, find the url based on the index:
private async void topBanner_Tapped(object sender, TappedRoutedEventArgs e)
{
var tappedItem = Images1a[count1a];
if (tappedItem.Url != "#")
{
await Windows.System.Launcher.LaunchUriAsync(new Uri(tappedItem.Url));
}
}
You can read more about how to launch URIs from the documentation
I am working on Windows Phone 8 project. In my project there are 10 Events with 10 EventHandlers ReverseGeocodeQuery_QueryCompleted (1 to 10). When first EventHandler is completed it turn on second event.
What should I implement to manage those Events without so much code.
code
myReverseGeocodeQuery = new ReverseGeocodeQuery();
myReverseGeocodeQuery.GeoCoordinate = mySimulationCoordinates.ElementAt(0);
myReverseGeocodeQuery.QueryCompleted += ReverseGeocodeQuery_QueryCompleted_1;
myReverseGeocodeQuery.QueryAsync();
private void ReverseGeocodeQuery_QueryCompleted_1(object sender, QueryCompletedEventArgs<IList<MapLocation>> e)
{
if (e.Error == null)
{
if (e.Result.Count > 0)
{
MapAddress address = e.Result[0].Information.Address;
label8txt.Text = address.City.ToString() + "\n" + address.Street.ToString();
StringBuilder str = new StringBuilder();
str.AppendLine("Pierwszy");
str.AppendLine("11" + address.HouseNumber);
str.AppendLine("17" + address.Street);
MessageBox.Show(str.ToString());
}
myReverseGeocodeQuery = new ReverseGeocodeQuery();
myReverseGeocodeQuery.GeoCoordinate = mySimulationCoordinates.ElementAt(1);
myReverseGeocodeQuery.QueryCompleted += ReverseGeocodeQuery_QueryCompleted_2;
myReverseGeocodeQuery.QueryAsync();
}
}
private void ReverseGeocodeQuery_QueryCompleted_2(object sender, QueryCompletedEventArgs<IList<MapLocation>> e)
{
if (e.Error == null)
{
if (e.Result.Count > 0)
{
MapAddress address = e.Result[0].Information.Address;
label8txt.Text = address.City.ToString() + "\n" + address.Street.ToString();
StringBuilder str = new StringBuilder();
str.AppendLine("Drugi");
str.AppendLine("11" + address.HouseNumber);
str.AppendLine("17" + address.Street);
MessageBox.Show(str.ToString());
myReverseGeocodeQuery = new ReverseGeocodeQuery();
myReverseGeocodeQuery.GeoCoordinate = mySimulationCoordinates.ElementAt(2);
myReverseGeocodeQuery.QueryCompleted += ReverseGeocodeQuery_QueryCompleted_3;
myReverseGeocodeQuery.QueryAsync();
}
}
}
Example Solution 1
public class DataContainer
{
public string Description { get; set; }
public GeoCoordinate Coordinate { get; set; }
//public List<GeoCoordinate> mySimulationCoordinates { get; set; }
public String EnterSimulation() {
StringBuilder strRet = new StringBuilder();
List<GeoCoordinate> mySimulationCoordinates = new List<GeoCoordinate>();
mySimulationCoordinates.Add(new GeoCoordinate(51.760752, 19.458216));
mySimulationCoordinates.Add(new GeoCoordinate(51.760757, 19.458356));
mySimulationCoordinates.Add(new GeoCoordinate(51.760738, 19.458442));
mySimulationCoordinates.Add(new GeoCoordinate(51.7607, 19.458501));
mySimulationCoordinates.Add(new GeoCoordinate(51.760662, 19.458533));
var descriptions = new[] { "Pierwszy", "Drugi", "Trzeci", "Czwarty", "PiÄ…ty" }; //etc
var zipped = mySimulationCoordinates.Zip(descriptions, (coord, desc) => new DataContainer { Description = desc, Coordinate = coord });
int k = zipped.Count();
foreach (var item in zipped)
{
var currentItem = item;
using (var waitHandle = new AutoResetEvent(false))
{
var geocodeQuery = new ReverseGeocodeQuery();
geocodeQuery.GeoCoordinate = item.Coordinate;
geocodeQuery.QueryCompleted += (sender, args) =>
{
if (args.Error == null)
{
if (args.Result.Count > 0)
{
MapAddress address = args.Result[0].Information.Address;
//label8txt.Text = address.City.ToString() + "\n" + address.Street.ToString();
StringBuilder str = new StringBuilder();
str.AppendLine(currentItem.Description);
str.AppendLine("House Number" + address.HouseNumber);
str.AppendLine("Street " + address.Street);
strRet.AppendLine("->");
strRet.Append(str);
waitHandle.Set();
}
}
};
geocodeQuery.QueryAsync();
waitHandle.WaitOne();
}
}
return strRet.ToString();
}
It stuck on 1st item. Is inside and wait ... wait ... can't pass to next element.
Umm... Let's see, shouldn't that be easier?
Warning: untested
public class DataContainer
{
public string Description {get;set;}
public GeoCoordinate Coordinate {get;set;}
}
var descriptions = new[] {"Pierwszy" , "Drugi" , "Trzeci" }; //etc
var zipped = mySimulationCoordinates.Zip(descriptions, (coord, desc) => new DataContainer { Description = desc, Coordinate = coord });
foreach(var item in zipped)
{
var currentItem = item;
using(var waitHandle = new AutoResetEvent(false))
{
var geocodeQuery = new ReverseGeocodeQuery();
geocodeQuery.GeoCoordinate = currentItem.Coordinates;
geocodeQuery.QueryCompleted += (sender, args) => {
if (e.Error == null)
{
if (e.Result.Count > 0)
{
MapAddress address = args.Result[0].Information.Address;
label8txt.Text = address.City.ToString() + "\n" + address.Street.ToString();
StringBuilder str = new StringBuilder();
str.AppendLine(currentItem.Description);
str.AppendLine("11" + address.HouseNumber);
str.AppendLine("17" + address.Street);
MessageBox.Show(str.ToString());
waitHandle.Set();
}
}
};
geoCodeQuery.QueryAsync();
waitHandle.WaitOne();
}
}
That should guarantee you that one event is handled after another in order.