I am trying to add a map to a Windows 8 Store app using the Bing Map SDK and control. With this set of Xaml:
<Page.Resources>
<DataTemplate x:Key="LogoTemplate">
<m:Pushpin m:MapLayer.Position="{Binding Item2}" Text="{Binding Item1}"/>
</DataTemplate>
</Page.Resources>
...
<m:Map Credentials="{StaticResource BingMapsApiKey}" ZoomLevel="12" HomeRegion="US" Heading="2">
<m:MapItemsControl x:Name="ListOfItems"
ItemTemplate="{StaticResource LogoTemplate}"
ItemsSource="{Binding LocationList}">
</m:MapItemsControl>
</m:Map>
Bound to this Property of the view model:
public IEnumerable<Tuple<string, Bing.Maps.Location>> LocationList
{
get
{
if (MapLocation != null)
{
return new List<Tuple<string, Bing.Maps.Location>>
{
new Tuple<string, Bing.Maps.Location>("1", new Bing.Maps.Location(MapLocation.lat, MapLocation.lng))
};
}
return Enumerable.Empty<Tuple<string, Bing.Maps.Location>>();
}
}
It consistently excepts with an E_FAIL HResult from a COM component in Bing maps. With this message in the debugger output window:
WinRT information: Failed to assign to property 'Bing.Maps.MapLayer.Position'
Lat and Long are valid points. I am stumped and cannot see anything to do differently. The interwebs has very little information about the App Store version of the Bing Maps control so am hoping somebody has gotten this to work.
Just in case anybody else has this issue (or also encounters difficulty integrating the windows store version of this control to a MVVM model) it looks like the solution is to wrap the control in a bindable version. I used this code form codeplex with some success so far.
It's simply not possible to data-bind the MapLayer.Position to a Location object, but you can data-bind Latitude and Longitude:
<m:Pushpin Text="{Binding Item1}"/>
<m:MapLayer.Position>
<m:Location Latitude="{Binding Item2.Latitude}" Longitude="{Binding Item2.Longitude}" />
</m:MapLayer.Position>
</m:Pushpin>
Related
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:
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.
I added to a working page this angular directive from angular ui
<input type="text" ng-model="vm.test" placeholder="prima selezionare il comune"
typeahead="address for address in vm.updateQuartieri($viewValue)"
typeahead-loading="loadingLocations" class="form-control" />
<i ng-show="loadingLocations" class="glyphicon glyphicon-refresh"></i>
I'm using the controller as syntax, the updateQuartieri return an array of string and all the controller is working fine. When I start to type in the text box, I receive this error
TypeError: Cannot read property 'length' of undefined
at http://localhost:43638/Scripts/angular-ui/ui-bootstrap-tpls.js:3602:24
looking to the source
var getMatchesAsync = function(inputValue) {
var locals = {$viewValue: inputValue};
isLoadingSetter(originalScope, true);
$q.when(parserResult.source(originalScope, locals)).then(function(matches) {
//it might happen that several async queries were in progress if a user were typing fast
//but we are interested only in responses that correspond to the current view value
var onCurrentRequest = (inputValue === modelCtrl.$viewValue);
if (onCurrentRequest && hasFocus) {
if (matches.length > 0) {
looks like the errors occur during the server call, because before I do the call all is fine, and happens before the server call returns data.
I'm using angular 1.3.
Any suggestions?
Luca
Yes, I solved, the problem is that the call to the controller in the typeahead is asynchronous, so the method that you're going to call must return a promise, not the actual data.
I've got the AjaxFileUpload control working just fine -- it uploads, and on completion calls the server-side code to move the files around, works just fine, etc etc etc.
What I'm worried about are potential server-side errors, and how to hand back some sort of warning to the user. Not an Ajax error, but something on the server-side code.
Now, I've got log4net running just fine, and it's called in my error-trapping code and merrily dumping logs when I hard-code an error.
But that doesn't tell the users anything.
RegisterStartupScript doesn't seem to be a valid solution, because there's no PostBack that would allow it to operate (same as my first attempt at populating fields. doh!).
Now, I can shove some JS into the ClientUploadComplete or ClientUploadCompleteAll to do a PostBack... but that doesn't seem right, and it would require that server-side error-messages be queued-up for display. Plus, it clears out the AjaxFileUpload display of what has been uploaded.
All the error-handling I've seen regarding these controls is for Ajax errors.
Is there anything for server-side issues that allows for easy feedback to the user?
Am I even barking up the right trees?
UPDATE Using the pointers # Yuriy's other answer I've got the following working:
Onn the server side:
protected void OnUploadComplete(object sender, AjaxFileUploadEventArgs e)
{
try
{
// does something with the uploaded files that _might_ fail
}
catch (Exception ex)
{
var ce = Logger.LogError(ex);
var msg = string.Format("{{ 'id': '{0}', 'message': '{1}'}}",
ce.ErrorId, ce.Message);
e.PostedUrl = msg;
}
}
(The Logger dumps the complete exception into a log4net log, and returns an error-number and consumer-friendly message to contact support)
Back on the page, the AjaxFileUpload control is configured to call the JS when complete:
<asp:AjaxFileUpload runat="server" ID="Uploader" MaximumNumberOfFiles="10"
OnUploadComplete="OnUploadComplete"
OnClientUploadComplete="AjaxFileUpload1_OnClientUploadComplete"/>
And the javascript:
<script type="text/javascript">
function AjaxFileUpload1_OnClientUploadComplete(sender, args) {
var errText = args.get_postedUrl();
if (!errText) return; // only process if populated
var errinfo = Sys.Serialization.JavaScriptSerializer.deserialize(errText);
if (errinfo && errinfo.id && errinfo.message) {
var idEl = document.getElementById('errnbr');
var msgEl = document.getElementById('errmsg');
if (idEl && msgEl) {
idEl.innerHTML = errinfo.id;
msgEl.innerHTML = errinfo.message;
}
}
}
</script>
which populates the following:
<div class="failureNotification" id="ErrorDisplay" runat="server">
<span id="errnbr"><asp:Literal ID="ErrorNumber" runat="server"></asp:Literal></span>
<span id="errmsg"><asp:Literal ID="FailureText" runat="server"></asp:Literal></span>
</div>
Although AjaxFileUploadState enumeration include Failed member I can't find any case where it used.
So there are two solutions available I believe.
The first is to tweak ACT project to add setters to State and StatusMessage properties of AjaxFileUploadEventArgs class and handle values of these properties on client in raiseUploadComplete function of Sys.Extended.UI.AjaxFileUpload.Control class and onUploadCompleteHandler of Sys.Extended.UI.AjaxFileUpload.ProcessorHtml5 class.
Or you can pass custom JSON to client via AjaxFileUploadEventArgs.PostedUrl property, deserialize it on client in OnClientUploadComplete handler and show error message if any. Please check this question for sample of usage PostedUrl property: getting asynfileupload controls file name on button click
I am trying to use the excellent DataGrid available in the Extended WPF Toolkit Community Edition made available by Xceed (http://wpftoolkit.codeplex.com/). I have an application that displays the results from reports in a simple DataGridControl object. The user can select the report from a list of reports and the data grid dynamically updates using a DataTable associated to the report. The columns in each Report's DataTable can vary both in name and quantity. With the default controls in WPF this works just fine using regular MVVM data binding. This also works fine with the DataGridControl from Xceed, except for when a column has been used to sort or group the data.
What happens is when a column is sorted or grouped, and the DataTable is updated to one that doesn't have the column in it, the DataGridControl throws an ArgumentException saying the column being sorted doesn't exist. Here's an example exception:
System.ArgumentException was unhandled
Message='' type does not have property named 'SAP_MATERIAL_NUMBER', so cannot sort data
collection.
Source=PresentationFramework StackTrace:
at System.Windows.Data.BindingListCollectionView.ConvertSortDescriptionCollection(SortDescriptionCollection
sorts)
at System.Windows.Data.BindingListCollectionView.RefreshOverride()
at System.Windows.Data.CollectionView.Refresh()
at System.Windows.Data.CollectionView.EndDefer()
at System.Windows.Data.CollectionView.DeferHelper.Dispose()
at System.Windows.Controls.ItemCollection.SetCollectionView(CollectionView
view)
at System.Windows.Controls.ItemCollection.SetItemsSource(IEnumerable
value)
at System.Windows.Controls.ItemsControl.OnItemsSourceChanged(DependencyObject
d, DependencyPropertyChangedEventArgs e)
...
Here's my current XAML that defines and binds the control:
<xcdg:DataGridControl
Grid.Row="2"
AutoCreateColumns="True"
AutoRemoveColumnsAndDetailConfigurations="True"
ReadOnly="True"
x:Name="xceedReportResult"
ItemsSource="{Binding SelectedReport.Report.Result}"
FontSize="11">
<xcdg:DataGridControl.View>
<xcdg:TableflowView
ShowRowSelectorPane="False"
IsAnimatedColumnReorderingEnabled="True"
HorizontalGridLineBrush="LightGray"
VerticalGridLineBrush="LightGray"
IsAlternatingRowStyleEnabled="True"
ShowScrollTip="False">
<xcdg:TableflowView.Theme>
<xcdg:ClassicSystemColorTheme />
</xcdg:TableflowView.Theme>
</xcdg:TableflowView>
</xcdg:DataGridControl.View>
</xcdg:DataGridControl>
...following some advice from the Xceed forums I've tried running the following code when a new report is selected in hopes of clearing out any SortDescriptions or GroupDescriptions, but this isn't working right:
ICollectionView source = xceedReportResult.ItemsSource as DataGridCollectionView;
if (source != null)
{
if (source.SortDescriptions != null)
{
source.SortDescriptions.Clear();
}
if (source.GroupDescriptions != null)
{
source.GroupDescriptions.Clear();
}
}
Has anyone used this data grid in this way, and found a way around this issue?
I think I found my issue, or at least a way to handle this without having exceptions be thrown. I modified by XAML code to use an explicit DataGridCollectionViewSource declaration for my grid:
<Control.Resources>
<xcdg:DataGridCollectionViewSource
x:Key="reportResultView"
x:Name="reportResultView"
Source="{Binding SelectedReport.Report.Result.DefaultView}"
AutoCreateItemProperties="True"/>
</Control.Resources>
and then update my DataGridControl to use this as the ItemsSource instead of binding directly to the DataTable:
<xcdg:DataGridControl
Grid.Row="2"
AutoCreateColumns="True"
AutoRemoveColumnsAndDetailConfigurations="True"
ReadOnly="True"
x:Name="xceedReportResult"
ItemsSource="{Binding Source={StaticResource reportResultView}}"
FontSize="11">
<xcdg:DataGridControl.View>
<xcdg:TableflowView
ShowRowSelectorPane="False"
IsAnimatedColumnReorderingEnabled="True"
HorizontalGridLineBrush="LightGray"
VerticalGridLineBrush="LightGray"
IsAlternatingRowStyleEnabled="True"
ShowScrollTip="False">
<xcdg:TableflowView.Theme>
<xcdg:ClassicSystemColorTheme />
</xcdg:TableflowView.Theme>
</xcdg:TableflowView>
</xcdg:DataGridControl.View>
</xcdg:DataGridControl>
Once I do that it no longer throws exceptions if the sorted or grouped column(s) don't exist, and the data grid updates as expected.