Loading Image while service gets data using Xamarin Forms - xamarin

In my application in login page i want loading image with message "Loading" in xamarin forms before the service gets data.
For that i used Activity indicator like this:
ActivityIndicator indicator = new ActivityIndicator { Color = Color.Blue, };
indicator.IsRunning = false;
indicator.IsVisible = false;
indicator.HorizontalOptions = LayoutOptions.CenterAndExpand;
indicator.VerticalOptions = LayoutOptions.CenterAndExpand;
and after click on Login button,I added code like this
indicator.IsRunning = true;
indicator.IsVisible = true;
now i am getting loading image only and in the same screen.But i want like the above image.can anyone suggest me to solve this.
Thanks in advance

You can use following library for the Dialogs
It supports Xamarin.Forms aswell
https://www.nuget.org/packages/Acr.UserDialogs/
EDIT 1
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Collections.ObjectModel;
**using Acr.UserDialogs;**
using Xamarin.Forms;
using Splat;
namespace ProjectScreen
{
public partial class MainPage : ContentPage
{
public ObservableCollection<MainPageViewModel> projects { get; set; }
public SQLite.Net.SQLiteConnection _connection;
public bool IsLoading;
public MainPage()
{
projects = new ObservableCollection<MainPageViewModel>();
InitializeComponent();
this.getConnection();
foreach (Project Pname in this.GetProjects())
{
projects.Add(new MainPageViewModel { Name = Pname.name });
lstView.ItemsSource = projects;
}
AddNewItem.Clicked += (o, s) =>
{
this.PromptCommand();
};
lstView.ItemSelected += LstView_ItemSelected;
}
private void LstView_ItemSelected(object sender, SelectedItemChangedEventArgs e)
{
**UserDialogs.Instance.ShowLoading("Loading data");**
Task.Run(() => { waitForMinute(); });
}
private async void waitForMinute()
{
await Task.Delay(10000);
**UserDialogs.Instance.Loading().Hide();**
Device.BeginInvokeOnMainThread(() =>
{
Navigation.PushAsync(new NavigationPage(new ProjectDetails()));
});
}
}
}
}
Lines indicated with ** are for AcrDialog You can use them in any file as per your requirement
make Sure you run them on main thread

Related

Change JSON serialization from camelCase to PascalCase [Duplicate-No solution?]

