MapsUI always shows "own location" marker at LatLng 0,0 - xamarin.forms

I have the issue with MapsUI 2.0.3 that the marker of my own location is always at 0,0 west of Africa. Clicking the focus on own location button obviously also moves me there.
I did add coarse and fine location permissions to manifest and do get permission to access locations, but "you are here" is always 0,0.
I then downloaded the MapsUI repository, and tried the samples, which show the same behavior, mostly. When the map loads, it shows position at 0,0. If I drag the map slightly, the marker slowly moves to my correct position. If I (in the samples) reload the same sample or another one, the marker remains stuck at 0,0, even when I drag the map. In summary, I can "fix" the 0,0 marker by interacting with the map but only once.
My device does have gps location enabled, and other location using apps work fine. This including other home made Xamarin forms apps, so this is an issue for MapsUI only.
It failing for both samples and own code makes this a bit confusing.
Does this ring a bell for anyone? Seems a bit strange to say the least.
Note that this also fails on the xamagin/android device emulator with a set position. Just mentioning this as a "fun" extra detail, map longpress event will never fire on my device, but does work on the emulator. I saw someone else, a long time back, complaining about that same issue, and a developer commenting on it being fixed in 2.0, while I see it in 2.3. All in all MapsUI seems like an extremely rich system that I would love to use, but which has weird little bugs and poor support.
The xaml for adding the mapview
<StackLayout>
<mapsui:MapView x:Name="mapView" IsMyLocationButtonVisible="True" />
</StackLayout>
And the c# setup
void start()
{
var status = await Permissions.RequestAsync<Permissions.LocationAlways>();
if(status==PermissionStatus.Denied) return;
var map = new Mapsui.Map
{
Transformation = new MinimalTransformation(),CRS = "EPSG:3857"};
var tileSource = new HttpTileSource(new GlobalSphericalMercator(),
"https://tile.thunderforest.com/landscape/{z}/{x}/{y}.png?
apikey=xxxxxxxxx",new[] { "a", "b", "c" }, name: "OpenStreetMap");
var tileLayer = new TileLayer(tileSource) { Name = "Carto Light" };
map.Layers.Add(tileLayer);
mapView.Map = map;
}

Although not knowing why MyLocationButton not works, but there is a workaround to make the current location to show in MapsUI.
There is a UpdateMyLocation method inside MyLocationLayer,then we can use this method to show the current location programmatically.
In addition, you could use Geolocation to get the current location.
Code as follows:
protected override async void OnAppearing()
{
base.OnAppearing();
var location = await Geolocation.GetLastKnownLocationAsync();
if (location != null)
{
Console.WriteLine($"Latitude: {location.Latitude}, Longitude: {location.Longitude}, Altitude: {location.Altitude}");
}
mapView.MyLocationLayer.UpdateMyLocation(new Position(location.Latitude, location.Longitude), true);
}
The effect:

Related

Launch MAP in Xamarin Forms ANDROID and camera move to user's current location

all right?
I'm banging my head with something that might be simple, but I can't think of anything else.
I want to make it so that when the user opens my app's map screen, the map camera will focus on where the user is located in real time.
PS: I'm using Xamarin.Essentials
Ps2: With this code the camera stays at Rome city or moves to ocean, but i need that moves to my atual position.
Below is the code I'm using, any help is welcome.
public async void AproximaLocalUsuario()
{
try
{
var request = new GeolocationRequest(GeolocationAccuracy.Medium);
var location = await Geolocation.GetLocationAsync(request);
if (location != null)
{
Position position = new Position(location.Latitude, location.Longitude);
MapSpan mapSpan = MapSpan.FromCenterAndRadius(position, Distance.FromKilometers(0.444));
map.MoveToRegion(mapSpan);
}
}
catch (FeatureNotSupportedException fnsEx)
{
// Handle not supported on device exception
}
I managed to get it to work, I wasn't starting the function, that was the problem. Below is the code that is working for me. Thanks for your help and I hope this post helps more people.

Xamarin Forms Prism DialogService takes some seconds to show up

My Dialog is a simple Frame with an Image, a label to display a question and two more labels (Yes / No) with TapCommand.
I've set up the container with the DialogPage.xaml and DialogPageViewModel and injected in the ViewModel I want to open the dialog.
Here is the code I'm using to call the Dialog:
public void ShowDialog()
{
_dialogService.ShowDialog("DiscardPopup", CloseDialogCallback);
}
void CloseDialogCallback(IDialogResult dialogResult)
{
var goBack = dialogResult.Parameters.GetValue<bool>("GoBack");
if (goBack)
NavigationService.GoBackAsync();
}
If the user taps over the "Yes label", I execute this command:
YesCommand = new DelegateCommand(() => YesTapped());
private void YesTapped()
{
IDialogParameters pa = new DialogParameters();
pa.Add("GoBack", true);
RequestClose(pa);
}
If the user taps over the "No label", I simply call:
NoCommand = new DelegateCommand(() => RequestClose(null));
The "problem" is when the ShowDialog is fired, the DiscardPopup is taking up to 3 seconds to show up.
Is there a way to make it faster?
The same happens with the TapCommands, 2 - 3 seconds when the RequestClose is invoked.
Without actual code telling you exactly what the issue is, is going to be best guess. Based on your feedback to my comments above I would suggest the following:
Try displaying the dialog on a test page that doesn't have a complex layout. My guess is that you won't see such a long load time. If that's the case this would point to your layout being overly complex and that the lag time is due to the device struggling to re-render the View
Try using Prism.Plugin.Popups. You'll need to initialize Rg.Plugins.Popup and register the DialogService. You can see docs on that at http://popups.prismplugins.com

Xamarin Forms crossPlatform: force to repaint

I know i know: probably it is one of the most asked questions. Before you send me some LMGTFY links, let me tell that I've been some hours with this question, and I've made some tries with Invalidate, PostInvalidate, RunOnUIThread, etc; with no success. I do not discard that the solution can be one of the previously mentioned, and I have not been using it properly. I am actually learning Xamarin, doing my first crossplatform app, so my knowledge of the framework is very poor.
So now let's go to my concrete problem, and let's see if someone can help me. I want a intro page for my app, with a progress bar and a text below saying what is doing the app (when starting the app, it calls a WS to download changes, and has to load info from text files and put it into some static data structures to use for all pages). What i want to do in the loading page is the following sequence:
1. Change text to tell what is the app doing.
2. Call WS or load a file.
3. Update progress bar.
4. Go to next update or to the welcome page if all is loaded.
What i get for my actual code is that the page is load when all the stuff is done, so I see the progress bar completed and the last text change. But is a static page, i don't see the progress bar growing neither the text changing.
This is my code:
public partial class LoadingPage : ContentPage
{
InitializeComponent();
this.lpb.Text = "Connecting to web server to check updates";
App.localInfo.updateInfo(); //Connect web server to check updates
this.pb.Progress = 0.2;
this.lpb.Text = "Loading info from local files";
App.localInfo.cargarInfo(); //Load local files to memory for quick access
this.pb.Progress = 0.7;
this.lpb.Text = "Doing other stuff"; //This is only for proves
Task.Run(async () =>
{
await Task.Delay(2000);
});
this.pb.Progress = 1;
this.lpb.Text = "Load completed. The app will start now";
}
And this is my ContentPage:
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Prueba1.Views.LoadingPage">
<ContentPage.Content>
<StackLayout>
<ProgressBar x:Name="pb" Progress="0.0" ProgressColor="Red"/>
<Label x:Name="lpb" Text="Welcome to Xamarin.Forms!"/>
</StackLayout>
</ContentPage.Content>
</ContentPage>
This is only the alpha version. I would like to concrete a little more, because I have to load around 10 different text files, and I would like to update progress bar and label inside the App.localInfo methods. But first I have to learn how to do this simple stuff, and then trying something more complicated.
Thanks in advance!
Instead of setting the progress property like you are, try using the progress bar's ProgressTo method inside an async method. Something like:
public MainPage()
{
InitializeComponent();
FireProgressBar();
}
async void FireProgressBar()
{
lpb.Text = "Connecting to web server to check updates";
// Task.Delay to simulate network call.
await Task.Delay(2000);
await pb.ProgressTo(.2, 250, Easing.Linear);
lpb.Text = "Loading info from local files";
// Task.Delay to simulate network call.
await Task.Delay(2000);
await pb.ProgressTo(.7, 250, Easing.Linear);
lpb.Text = "Doing other stuff";
// Task.Delay to simulate network call.
await Task.Delay(2000);
await pb.ProgressTo(1.0, 250, Easing.Linear);
lpb.Text = "Load completed. The app will start now";
}
This has the added benefit of actually seeing the progress bar moving, not just jerking from one value to the next.

Working with in memory FeatureSet and Feature DotSpatial

I'm a beginner with DotSpatial and I'm stuck with a problem.
I try to work with in memory feature (to keep them only in Map) until the user hit save button.
The basic idea is that the user imports some dxf files and creates featureset based on layer name if the FeatureSet doesn't all ready exist, and for each polyline from dxf creates feature which will be added into a featureset.
public IFeature AddPoligons(EntityObject polyline, List<Text> textInDxf)
{
IFeatureSet featureSet = null;
//Getting the right featureset from map
foreach (var x in appManager.Map.GetPolygonLayers())
{
if (!string.Equals(x.DataSet.Name, layerName)) continue;
featureSet = x.DataSet as FeatureSet;
break;
}
var polygon = CreatePolygon(polyline);
//Creating feature and adding to FeatureSet
var feature = featureSet.AddFeature(polygon);
//Populating DataRow with information
AddinfoIntoDataTable(feature, polygon, textInDxf);
return feature;
}
Everything thing looks fine, the map is updated with new polygons, can select them, view information from datatable BUT, when I try to delete a selected feature (polygon) it throws an IndexOutOfRange exception.
What I'm doing wrong there?
Please help! Thank you and sorry for my poor English.
P.S.
When I created the featureSet first I saved it on the disk and then loaded into map with Map.AddLayer() method.
Meanwhile I found the solution somewhere on CodePlex-DotSpatial forum, and was posted by Jany.
The idea is to call this pice of code after each action against a FeatureSet (add, remove, move)
featureLayer.DataSet.UpdateExtent();
featureLayer.DataSet.InitializeVertices();
featureLayer.LabelLayer?.CreateLabels();
if(save)
{
featureLayer.DataSet.Save();
featureLayer.DataSet.Close();
}
featureLayer.AssignFastDrawnStates();
AppManager.Map.Refresh();
AppManager.Map.ResetBuffer();
where featureLayer is IFeatureLayer.
There is one problem:
If we save the project with AppManager.Serialization.SaveProject() and then open the project AppManager.Serialization.OpenProject() the issue appear again.
As a solution for this I call my Save method after open the project and on short is look like this:
public void Save()
{
foreach(var featureLayer in AppManager.Map.GetPolygonLayers())
{
featureLayer.DataSet.Save();
}
}
Hope that helps someone.

Is there a way to access ALAssets information outside of resultBlock?

Okay so I have my ImagePicker all setup and the ALAssetLibrary setup to get the Picture and Title (if it exists for existing pictures or generic text for a new picture) but now I'm trying to figure out if there's a way I can access this information outside of the block call from the assetForURL method. So here's my code just so I can show what's happening (this is in the viewDidLoad method of a screen that is displayed after a picture selection is made)
__block NSString *documentName;
__block UIImage *docImage;
NSURL *resourceURL = [imageInfo objectForKey:UIImagePickerControllerReferenceURL];
ALAssetsLibraryAssetForURLResultBlock resultblock = ^(ALAsset *asset)
{
ALAssetRepresentation *imageRep = [asset defaultRepresentation];
//Get Image
CGImageRef iref = [imageRep fullResolutionImage];
//If image is null then it's a new picture from Camera
if (iref == NULL) {
docImage = [imageInfo objectForKey:UIImagePickerControllerOriginalImage];
documentName = #"New Picture";
}
else {
docImage = [UIImage imageWithCGImage:iref];
documentName = [imageRep filename];
}
};
// get the asset library and fetch the asset based on the ref url (pass in block above)
ALAssetsLibrary *imageAsset = [[ALAssetsLibrary alloc] init];
[imageAsset assetForURL:resourceURL resultBlock:resultblock failureBlock:nil];
Now I want to be able to use the two variables (documentName and docImage) elsewhere in this ViewController (for example if someone wants to change the name of the document before they save it I want to be able to revert back to the default name) but I can't seem to figure out what I need to do so these variables can be used later. Don't know if this makes much sense or not, so if I need to clarify anything else let me know.
Okay so I figured out that the problem wasn't with the code but with my logic on how I was using it. I was trying to do this on the Modal View that was presented after an image was selected instead of just doing this in the ImagePicker screen and then calling the Modal window inside of the result block code.

Resources