Multiple destination from xamarin forms - c#

I have functional, which open google maps with route but with one point of destination. I want add several points of stop. How I can do it? See my code:
public Command OpenMap
{
get
{
return _openMap ?? (_openMap = new Command(async () =>
{
await Xamarin.Essentials.Map.OpenAsync(Position.Latitude, Position.Longitude, new MapLaunchOptions
{
Name = Address.Name,
NavigationMode = NavigationMode.Driving
});
}));
}
}
I use Xamarin.Essentials.Map maybe exists another way?
In the end, I want that after btn click have been open google maps with navigation route which consists of several destination.

Related

How to await multiple possibly uninitialized Tasks in C#?

I have an API POST endpoint creating a resource, that resource may have multiple relationships. To make sure the resource is created with valid relationships first I need to check if the given IDs exist. There are multiple such relations, and I don't want to await each sequentially. Here's my code:
[HttpPost]
public async Task<ActionResult<Person>> PostPerson(Person person)
{
ValueTask<Person> master, apprentice;
ValueTask<Planet> planet;
ValueTask<Models.LifeFormType> lifeFormType;
if (person.MasterId.HasValue)
{
master = _context.People.FindAsync(person.MasterId);
}
if (person.ApprenticeId.HasValue)
{
apprentice = _context.People.FindAsync(person.ApprenticeId);
}
if (person.FromPlanetId.HasValue)
{
planet = _context.Planets.FindAsync(person.FromPlanetId);
}
if (person.LFTypeId.HasValue)
{
lifeFormType = _context.LifeFormTypes.FindAsync(person.LFTypeId);
}
List<ValueTask> tasks = new List<ValueTask> {master, apprentice, planet, lifeFormType};
// if the above worked I'd process the tasks as they completed and throw errors
// if the given id was not found and such
_context.Attach(person);
// _context.People.Add(person);
await _context.SaveChangesAsync();
return CreatedAtAction("GetPerson", new { id = person.Id }, person);
}
As shown here I want to await the list of [master,apprentice,planet,lifeFormType] as they complete, but I get an error during the creation of the list that Local variable 'master' might not be initialized before accessing. So I tried in each check if the resource has that value to create an else block and somehow add a ValueTask.CompletedTask like so:
if (person.MasterId.HasValue)
{
master = _context.People.FindAsync(person.MasterId);
}
else
{
master = ValueTask.CompletedTask;
}
but then I get an error saying that Cannot convert source type 'System.Threading.Tasks.ValueTask' to target type 'System.Threading.Tasks.ValueTask<Models.Person>'.
How to do this? I guess I'll just await each and every request for now.
You can avoid this by initializing master at the declaration site.
The easiest way is using the default keyword.
ValueTask<Person> master = default;

How to request Contacts and Calendar Permissions on XamarinMac?

I'm trying to access the ContactStore of MacOS App, did the following implementation
public void Contacts()
{
//Starting
var store = new CNContactStore();
store.RequestAccess(CNEntityType.Contacts, async (bool granted, NSError error) =>
{
if (granted)
{
//Query things
}
});
}
The thing is that the Authorize screen never popup, and the Permission always say denied.
If I go to settings to remove that record, the app is not there.
Can someone please point me to the light?
It works for me with those two lines:
var contactStore = new CNContactStore();
var status = CNContactStore.GetAuthorizationStatus(CNEntityType.Contacts);
It could be also that you need to set NSContactsUsageDescription in info.plist.

UWP FolderPicker window opens but is frozen