I know this is duplicate of some past questions.But there were no real solution.
One of the related links
Another one
I am working with .Net Core 3 Multipage Template.
I've tried everything like given below. But no use.
This is my interface from application project:
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Abp.Application.Services;
using Abp.Application.Services.Dto;
using TSE.Kalibrasyon.Roles.Dto;
using TSE.Kalibrasyon.Users.Dto;
namespace TSE.Kalibrasyon.Labs
{
public interface ILabAppService : IApplicationService
{
string Test();
Task<List<Entities.Labs.Labs>> GetAllAsync();
System.Threading.Tasks.Task Update(Entities.Labs.Labs input);
System.Threading.Tasks.Task Create(Entities.Labs.Labs input);
}
}
and the implementation is:
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Abp.Application.Services;
using Abp.Application.Services.Dto;
using Abp.Authorization;
using Abp.Domain.Entities;
using Abp.Domain.Repositories;
using Abp.Extensions;
using Abp.IdentityFramework;
using Abp.Linq.Extensions;
using Abp.Localization;
using Abp.Runtime.Session;
using Abp.UI;
using TSE.Kalibrasyon.Authorization;
using TSE.Kalibrasyon.Authorization.Accounts;
using TSE.Kalibrasyon.Authorization.Roles;
using TSE.Kalibrasyon.Authorization.Users;
using TSE.Kalibrasyon.Roles.Dto;
using TSE.Kalibrasyon.Users.Dto;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using TSE.Kalibrasyon.Entities.Labs.Dto;
using TSE.Kalibrasyon.Entities.Labs;
using TSE.Kalibrasyon.Labs.Dto;
using Abp.Web.Models;
using Newtonsoft.Json;
using Microsoft.AspNetCore.Mvc;
namespace TSE.Kalibrasyon.Labs
{
//[AbpAuthorize(PermissionNames.Pages_Users)]
public class LabAppService : KalibrasyonAppServiceBase, ILabAppService
{
private readonly IRepository<Entities.Labs.Labs> _labRepository;
public LabAppService(IRepository<Entities.Labs.Labs> labRepository)
{
_labRepository = labRepository;
}
[Microsoft.AspNetCore.Mvc.HttpGet]
public string Test()
{
return "merhaba";
}
[DontWrapResult]
public async Task<List<Entities.Labs.Labs>> GetAllAsync()
{
//var chk = await _labRepository.GetAllListAsync();
return await _labRepository.GetAllListAsync();
}
[DontWrapResult]
//public List<Entities.Labs.Labs> GetAll2()
public object GetAll2()
{
List<Entities.Labs.Labs> chk = _labRepository.GetAllListAsync().Result;
//return _labRepository.GetAllListAsync().Result;
var bak= new { Items = chk, Count = chk.Count() };
return new { Items = chk, Count = chk.Count() };
//return Json(new { Items = chk, Count = chk.Count() }, new JsonSerializerSettings { ContractResolver = new PascalCasePropertyNamesContractResolver() });
}
[DontWrapResult]
public string GetAll3()
{
List<Entities.Labs.Labs> chk = _labRepository.GetAllListAsync().Result;
var obj= new { Items = chk, Count = chk.Count() };
//return Json(new { Items = chk, Count = chk.Count() }, new JsonSerializerSettings { ContractResolver = new PascalCasePropertyNamesContractResolver() });
var settings = new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.All };
//var text = JsonConvert.SerializeObject(configuration, settings);
var text = JsonConvert.SerializeObject(obj);
return text;
//return Json(new { Items = chk, Count = chk.Count() });
}
public async Task Update(Entities.Labs.Labs input)
{
await _labRepository.UpdateAsync(input);
}
public async Task Create(Entities.Labs.Labs input)
{
await _labRepository.InsertAsync(input);
}
}
//public class Data
//{
// public bool requiresCounts { get; set; }
// public int skip { get; set; }
// public int take { get; set; }
//}
}
and the response body is:
[
{
"labName": "BASINÇ KALİBRASYON LABORATUVARI",
"labKod": "BAS",
"bolgeKodu": 5,
"id": 1
}
]
My model for this entity is :
using Abp.Domain.Entities;
using Abp.Domain.Repositories;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.Text;
namespace TSE.Kalibrasyon.Entities.Labs
{
[Table("Labs")]
public partial class Labs : Entity
{
private readonly IRepository<Labs> _lablarRepository;
//private readonly TownAppService _townAppService;
//private readonly IRepository<Town> _townRepository;
public Labs()
{
//this.Towns = new List<Town>();
//this.Districts = new List<District>();
//this.Neighborhoods = new List<Neighborhood>();
OnCreated();
}
//[System.ComponentModel.DataAnnotations.Key]
//[System.ComponentModel.DataAnnotations.Required()]
//public virtual int Id
//{
// get;
// set;
//}
[System.ComponentModel.DataAnnotations.Required()]
public virtual string LabName
{
get;
set;
}
[System.ComponentModel.DataAnnotations.StringLength(3)]
[System.ComponentModel.DataAnnotations.Required()]
public virtual string LabKod
{
get;
set;
}
[System.ComponentModel.DataAnnotations.Required()]
public virtual int BolgeKodu
{
get;
set;
}
#region Extensibility Method Definitions
partial void OnCreated();
#endregion
}
}
And there is an another big problem also, I am using Syncfusion .Net Core Grid as a third party tool. It requires a method for database operations as given below.
[IgnoreAntiforgeryToken]
public IActionResult UrlDatasource([FromBody]DataManagerRequest dm)
{
Api api=new Api();
//IEnumerable DataSource = Orders.GetAllRecords();
IEnumerable DataSource = api.LabsGetAll();
DataOperations operation = new DataOperations();
if (dm.Search != null && dm.Search.Count > 0)
{
DataSource = operation.PerformSearching(DataSource, dm.Search); //Search
}
if (dm.Sorted != null && dm.Sorted.Count > 0) //Sorting
{
DataSource = operation.PerformSorting(DataSource, dm.Sorted);
}
if (dm.Where != null && dm.Where.Count > 0) //Filtering
{
DataSource = operation.PerformFiltering(DataSource, dm.Where, dm.Where[0].Operator);
}
int count = DataSource.Cast<Entities.Labs.Labs>().Count();
if (dm.Skip != 0)
{
DataSource = operation.PerformSkip(DataSource, dm.Skip); //Paging
}
if (dm.Take != 0)
{
DataSource = operation.PerformTake(DataSource, dm.Take);
}
return dm.RequiresCounts ? Json(new { result = DataSource, count = count }) : Json(DataSource);
}
When I don't use the [IgnoreAntiforgeryToken] for the method. It doesn't hit the method with the HTTP ERROR 415.
Syncfusion says that, it is just because of camel casing and offers adding the
services.PostConfigure<MvcJsonOptions>(options =>
{
options.SerializerSettings.ContractResolver = new DefaultContractResolver();
});
into ConfigureServices method of StartUp file. But I think it works only with the .net core 2.x. It was not a solution for me with ABP working on .net core 3.0
My StartUp.cs in Host App is:
using System;
using System.Linq;
using System.Reflection;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Castle.Facilities.Logging;
using Abp.AspNetCore;
using Abp.AspNetCore.Mvc.Antiforgery;
using Abp.Castle.Logging.Log4Net;
using Abp.Extensions;
using TSE.Kalibrasyon.Configuration;
using TSE.Kalibrasyon.Identity;
using Abp.AspNetCore.SignalR.Hubs;
using Abp.Dependency;
using Abp.Json;
using Microsoft.OpenApi.Models;
using Newtonsoft.Json.Serialization;
using Microsoft.AspNetCore.Mvc;
namespace TSE.Kalibrasyon.Web.Host.Startup
{
public class Startup
{
private const string _defaultCorsPolicyName = "localhost";
private readonly IConfigurationRoot _appConfiguration;
public Startup(IWebHostEnvironment env)
{
_appConfiguration = env.GetAppConfiguration();
}
public IServiceProvider ConfigureServices(IServiceCollection services)
{
//MVC
services.AddControllersWithViews(
options =>
{
options.Filters.Add(new AbpAutoValidateAntiforgeryTokenAttribute());
}
).AddNewtonsoftJson(options =>
{
//options.SerializerSettings.ContractResolver = new AbpMvcContractResolver(IocManager.Instance)
//{
// NamingStrategy = new CamelCaseNamingStrategy()
//};
options.SerializerSettings.ContractResolver = new DefaultContractResolver();
});
services.PostConfigure<MvcNewtonsoftJsonOptions>(options =>
{
options.SerializerSettings.ContractResolver = new DefaultContractResolver();
});
IdentityRegistrar.Register(services);
AuthConfigurer.Configure(services, _appConfiguration);
services.AddSignalR();
// Configure CORS for angular2 UI
services.AddCors(
options => options.AddPolicy(
_defaultCorsPolicyName,
builder => builder
.WithOrigins(
// App:CorsOrigins in appsettings.json can contain more than one address separated by comma.
_appConfiguration["App:CorsOrigins"]
.Split(",", StringSplitOptions.RemoveEmptyEntries)
.Select(o => o.RemovePostFix("/"))
.ToArray()
)
.AllowAnyHeader()
.AllowAnyMethod()
.AllowCredentials()
)
);
// Swagger - Enable this line and the related lines in Configure method to enable swagger UI
services.AddSwaggerGen(options =>
{
options.SwaggerDoc("v1", new OpenApiInfo() { Title = "Kalibrasyon API", Version = "v1" });
options.DocInclusionPredicate((docName, description) => true);
// Define the BearerAuth scheme that's in use
options.AddSecurityDefinition("bearerAuth", new OpenApiSecurityScheme()
{
Description = "JWT Authorization header using the Bearer scheme. Example: \"Authorization: Bearer {token}\"",
Name = "Authorization",
In = ParameterLocation.Header,
Type = SecuritySchemeType.ApiKey
});
});
// Configure Abp and Dependency Injection
return services.AddAbp<KalibrasyonWebHostModule>(
// Configure Log4Net logging
options => options.IocManager.IocContainer.AddFacility<LoggingFacility>(
f => f.UseAbpLog4Net().WithConfig("log4net.config")
)
);
}
public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory)
{
app.UseAbp(options => { options.UseAbpRequestLocalization = false; }); // Initializes ABP framework.
app.UseCors(_defaultCorsPolicyName); // Enable CORS!
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAbpRequestLocalization();
app.UseEndpoints(endpoints =>
{
endpoints.MapHub<AbpCommonHub>("/signalr");
endpoints.MapControllerRoute("default", "{controller=Home}/{action=Index}/{id?}");
endpoints.MapControllerRoute("defaultWithArea", "{area}/{controller=Home}/{action=Index}/{id?}");
});
// Enable middleware to serve generated Swagger as a JSON endpoint
app.UseSwagger();
// Enable middleware to serve swagger-ui assets (HTML, JS, CSS etc.)
app.UseSwaggerUI(options =>
{
options.SwaggerEndpoint(_appConfiguration["App:ServerRootAddress"].EnsureEndsWith('/') + "swagger/v1/swagger.json", "Kalibrasyon API V1");
options.IndexStream = () => Assembly.GetExecutingAssembly()
.GetManifestResourceStream("TSE.Kalibrasyon.Web.Host.wwwroot.swagger.ui.index.html");
}); // URL: /swagger
}
}
}
Is there any solution that you might know? Thanks in advance.
and also, Controlling serialization of property names with JsonResult. But no use.Any idea please?
In .NET Core 3.x, you now need to modify JsonSerializerOptions.PropertyNamingPolicy.
For PascalCase — following your original property name — set to null:
services.AddMvc(...)
.AddJsonOptions(jsonOptions =>
{
jsonOptions.JsonSerializerOptions.PropertyNamingPolicy = null;
});
For lowercase (or another custom naming policy), subclass JsonNamingPolicy and override the ConvertName method.
services.AddMvc(...)
.AddJsonOptions(jsonOptions =>
{
jsonOptions.JsonSerializerOptions.PropertyNamingPolicy = new JsonLowercaseNamingPolicy();
});
public class JsonLowercaseNamingPolicy : JsonNamingPolicy
{
public override string ConvertName(string name) => name.ToLowerInvariant();
}
Reference: https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json-how-to?view=netcore-3.1#use-a-custom-json-property-naming-policy
In .NET 6.0, I managed to fix the same issue, just add this code inside Program.cs (ofc, with Newtonsoft package previously installed.):
builder.Services.AddControllers().AddJsonOptions(options =>
options.JsonSerializerOptions.PropertyNamingPolicy = null);
For newtonsoft this is the implementation.
.AddControllersWithViews()
.AddNewtonsoftJson(options =>
{
options.SerializerSettings.ContractResolver = null;
}
);
Hope it helps.