The basic idea is I have a UWP app pulling user data from a json file saved locally, and at various times it may pull that full list of objects from the file, but it always checks that the user has set the location for the data, and if not, prompts via a FolderPicker for the user to set the location. In this case, I have combobox that helps filter the objects after selecting a criteria and entering text.
Here's the call stack:
UWPMiniatures.exe!UWPMiniatures.Data.MiniDAL.SetSaveFolder() Line 98 C# Symbols loaded.
UWPMiniatures.exe!UWPMiniatures.Data.MiniDAL.LoadAllAsync() Line 71 C# Symbols loaded.
UWPMiniatures.exe!UWPMiniatures.Data.MiniDataService.Load() Line 36 C# Symbols loaded.
UWPMiniatures.exe!UWPMiniatures.MainPage.FilterGridView(string submission) Line 156 C# Symbols loaded.
UWPMiniatures.exe!UWPMiniatures.MainPage.SearchIcon_Click(object sender, Windows.UI.Xaml.RoutedEventArgs e) Line 95 C# Symbols loaded.
So, working backwords, the FolderPicker is being called here:
private async Task SetSaveFolder()
{
if(!StorageApplicationPermissions.FutureAccessList.ContainsItem("PickedFolderToken"))
{
FolderPicker folderPicker = new FolderPicker();
folderPicker.SuggestedStartLocation = PickerLocationId.Desktop;
folderPicker.FileTypeFilter.Add("*");
folderPicker.CommitButtonText = "Pick A Folder To Save Your Data";
StorageFolder folder = await folderPicker.PickSingleFolderAsync();
if (folder != null)
{
// Application now has read/write access to all contents in the picked folder (including other sub-folder contents)
StorageApplicationPermissions.FutureAccessList.AddOrReplace("PickedFolderToken", folder);
var userFolder = await StorageApplicationPermissions.FutureAccessList.GetFolderAsync("PickedFolderToken");
var file = await userFolder.CreateFileAsync("AllMinisList.json",CreationCollisionOption.OpenIfExists);
var imagefolder = await userFolder.CreateFolderAsync("Images");
}
}
}
The folder picker dialog opens, with a blinking cursor next to Folder:, but nothing happens when I click anywhere, nor can i type in Folder: textbox. Now, putting this identical code in a new project and calling it in response to a click event works fine: Dialog opens, I make a new folder or pick an existing one, it gets added to future access list. Not sure how to else to troubleshoot this but the problem seems to lie out side the actual code calling the FolderPicker.
here is the code for the other calling function
private void SearchIcon_Click(object sender, RoutedEventArgs e)
{
FilterGridView(SearchTextBox.Text);
SearchTextBox.Text = "";
}
private async void FilterGridView(string submission)
{
var selected = FilterComboBox.SelectedValue;
miniDS = new MiniDataService();
if(selected.ToString()=="All")
{
MiniList.Clear();
List<Miniature> fullList = await miniDS.Load();
fullList.ForEach(m => MiniList.Add(m));
}
else if (selected.ToString() == "Quantity")
{
List<Miniature> fullList = await miniDS.Load();
var templist = fullList.AsQueryable()
.Where($"{selected} = #0", submission); ;
MiniList.Clear();
templist.ToList<Miniature>()
.ForEach(m => MiniList.Add(m));
}
else
{
List<Miniature> fullList = await miniDS.Load();
var templist = fullList.AsQueryable()
.Where($"{selected}.StartsWith(#0)", submission);
MiniList.Clear();
templist.ToList<Miniature>()
.ForEach(m => MiniList.Add(m));
}
}
MiniDataService and MiniDal don't do much here other than pass the call along.
Any ideas where I can look to troubleshoot this?
UPDATE: Some additional info, I copied the code from SetSaveFolder() directly into a new event handler for a button, clicked it, I get FolderPicker, functions perfectly. But thats not at all the functionality needed. I need it to be called, directly or indirectly from my Data Service. So here's where its created:
public sealed partial class MainPage : Page
{
/// <summary>
/// MiniList is the list of minis currently being displayed
/// </summary>
private ObservableCollection<Miniature> MiniList;
private MiniDataService miniDS;
private List<string> FilterComboList;
private Miniature NewMini;
public MainPage()
{
this.InitializeComponent();
miniDS = new MiniDataService();
MiniList = new ObservableCollection<Miniature>();
FilterComboList = PopulateFilterCombo();
NewMini = new Miniature();
MyFrame.Navigate(typeof(MiniListPage), MiniList);
}
...
So the problem seems to have something to do with the fact that FolderPicker is being called from this "static" object. Is this a thread issue? I thought in UWP I am always on the UI threadm and since at the top level an event handler is calling folderPicker I can't understand why the UI seems locked.
So i think I figured it out, though I have no idea why this happened. If anyone can clue me in, id appreciate it.
So from the call List<Miniature> fullList = await miniDS.Load();
Here's that method:
public async Task<List<Miniature>> Load()
{
return await minidal.LoadAllAsync();
}
public async Task<List<Miniature>> LoadAllAsync()
{
List<Miniature> MiniCollection = new List<Miniature>();
if (StorageApplicationPermissions.FutureAccessList.ContainsItem("PickedFolderToken"))
{
try
{
var userFolder = await StorageApplicationPermissions.FutureAccessList.GetFolderAsync("PickedFolderToken");
var file = await userFolder.GetFileAsync("AllMinisList.json");
var data = await file.OpenReadAsync();
using (StreamReader stream = new StreamReader(data.AsStream()))
{
string text = stream.ReadToEnd();
MiniCollection = JsonConvert.DeserializeObject<List<Miniature>>(text);
}
}
catch(Exception e)
{
throw e;
}
}
else
{
SetSaveFolder().Wait();
return MiniCollection;
}
return MiniCollection;
}
So the problem was right here:
SetSaveFolder().Wait();
When I replace that with
await SetSaveFolder();
it works fine. I can click in the folderPicker, and it does what it's supposed to. I guess I though .Wait() was used when you aren't return anything other than but it seems there is more too it than that!

Removing a command from DiscordBot CommandService

I am trying to figure out how to remove a command from the discord bot after it has been created. Here is how I create the command:
_commandService.CreateCommand("create").Parameter("message", ParameterType.Multiple).Do(async e =>
{
var message = e.Args.Skip(1).Aggregate("", (current, t) => current + (t + " "));;
_commandService.CreateCommand("hello").Do(async cc =>
{
await e.User.SendMessage(customCommand.Message);
});
});
The _commandService object is of type Discord.Commands.CommandService
Now, I want to be able to run:
_commandService.CreateCommand("delete").Parameter("message", ParameterType.Multiple).Do(async e =>
{
_commandService.DeleteCommand("hello");
});
However, no such method exists, nor am I able to access the commands inside _commandService object as everything is read only get;
Does anyone know how I can delete the command without having to restart the bot?
It's possible, but as of discord.net 1.0 you need to use the Modules system to do it. Unfortunately, it greatly complicates things. Hopefully they'll add a proper DeleteCommand(string commandName) in a future update.
Why you need to do this (this section not needed if you don't care about the discord.net source): The
class CommandMap (it stores the commands, unsurprisingly) exposes a method RemoveCommand that does what you're looking to do. The only reference to an object of this class in the source is in the private method RemoveModuleInternal in CommandService. This is exposed in one of two public methods: RemoveModuleAsync(ModuleInfo module) or RemoveModuleAsync<T>(). There is no other way to affect commands as of the 1.0 release.
How to do it: Get the ModuleInfo object for your module first. Preferably, the module you create will only contain the command you want to delete for reasons that should be obvious pretty soon. When you use CreateModuleAsync(string primaryAlias, Action<ModuleBuilder> buildFunc) (or one of the other methods used to add modules) you'll get the ModuleInfo object back. This does mean you need to use a ModuleBuilder instead of the simple commandService.CreateCommand method you use. Read up on how to do that here... if the process still confuses you, it's an excellent topic for another question.
You need to keep track of the ModuleInfo object that CreateModuleAsync returns in some manner (the method I would use is below) and then your second command becomes:
// private ModuleInfo createInfo
_commandService.CreateCommand("delete").Parameter("message", ParameterType.Multiple).Do(async e =>
{
if (createInfo != null)
{
await _commandService.DeleteModuleAsync(createInfo);
}
});
Do note that the entire module instance is getting deleted... that's why your "create" command should be the only thing in it.
An alternate solution (although significantly less elegant) if this whole Module business seems too complicated would be to store a boolean and simply toggle it to simulate the deletion of the command. That is:
// bool createNotDeleted = true;
_commandService.CreateCommand("create").Parameter("message", ParameterType.Multiple).Do(async e =>
{
if (createNotDeleted)
{
var message = e.Args.Skip(1).Aggregate("", (current, t) => current + (t + " "));;
_commandService.CreateCommand("hello").Do(async cc =>
{
await e.User.SendMessage(customCommand.Message);
});
}
else
{
// error handling
}
});
and
_commandService.CreateCommand("delete").Parameter("message", ParameterType.Multiple).Do(async e =>
{
if (createNotDeleted)
{
createNotDeleted = false
// return something indicating command is deleted
}
else
{
// error handling
}
});

How to I pass the object itself (like how we can do in C#) in mootools?

I would like to know how to pass self to an other object in mootools,
I am trying to build classes based on mootools class declaration, but i am noticing i cannot send the object itself using this when i use this it sends DOMWindow instead of World or the object itself, the following is my code,
var World = new Class({
....
initialize: function(rows, ...) {
// build grass // can only have one grass per location
this.grassList = Enumerable.Range(0, rows).SelectMany(
function(row) {
return Enumerable.Range(0, columns).Select(
function(column) {
return new Grass(this, new Location(row, column), quantityOfGrass, maxQuantityOfGrass, growRateOfGrass)
})
}).ToArray();
}
....
}
I'm facing problem at this location,
return new Grass(this, new Location(row, column), quantityOfGrass, maxQuantityOfGrass, growRateOfGrass)
since it didn't work i checked for,
return new Grass(World, new Location(row, column), quantityOfGrass, maxQuantityOfGrass, growRateOfGrass)
it didn't work either i am using linq.js and mootools could someone guide me?
var World = new Class({
....
initialize: function(rows, ...) {
// save a reference to the correct "this"
var self = this;
// build grass // can only have one grass per location
self.grassList = Enumerable.Range(0, rows).SelectMany(
function(row) {
return Enumerable.Range(0, columns).Select(
function(column) {
return new Grass(self, new Location(row, column), quantityOfGrass, maxQuantityOfGrass, growRateOfGrass)
})
}).ToArray();
}
....
}
The object referenced by this changes dynamically.
A callback function like your function(column) will know nothing about what this referred to in functions called earlier. If you want to re-use the reference to a specific this, you must save that reference in a variable.

Categories