Initialize an xamarin view after an async method

Good evening everyone.
For some time now I have been to Xamarin. My first tests are rather conclusive. I decided to try to make a small application that retrieves information in a database via an API and then update this data via a ListView.
When I launch the application on my emulator everything works but as soon as I install the application on my phone it crashes. I thought this was because the API but I have an API that I use to check the Login / password that works correctly.
The API that returns the data reviews a lot of line about 3500/4000, can this be the reason?
So I passed the loading of the data in my viewModel in an async method but the problem now is that the view loads before the data is loaded correctly. Is there a way to get the view initialized after the data is loaded?
Below my code.
Initializing my viewModel
class ManageInventViewModel
{
public ObservableCollection<InventViewModel> InventProduct { get; set; }
public Command<InventViewModel> UpdateCommand
{
get
{
return new Command<InventViewModel>(invent =>
{
var index = invent.IndexLigneInventaire;
InventProduct.Remove(invent);
InventProduct.Insert(index, invent);
});
}
}
public Command<InventViewModel> ResetStock
{
get
{
return new Command<InventViewModel>(invent =>
{
var index = InventProduct.IndexOf(invent);
InventProduct.Remove(invent);
invent.RealStockProduct = 0;
InventProduct.Insert(index, invent);
});
}
}
public ManageInventViewModel()
{
LoadInventaire();
}
private async void LoadInventaire()
{
var listMvt = await Utils.Utils.GetListMouvementUntilDate();
var listStock = Utils.Utils.GetStockByProduct(listMvt).Take(20);
InventProduct = new ObservableCollection<InventViewModel>();
var indexLine = 0;
foreach (var stock in listStock)
{
var inventViewModel = new InventViewModel
{
LibelleProduit = stock.LibelleProduit,
PrCodeProduit = stock.PrCodeProduit,
UpCodeProduit = stock.UpCodeProduit,
RealStockProduct = stock.StockTheoProdct,
StockTheoProdct = stock.StockTheoProdct,
IndexLigneInventaire = indexLine
};
++indexLine;
InventProduct.Add(inventViewModel);
}
}
}
Initializinz my view
public partial class InventPage : ContentPage
{
public InventPage()
{
InitializeComponent();
TableInvent.ItemSelected += (sender, e) =>
{
if (TableInvent.SelectedItem != null)
{
if (TableInvent.SelectedItem is InventViewModel item)
{
PopupNavigation.Instance.PushAsync(new ChangeStockModal(item, this));
}
TableInvent.SelectedItem = null;
}
};
}
private void Reset_Stock(object sender, EventArgs e)
{
var input = sender as Button;
var inventViewModel = input?.BindingContext as InventViewModel;
var listViewModel = BindingContext as ManageInventViewModel;
listViewModel?.ResetStock.Execute(inventViewModel);
}
public void Update_Stock_List(InventViewModel dataStockUpdate)
{
var listViewModel = BindingContext as ManageInventViewModel;
listViewModel?.UpdateCommand.Execute(dataStockUpdate);
PopupNavigation.Instance.PopAsync();
}
}
Thanks
I managed to create the ActivityIndicator but I can not get my data loaded while I'm displaying the wait screen.
Regarding this issue, I don't see you useActivityIndicator from your code,maybe you didn't update your code, I think if you use useActivityIndicator , You can bind one property to ActivityIndicator IsRunning and IsVisible, then you can solve your issue.
Related use ActivityIndicator step, you can take a look:
ActivityIndicator

How to Set auto sliders in pageviewers in xamarin.android

I am trying to put auto sliders in my code for page viewers in xamarin.android and tried may ways to do that but it is not working correctly can you please help me to set up the auto slider to the page viewer i am posting my last tried code which is auto sliding one page and jumping off right away to last page.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Android.Support.V4.View;
using Android.Support.V4.App;
using MyApplication.Droid.Library;
using System.Timers;
namespace MyApplication.Droid.Circles
{
[Activity(Label = "SampleCirclesSnap")]
public class SampleCirclesSnap : FragmentActivity
{
public TestFragmentAdapter mAdapter;
public ViewPager mPager;
public PageIndicator mIndicator;
public Timer time;
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
SetContentView(Resource.Layout.simple_circles);
mAdapter = new TestFragmentAdapter(SupportFragmentManager);
mPager = FindViewById<ViewPager>(Resource.Id.pager);
mPager.Adapter = mAdapter;
var indicator = FindViewById<CirclePageIndicator>(Resource.Id.indicator);
mIndicator = indicator;
indicator.SetViewPager(mPager);
indicator.SetSnap(true);
time = new System.Timers.Timer();
time.Elapsed += (sender, args) => viewPager.SetCurrentItem(CurrentItem++, true);
time.Interval = 1000;
time.Enabled = true;
}
}
}
My fragments related code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Android.Support.V4.App;
using Fragment = Android.Support.V4.App.Fragment;
using FragmentManager = Android.Support.V4.App.FragmentManager;
namespace MyApplication.Droid
{
public class TestFragmentAdapter : FragmentPagerAdapter
{
// public static string[] CONTENT = new string[] { "This", "Is", "A", "Test", };
public static int[] CONTENT = new int[] { Resource.Drawable.Visa, Resource.Drawable.home_s, Resource.Drawable.Set_s, Resource.Drawable.Icon, Resource.Drawable.home_s };
int mCount;
public TestFragmentAdapter(FragmentManager fm) : base(fm)
{
mCount = CONTENT.Count();
}
public override Fragment GetItem(int position)
{
return new TestFragment(CONTENT[position % CONTENT.Count()]);
}
public override int Count
{
get
{
return mCount;
}
}
public void SetCount(int count)
{
Console.WriteLine("Setting count to " + count);
if (count > 0 && count <= 10)
{
mCount = count;
NotifyDataSetChanged();
}
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Fragment = Android.Support.V4.App.Fragment;
namespace MyApplication.Droid
{
class TestFragment : Fragment
{
private const string KEY_CONTENT = "TestFragment:Content";
string mContent = "???";
private int v;
public TestFragment()
{
}
public TestFragment(int v)
{
this.v = v;
}
//public TestFragment(string content)
//{
// var builder = new StringBuilder();
// for (int i = 0; i < 20; i++)
// {
// if (i != 19)
// builder.Append(content).Append(" ");
// else
// builder.Append(content);
// }
// mContent = builder.ToString();
//}
public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
//if ((savedInstanceState != null) && savedInstanceState.ContainsKey(KEY_CONTENT))
//{
// mContent = savedInstanceState.GetString(KEY_CONTENT);
//}
ImageView image = new ImageView(Activity);
image.SetImageResource(v);
//TextView text = new TextView(Activity);
//text.Gravity = GravityFlags.Center;
//text.Text = mContent;
//text.TextSize = (20 * Resources.DisplayMetrics.Density);
//text.SetPadding(20, 20, 20, 20);
LinearLayout layout = new LinearLayout(Activity);
layout.LayoutParameters = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FillParent, ViewGroup.LayoutParams.FillParent);
layout.SetGravity(GravityFlags.Center);
layout.AddView(image);
return layout;
}
public override void OnSaveInstanceState(Bundle outState)
{
base.OnSaveInstanceState(outState);
outState.PutString(KEY_CONTENT, mContent);
}
}
}
anyone Please help me with the code to auto slide pageviewers on set time in xamarin android
I think you will need to invoke your method of changing current item to the RunOnUiThread method to ensure this it will be executed in UI thread, for example:
var timer = new System.Timers.Timer();
timer.Interval = 1000;
timer.Enabled = true;
int page = 0;
timer.Elapsed += (sender, args) =>
{
RunOnUiThread(() =>
{
if (page <= viewPager.Adapter.Count)
{
page++;
}
else
{
page = 0;
}
viewPager.SetCurrentItem(page, true);
Log.WriteLine(LogPriority.Debug, "CurrentItem:", viewPager.CurrentItem.ToString());
});
};
Tested on Android 6.0 emulator:

Xamarin Forms timepicker 24hour

I'm new to Xamarin.Forms and i can't seems to find how to show the dialog in a 24hour format instead of a AM/PM
can someone help me ?
Thank you
This page is really usefull to learn how to format dates in C#:
https://msdn.microsoft.com/en-us/library/8kb3ddd4%28v=vs.110%29.aspx
And with this code I was able to show a 24 hour format:
TimePicker timePicker = new TimePicker
{
Format = "HH:mm"
};
The only solution i found is here:
24h timepicker
Basically a custom renderer within each platform project will be needed.
Xamarin.iOS:
using MonoTouch.Foundation;
using MonoTouch.UIKit;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;
using PersonalTrainer.iOS.View.Controls;
[assembly: ExportRenderer (typeof (TimePicker), typeof (TimePicker24HRenderer))]
namespace YourNamespace.iOS.View.Controls {
public class TimePicker24HRenderer : TimePickerRenderer {
protected override void OnElementChanged(ElementChangedEventArgs<TimePicker> e) {
base.OnElementChanged(e);
var timePicker = (UIDatePicker)Control.InputView;
timePicker.Locale = new NSLocale("no_nb");
}
}
}
For Android:
[assembly: ExportRenderer(typeof(TimePicker), typeof(TimePicker24HRenderer))]
namespace YourNamespace.Droid.View.Controls {
public class TimePicker24HRenderer : ViewRenderer<Xamarin.Forms.TimePicker, Android.Widget.EditText>, TimePickerDialog.IOnTimeSetListener, IJavaObject, IDisposable {
private TimePickerDialog dialog = null;
protected override void OnElementChanged(ElementChangedEventArgs<TimePicker> e) {
base.OnElementChanged(e);
this.SetNativeControl(new Android.Widget.EditText(Forms.Context));
this.Control.Click += Control_Click;
this.Control.Text = DateTime.Now.ToString("HH:mm");
this.Control.KeyListener = null;
this.Control.FocusChange += Control_FocusChange;
}
void Control_FocusChange(object sender, Android.Views.View.FocusChangeEventArgs e) {
if (e.HasFocus) { ShowTimePicker(); }
}
void Control_Click(object sender, EventArgs e) {
ShowTimePicker();
}
private void ShowTimePicker() {
if (dialog == null) {
dialog = new TimePickerDialog(Forms.Context, this, DateTime.Now.Hour, DateTime.Now.Minute, true);
}
dialog.Show();
}
public void OnTimeSet(Android.Widget.TimePicker view, int hourOfDay, int minute) {
var time = new TimeSpan(hourOfDay, minute, 0);
this.Element.SetValue(TimePicker.TimeProperty, time);
this.Control.Text = time.ToString(#"hh\:mm");
}
}
}
For Windows Phone:
[assembly: ExportRenderer (typeof (MyTimePicker), typeof (TimePicker24HRenderer))]
namespace YourNamespace.WindowsPhone.View.Controls {
public class TimePicker24HRenderer : TimePickerRenderer {
// Override the OnElementChanged method so we can tweak this renderer post-initial setup
protected override void OnElementChanged (ElementChangedEventArgs<Xamarin.Forms.TimePicker> e) {
base.OnElementChanged (e);
if (Control != null) {
var nativeControl = (Windows.UI.Xaml.Controls.TimePicker)Control;
nativeControl.Foreground = new SolidColorBrush(Colors.Gray);
Control.ClockIdentifier = "24HourClock";
}
}
}
}
In XAML you can set the the 24 hours format string to TimePicker by using the Format property:
<TimePicker Format="HH:mm"/>
Ok. You have to do it plateform specific.. I did something like that.
So create an interface
public interface TimePickerInterface
{
void showTimePicker (ButtonOrLabel lbl);
}
In Android you create your timepicker class
[assembly:Dependency(typeof(yournamespace.MyTimePicker))]
namespace yournamespace
{
public class MyTimePicker:Java.Lang.Object,TimePickerInterface,Android.App.TimePickerDialog.IOnTimeSetListener
{
String originalText="";
LabelOrButton lbl=new LabelOrButton();
public void showTimePicker(LabelOrButton lbl)
{
var c = Forms.Context;
originalText = lbl.Text;
this.lbl = lbl;
var time = DateTime.Now.TimeOfDay;
TimePickerDialog dialog = new TimePickerDialog(c,this,time.Hours,time.Minutes,true);
dialog.SetCanceledOnTouchOutside (true);
dialog.Show ();
}
public void OnTimeSet (Android.Widget.TimePicker view, int hourOfDay, int minute)
{
if(view.IsShown)
lbl.Text = (hourOfDay<=9 ? ("0"+hourOfDay+""):hourOfDay+"")+":"+(minute<=9 ? ("0"+minute+""):minute+"");
}
}
}
And in your xamarin forms you call it in actionlistener of your button or gesturerecognizer of your label:
DependencyService.Get<TimePickerInterface> ().showTimePicker(myButtonOrLabel);
You can do the same thing for DatePicker..
Hope it helps..

Create a simple GUI from scratch

On a platform that has no real libraries available, and bare-minimum graphics other than a "display object of dimension(x,y,xx,yy) at coordinates (x,y), I'm trying to create a simple gui.
Can someone point me to a reference where I can understand the logistical principles involved in displaying a set of objects on the screen, and highlighting the selected object, allowing users to navigate between objects and move highlighting to each object. It seems like it should be simple to do, but I would like to understand how people think about this.
How would one create an object with a method like obj.highlight() where obj.highlight would turn off highlighting in all other objects? Would one simply do a for next loop through an array of objects, skipping the current object, turning off highlighting and then set the current object to true? Highlighting would be accomplished by drawing another object on top of the selected object with a transparent center.
This is a single threaded system, (but allows a small amount of async processing).
I'm looking more for conceptual ideas but code in VB that doesn't make use of proprietary graphics calls might be useful.
I've coded a small sample app that does its own control framework by painting over a form using .Net C#. Just something simple with this result:
I've done the IsSelected by recursively disabling all controls and toggling the clicked one.
See the part with window.MouseUp += (sender, arg) =>.
Selection can go through mouse or the Tab key.
The code approach should be portable to other languages, and online-translatable to VB.Net.
Relevant snippet of code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using System.Drawing;
using System.Threading;
using System.Threading.Tasks;
namespace CustomGUI
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Form window = new Form1();
window.BackColor = Color.Gray;
Graphics api = window.CreateGraphics();
GUIControl form = new GUIControl();
form.Location = new Point(30,30);
form.Size = new Size(200, 300);
GUIControl control1 = new GUIControl();
control1.Location = new Point(0, 0);
control1.Size = new Size(200, 130);
control1.Background = Color.Blue;
GUIControl control11 = new GUIControl();
control11.Location = new Point(140, 30);
control11.Size = new Size(30, 30);
control11.Background = Color.Red;
GUIControl control12 = new GUIControl();
control12.Location = new Point(30, 30);
control12.Size = new Size(30, 30);
control12.Background = Color.Red;
control12.BorderColor = Color.Green;
control12.BorderWidth = 5;
GuiLabel control2 = new GuiLabel();
control2.Location = new Point(10, 200);
control2.Size = new Size(180, 30);
control2.Background = Color.Green;
control2.Text = "Hello World!";
control1.AddChild(control11);
control1.AddChild(control12);
form.AddChild(control1);
form.AddChild(control2);
window.MouseUp += (sender, arg) =>
{
// hit test the control where the mouse has landed
IGUIContainer control = form.HitTest(arg.Location);
if (control != null)
{
// recursive on all controls
foreach (var ct in (new IGUIContainer[] { form }).Traverse(c => c.Controls))
{
//deselecting all others
if (ct != control) ct.IsSelected = false;
}
control.IsSelected = !control.IsSelected;
}
window.Invalidate(); // force paint
};
window.KeyUp += (sender, key) =>
{
if (key.KeyCode == Keys.Tab && key.Modifiers == Keys.None)
{
var selected = (new IGUIContainer[] { form }).Traverse(c => c.Controls).FirstOrDefault(c => c.IsSelected);
IGUIContainer parent;
if (selected == null)
{
parent = form;
}
else
{
parent = selected;
}
IGUIContainer control;
if (parent.Controls.Count > 0)
{
control = parent.Controls[0];
}
else
{
control = GUIControl.Next(parent);
}
if (control == null) control = form;
foreach (var ct in (new IGUIContainer[] { form }).Traverse(c => c.Controls))
{
if (ct != control) ct.IsSelected = false;
}
control.IsSelected = true;
window.Invalidate();
}
};
window.Paint += (sender, args) =>
{
form.Draw(api, new Point(0,0));
};
Application.Run(window);
}
}
}
All the needed classes and interfaces:
IDrawable:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
namespace CustomGUI
{
public interface IDrawable
{
Point Location { get; set; }
Size Size { get; set; }
Rectangle GetRealRect(Point origin);
void Draw(Graphics gfxApi, Point origin);
}
}
IGUIContainer:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
namespace CustomGUI
{
delegate void SelectionChangedHandler(object sender, bool newIsSelected);
interface IGUIContainer : IUIElement
{
IGUIContainer Parent { get; set; }
List<IGUIContainer> Controls { get; }
void AddChild(IGUIContainer child);
bool IsSelected { get; set; }
event SelectionChangedHandler SelectionChanged;
IGUIContainer HitTest(Point mouseCoord);
}
}
UIElement:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Diagnostics;
namespace CustomGUI
{
abstract class UIElement : IUIElement
{
private Point _location;
private Size _size;
private Color _background;
private Color _foreground;
private Color _borderColor;
private int _borderWidth;
public UIElement()
{
_foreground = Color.Black;
_background = Color.White;
_borderColor = Color.Transparent;
}
public Point Location
{
get
{
return _location;
}
set
{
_location = value;
}
}
public Size Size
{
get
{
return _size;
}
set
{
_size = value;
}
}
public virtual void Draw(Graphics drawingApi, Point origin)
{
Rectangle inside = GetRealRect(origin);
Pen borderPen = new Pen(new SolidBrush(_borderColor), _borderWidth);
drawingApi.FillRectangle(new SolidBrush(_background), inside);
drawingApi.DrawRectangle(borderPen, inside);
}
public Rectangle ClientRect
{
get
{
return new Rectangle(_location, _size);
}
}
public Color Background
{
get
{
return _background;
}
set
{
_background = value;
}
}
public Color Foreground
{
get
{
return _foreground;
}
set
{
_foreground = value;
}
}
public Rectangle GetRealRect(Point origin)
{
int left = ClientRect.Left + origin.X;
int top = ClientRect.Top + origin.Y;
int width = ClientRect.Width;
int height = ClientRect.Height;
Debug.WriteLine("GetRealRect " + left + ", " + top + ", " + width + ", " + height);
return new Rectangle(left, top, width, height);
}
public int BorderWidth
{
get
{
return _borderWidth;
}
set
{
_borderWidth = value;
}
}
public Color BorderColor
{
get
{
return _borderColor;
}
set
{
_borderColor = value;
}
}
}
}
GUIControl:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
namespace CustomGUI
{
class GUIControl : UIElement, IGUIContainer
{
private IGUIContainer _parent;
private List<IGUIContainer> _controls = new List<IGUIContainer>();
private bool _isSelected;
public List<IGUIContainer> Controls
{
get
{
return _controls;
}
}
public override void Draw(Graphics api, Point origin)
{
Point original = origin;
base.Draw(api, origin);
origin.Offset(this.Location);
foreach (var ctrl in Controls)
{
ctrl.Draw(api, origin);
}
if (IsSelected)
{
Pen selection = new Pen(Color.Yellow, 3);
selection.DashStyle = System.Drawing.Drawing2D.DashStyle.Dot;
api.DrawRectangle(selection, GetRealRect(original));
}
}
public IGUIContainer HitTest(Point coord)
{
Point newOrigin = coord;
newOrigin.Offset(-this.Location.X, -this.Location.Y);
foreach (var ctrl in Controls)
{
IGUIContainer hit = ctrl.HitTest(newOrigin);
if (hit != null)
{
return hit;
}
}
return ClientRect.Contains(coord) ? this : null;
}
public bool IsSelected
{
get
{
return _isSelected;
}
set
{
_isSelected = value;
if (SelectionChanged != null)
{
SelectionChanged(this, _isSelected);
}
}
}
public event SelectionChangedHandler SelectionChanged;
public void AddChild(IGUIContainer child)
{
// if you need to implement event propagation this is the place to attach them to children
child.Parent = this;
Controls.Add(child);
}
public IGUIContainer Parent
{
get
{
return _parent;
}
set
{
_parent = value;
}
}
public static IGUIContainer Next(IGUIContainer self)
{
if (self.Parent != null &&
self.Parent.Controls.Count - 1 > self.Parent.Controls.IndexOf(self))
{
return self.Parent.Controls[self.Parent.Controls.IndexOf(self) + 1];
}
else if (self.Parent != null)
{
return Next(self.Parent);
}
else
{
return null;
}
}
}
}
GUILabel:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
namespace CustomGUI
{
class GuiLabel : GUIControl
{
public string Text { get; set; }
public Font Font { get; set; }
public GuiLabel()
{
Font = new Font(new FontFamily("Tahoma"), 12, FontStyle.Regular);
}
public override void Draw(System.Drawing.Graphics api, System.Drawing.Point origin)
{
base.Draw(api, origin);
Rectangle controlRect = GetRealRect(origin);
SizeF size = api.MeasureString(Text, Font);
Point textPosition = new Point(controlRect.Location.X + (int)(controlRect.Width - size.Width) / 2,
controlRect.Location.Y + (int)(controlRect.Height - size.Height) / 2);
api.DrawString(Text, Font, new SolidBrush(Foreground), textPosition);
}
}
}
Extension (for Traverse method to flatten recursion):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace CustomGUI
{
static class Extensions
{
public static IEnumerable<T> Traverse<T>(this IEnumerable<T> source, Func<T, IEnumerable<T>> fnRecurse)
{
foreach (T item in source)
{
yield return item;
IEnumerable<T> seqRecurse = fnRecurse(item);
if (seqRecurse != null)
{
foreach (T itemRecurse in Traverse(seqRecurse, fnRecurse))
{
yield return itemRecurse;
}
}
}
}
}
}
Well that is one question that can be answered in a million ways... :)
But as long as you can draw pixels (or anything remotely like it), you can draw a GUI. If you have an object oriented language at hand, I would not choose to highlight and unhighlight the current object. I would give if focus and remove focus from it, and let the object itself decide whether it should be redrawn and how that should be done.
You can automatically unfocus the previous object if all object are placed in some sort of container. When you press a navigational key (like Tab) or press a mouse button, that container can process that message and focus the next object and unfocus the last object.
It requires some programming, but the concept is quite easy. It becomes harder when you want it to perform well, look slick, have all kinds of anumations and transitions... But as I said, the concept is simple and you won't even need OO to do it, although it will probably give you a much cleaner result. I think I can program an ASCII based GUI in DOS Batch on a rainy afternoon if I needed to.

Resources