Xamarin.Forms.Maps - Catastrophic failure (Exception from HRESULT: 0x8000FFFF (E_UNEXPECTED)) - exception

I followed the Xamarin Tutorial Customizing a Map.
I changed it a bit to be able to draw a route.
public class CustomMap : Map
{
public static readonly BindableProperty RouteCoordinatesProperty =
BindableProperty.Create(nameof(RouteCoordinates), typeof(List<Position>), typeof(CustomMap), new List<Position>(), BindingMode.TwoWay);
public List<Position> RouteCoordinates
{
get { return (List<Position>)GetValue(RouteCoordinatesProperty); }
set { SetValue(RouteCoordinatesProperty, value); }
}
}
The WinPhone 8.1 renderer:
[assembly: ExportRenderer(typeof(CustomMap), typeof(CustomMapRenderer))]
namespace PROJECT.WinPhone
{
public class CustomMapRenderer : MapRenderer
{
MapControl nativeMap;
CustomMap formsMap;
protected override void OnElementChanged(ElementChangedEventArgs<Map> e)
{
base.OnElementChanged(e);
if (e.OldElement != null)
{
nativeMap = Control as MapControl;
}
if (e.NewElement != null)
{
formsMap = (CustomMap)e.NewElement;
nativeMap = Control as MapControl;
//UpdatePolyLine();
var coordinates = new List<BasicGeoposition>();
foreach (var position in formsMap.RouteCoordinates)
{
coordinates.Add(new BasicGeoposition() { Latitude = position.Latitude, Longitude = position.Longitude });
}
var polyline = new MapPolyline();
polyline.StrokeColor = Windows.UI.Color.FromArgb(128, 255, 0, 0);
polyline.StrokeThickness = 5;
polyline.Path = new Geopath(coordinates);
nativeMap.MapElements.Add(polyline);
}
}
}
}
polyline.Path = new Geopath(coordinates); throws Catastrophic failure (Exception from HRESULT: 0x8000FFFF (E_UNEXPECTED))
The problem is that my two others renderer (Android & iOS) works.. Maybe something isn't possible because I work with WinPhone8.1 unlike the tutorial, which is UWP
AndroidRenderer
[assembly: ExportRenderer(typeof(CustomMap), typeof(CustomMapRenderer))]
namespace PROJECT.Droid
{
public class CustomMapRenderer : MapRenderer, IOnMapReadyCallback
{
GoogleMap map;
Polyline polyline;
protected override void OnElementChanged(Xamarin.Forms.Platform.Android.ElementChangedEventArgs<Xamarin.Forms.View> e)
{
base.OnElementChanged(e);
if (e.OldElement != null)
{
// Unsubscribe
}
if (e.NewElement != null)
{
((MapView)Control).GetMapAsync(this);
}
UpdatePolyLine();
}
protected override void OnElementPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
if (this.Element == null || this.Control == null)
return;
if (e.PropertyName == CustomMap.RouteCoordinatesProperty.PropertyName)
{
UpdatePolyLine();
}
}
private void UpdatePolyLine()
{
if (map != null)
{
if (polyline != null)
{
polyline.Remove();
polyline.Dispose();
}
var polylineOptions = new PolylineOptions();
polylineOptions.InvokeColor(0x66FF0000);
int a = 0;
foreach (var position in ((CustomMap)this.Element).RouteCoordinates)
{
polylineOptions.Add(new LatLng(position.Latitude, position.Longitude));
}
polyline = map.AddPolyline(polylineOptions);
}
}
public void OnMapReady(GoogleMap googleMap)
{
map = googleMap;
UpdatePolyLine();
}
}
}
iOSRenderer
[assembly: ExportRenderer(typeof(CustomMap), typeof(CustomMapRenderer))]
namespace PROJECT.iOS
{
public class CustomMapRenderer : MapRenderer
{
MKMapView nativeMap;
MKPolylineRenderer polylineRenderer;
protected override void OnElementChanged(ElementChangedEventArgs<View> e)
{
base.OnElementChanged(e);
if (e.OldElement != null)
{
nativeMap = Control as MKMapView;
nativeMap.OverlayRenderer = null;
}
if (e.NewElement != null)
{
UpdatePolyLine();
}
}
protected override void OnElementPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
if (this.Element == null || this.Control == null)
return;
if (e.PropertyName == CustomMap.RouteCoordinatesProperty.PropertyName)
{
UpdatePolyLine();
}
}
MKOverlayRenderer GetOverlayRenderer(MKMapView mapView, IMKOverlay overlay)
{
if (polylineRenderer == null)
{
polylineRenderer = new MKPolylineRenderer(overlay as MKPolyline);
polylineRenderer.FillColor = UIColor.Blue;
polylineRenderer.StrokeColor = UIColor.Red;
polylineRenderer.LineWidth = 3;
polylineRenderer.Alpha = 0.4f;
}
return polylineRenderer;
}
private void UpdatePolyLine()
{
if (nativeMap != null)
{
var formsMap = ((CustomMap)this.Element);
nativeMap = Control as MKMapView;
nativeMap.OverlayRenderer = GetOverlayRenderer;
CLLocationCoordinate2D[] coords = new CLLocationCoordinate2D[formsMap.RouteCoordinates.Count];
int index = 0;
foreach (var position in formsMap.RouteCoordinates)
{
coords[index] = new CLLocationCoordinate2D(position.Latitude, position.Longitude);
index++;
}
var routeOverlay = MKPolyline.FromCoordinates(coords);
nativeMap.AddOverlay(routeOverlay);
}
}
}
}

After a long time, I found why it didn't works...
If you're doing like me, if you do a HttpRequest to something as Google Direction API, then the result will comes after the first passage in the OnElementChanged().
Because formsMap.RouteCoordinates isn't null but empty, the Catastrophic failure (Exception from HRESULT: 0x8000FFFF (E_UNEXPECTED)) is thrown..
This is the good CustomMapRenderer for PolyLine use
using PROJECT;
using PROJECT.UWP;
using System.Collections.Generic;
using Windows.Devices.Geolocation;
using Windows.UI.Xaml.Controls.Maps;
using Xamarin.Forms.Maps;
using Xamarin.Forms.Maps.UWP;
using Xamarin.Forms.Platform.UWP;
[assembly: ExportRenderer(typeof(CustomMap), typeof(CustomMapRenderer))]
namespace PROJECT.UWP
{
public class CustomMapRenderer : MapRenderer
{
MapControl nativeMap;
CustomMap formsMap;
protected override void OnElementChanged(ElementChangedEventArgs<Map> e)
{
base.OnElementChanged(e);
if (e.OldElement != null)
{
nativeMap = Control as MapControl;
}
if (e.NewElement != null)
{
formsMap = (CustomMap)e.NewElement;
nativeMap = Control as MapControl;
UpdatePolyLine();
}
}
protected override void OnElementPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
if (this.Element == null || this.Control == null)
return;
if (e.PropertyName == CustomMap.RouteCoordinatesProperty.PropertyName)
{
UpdatePolyLine();
}
}
private void UpdatePolyLine()
{
if (formsMap != null && formsMap.RouteCoordinates.Count > 0)
{
List<BasicGeoposition> coordinates = new List<BasicGeoposition>();
foreach (var position in formsMap.RouteCoordinates)
{
coordinates.Add(new BasicGeoposition() { Latitude = position.Latitude, Longitude = position.Longitude });
}
Geopath path = new Geopath(coordinates);
MapPolyline polyline = new MapPolyline();
polyline.StrokeColor = Windows.UI.Color.FromArgb(128, 255, 0, 0);
polyline.StrokeThickness = 5;
polyline.Path = path;
nativeMap.MapElements.Add(polyline);
}
}
}
}

Related

android - picasso not rendering image in first load of fragment

I'm using Picasso library to load image from URL to be rendered in a Google Map Cluster Marker, the problem is on the first load of the Fragment the images is not displaying I have to reload the Fragment for the images to display.
MapsFragment
private ClusterManager mClusterManager;
private ClusterManagerRenderer mClusterManagerRenderer;
private ArrayList<ClusterMarker> mClusterMarkers = new ArrayList<>();
//....
public void onMapReady(GoogleMap googleMap) {
if (ActivityCompat.checkSelfPermission(getContext(), Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(getContext(), Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) return;
//....
mMap = googleMap;
renderMarkers();
setGoogleMapStyle();
//.....
}
private void renderMarkers(){
//.....
if (mClusterManager != null && !mClusterMarkers.isEmpty()) {
mClusterManager.clearItems();
mClusterMarkers.clear();
}
if(mMap != null) {
if(mClusterManager == null) mClusterManager = new ClusterManager<ClusterMarker>(getActivity().getApplicationContext(), mMap);
if(mClusterManagerRenderer == null){
mClusterManagerRenderer = new ClusterManagerRenderer(
getContext(),
mMap,
mClusterManager
);
mClusterManager.setRenderer(mClusterManagerRenderer);
}
try{
ClusterMarker newClusterMarker = new ClusterMarker(
new LatLng((Double) eachImage.get("lat"), (Double) eachImage.get("lng")), // image lat lng
(String) eachImage.get("notes"), // marker title
(String) eachImage.get("notes"), // marker snippet
(String) eachImage.get("image") // image url http://i.imgur.com/DvpvklR.png
);
mClusterManager.addItem(newClusterMarker);
mClusterMarkers.add(newClusterMarker);
}catch (NullPointerException e){
Log.e("tag", "addMapMarkers: NullPointerException: " + e.getMessage() );
}
mClusterManager.cluster();
}
//....
Log.e("tag", "addMapMarkers: markers are set");
}
ClusterManagerRenderer
public class ClusterManagerRenderer extends DefaultClusterRenderer<ClusterMarker> {
//....
#Override
protected void onBeforeClusterItemRendered(ClusterMarker item, MarkerOptions markerOptions) {
Picasso.get().load(item.getThumbnail()).into(imageView);
Bitmap icon = iconGenerator.makeIcon();
markerOptions.icon(BitmapDescriptorFactory.fromBitmap(icon)).title(item.getTitle());
}
//....
}

NullPointerException at dual fragment display

I'm writing an app that has two kinds of displays:
1. "phone mode" on normal sized displays, show one fragment at a time (search fragment, map fragment, etc). Here the fragments load with no particular problem.
2."Tablet mode" on larger displays, shows two fragments side by side - one is the same as "phone mode", the second is a permenant display of the map fragment. When trying to load the app on a tablet emulator it throws an exception:
FATAL EXCEPTION: main
Process: il.co.sredizemnomorie.myapiplaces, PID: 7808
java.lang.RuntimeException: Unable to start activity ComponentInfo{il.co.sredizemnomorie.myapiplaces/il.co.sredizemnomorie.myapiplaces.MainActivity}: java.lang.NullPointerException
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2195)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2245)
at android.app.ActivityThread.access$800(ActivityThread.java:135)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1196)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:136)
at android.app.ActivityThread.main(ActivityThread.java:5017)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:779)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:595)
at dalvik.system.NativeStart.main(Native Method)
Caused by: java.lang.NullPointerException
at maps.f.g.a(Unknown Source)
at maps.ag.g$a.<init>(Unknown Source)
at maps.ag.g.a(Unknown Source)
at maps.ag.R.<init>(Unknown Source)
at maps.ag.t.a(Unknown Source)
at uz.onTransact(:com.google.android.gms.DynamiteModulesB:167)
at android.os.Binder.transact(Binder.java:361)
at com.google.android.gms.maps.internal.IGoogleMapDelegate$zza$zza.addMarker(Unknown Source)
at com.google.android.gms.maps.GoogleMap.addMarker(Unknown Source)
at il.co.sredizemnomorie.myapiplaces.FragmentWithMap.setUpMap(FragmentWithMap.java:165)
at il.co.sredizemnomorie.myapiplaces.FragmentWithMap.setUpMapIfNeeded(FragmentWithMap.java:141)
at il.co.sredizemnomorie.myapiplaces.FragmentWithMap.onCreateView(FragmentWithMap.java:72)
at android.support.v4.app.Fragment.performCreateView(Fragment.java:1974)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1067)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1252)
at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:742)
at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1617)
at android.support.v4.app.FragmentController.execPendingActions(FragmentController.java:339)
at android.support.v4.app.FragmentActivity.onStart(FragmentActivity.java:602)
at il.co.sredizemnomorie.myapiplaces.MainActivity.onStart(MainActivity.java:270)
at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1171)
at android.app.Activity.performStart(Activity.java:5241)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2168)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2245) 
at android.app.ActivityThread.access$800(ActivityThread.java:135) 
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1196) 
at android.os.Handler.dispatchMessage(Handler.java:102) 
at android.os.Looper.loop(Looper.java:136) 
at android.app.ActivityThread.main(ActivityThread.java:5017) 
at java.lang.reflect.Method.invokeNative(Native Method) 
at java.lang.reflect.Method.invoke(Method.java:515) 
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:779) 
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:595) 
at dalvik.system.NativeStart.main(Native Method) 
Here's the code:
MainActivity.java
public class MainActivity extends ActionBarActivity implements FragmentWithDetails.OnFragmentInteractionListener, FragmentWithMap.OnFragmentInteractionListener,
FragmentWithDetails.ListFragmentListener, TextView.OnEditorActionListener, GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener,
SettingsFragment.OnFragmentInteractionListener {
private static final String TAG = "PlaceFounder";
public static final String TAG_FAVORITES = "frag_favorites";
private static final String TAG_MAP = "map";
private static final String TAG_DETAILS = "details";
protected GoogleApiClient mGoogleApiClient;
protected Location mLastLocation;
private Bundle currentLocationBundle = new Bundle();
FragmentTransaction fragmentTransaction;
private android.support.v4.app.FragmentManager fragmentManager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
buildGoogleApiClient();
fragmentManager = getSupportFragmentManager();
FragmentWithDetails fragmentDetails;
if (isSingleFragment()) {
if (savedInstanceState == null) {
fragmentDetails = FragmentWithDetails.newInstance();
fragmentDetails.setArguments(currentLocationBundle);
fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.add(R.id.fragmnet_container, fragmentDetails, TAG_DETAILS);
fragmentTransaction.commit();
}
}//end if we at small screen
else {
if (savedInstanceState == null) {
fragmentDetails = FragmentWithDetails.newInstance();
FragmentWithMap fragmentWithMap = FragmentWithMap.newInstance(null);
fragmentDetails.setArguments(currentLocationBundle);
fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.add(R.id.fragmnet_container_details, fragmentDetails, TAG_DETAILS);
fragmentTransaction.add(R.id.fragmnet_container_map, fragmentWithMap, TAG_MAP);
fragmentTransaction.commit();
}
}//end if big screen
}
// Show favorites fragment
private void showFavorites() {
currentLocationBundle.putInt("isShowFav", 1);
FragmentWithDetails fragmentFavorites = (FragmentWithDetails) fragmentManager.findFragmentByTag(TAG_FAVORITES);
if (fragmentFavorites == null) {
fragmentFavorites = FragmentWithDetails.newInstance();
fragmentFavorites.setArguments(currentLocationBundle);
}
fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.fragmnet_container, fragmentFavorites, TAG_FAVORITES);
fragmentTransaction.addToBackStack(null);
fragmentTransaction.show(fragmentFavorites);
handleLargeLayout();
fragmentTransaction.commit();
}
//Hide details and map only on large screen
//On small screen we reuse the same container
private void handleLargeLayout() {
if (!isSingleFragment()) {
fragmentTransaction.hide(getDetailsFragment());
fragmentTransaction.hide(getMapFragment());
}
}
private FragmentWithMap getMapFragment() {
return (FragmentWithMap) fragmentManager.findFragmentByTag(TAG_MAP);
}
private FragmentWithDetails getDetailsFragment() {
return (FragmentWithDetails) fragmentManager.findFragmentByTag(TAG_DETAILS);
}
private FragmentWithDetails getFavoritesFragment() {
return (FragmentWithDetails) fragmentManager.findFragmentByTag(TAG_FAVORITES);
}
// Show settings fragment
private void showSettings() {
SettingsFragment settingsFragment = SettingsFragment.newInstance();
fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.fragmnet_container, settingsFragment, "frag_settings");
fragmentTransaction.addToBackStack(null);
fragmentTransaction.show(settingsFragment);
handleLargeLayout();
fragmentTransaction.commit();
}
// Display current location on map
private void getCurrentLocation() {
String currentLat = null;
String currentLong = null;
if (mLastLocation != null) {
currentLat = String.valueOf(mLastLocation.getLatitude());
currentLong = String.valueOf(mLastLocation.getLongitude());
if (getMapFragment() != null) {
getMapFragment().setPlace(new Place(0, "Current location", "", (float) mLastLocation.getLatitude(), (float) mLastLocation.getLongitude()));
}
}
currentLocationBundle.putString("currentLat", currentLat);
currentLocationBundle.putString("currentLong", currentLong);
}
//Builds a GoogleApiClient.
protected synchronized void buildGoogleApiClient() {
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_settings:
showSettings();
return true;
case R.id.action_favorites:
showFavorites();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
protected boolean isSingleFragment() {
return findViewById(R.id.layout_single_fragment) != null;
}
#Override
public void onFragmentInteraction(Uri uri) {
}
#Override
public void onPlaceSelected(long placeId) {
fragmentManager = getSupportFragmentManager();
Place place = getPlace(placeId);
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
if (isSingleFragment()) {
FragmentWithMap fragmentWithMap = FragmentWithMap.newInstance(place);
fragmentTransaction.replace(R.id.fragmnet_container, fragmentWithMap, TAG_MAP).addToBackStack(null);
} else {
if (getMapFragment() == null) {
android.support.v4.app.Fragment fragmentWithMap = FragmentWithMap.newInstance(place);
fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.add(R.id.fragmnet_container_map, fragmentWithMap, TAG_MAP);
fragmentTransaction.show(fragmentWithMap);
fragmentTransaction.show(getDetailsFragment());
} else {
FragmentWithMap fragmentWithMap = getMapFragment();
fragmentTransaction.show(fragmentWithMap);
fragmentTransaction.show(getDetailsFragment());
if (getFavoritesFragment() != null) {
fragmentTransaction.hide(getFavoritesFragment());
}
fragmentWithMap.showPlace(place);
}
}
fragmentTransaction.commit();
}
private Place getPlace(long placeId) {
Cursor cursor = null;
Place place = null;
try {
cursor = getContentResolver().query(PlacesContract.Places.CONTENT_URI, null, "_id=" + placeId, null, "name DESC");
cursor.moveToNext();
place = new Place(cursor.getInt(0), cursor.getString(1), cursor.getString(2), cursor.getFloat(3), cursor.getFloat(4));
} finally {
if (cursor != null && !cursor.isClosed()) {
cursor.close();
}
}
return place;
}
#Override
public void onBackPressed() {
if (isSingleFragment() && getMapFragment() != null) {
fragmentManager.popBackStack(null,
FragmentManager.POP_BACK_STACK_INCLUSIVE);
} else if (fragmentManager.findFragmentByTag("frag_favorites") != null) {
fragmentManager.popBackStack(null,
FragmentManager.POP_BACK_STACK_INCLUSIVE);
} else if (fragmentManager.findFragmentByTag("frag_settings") != null) {
fragmentManager.popBackStack(null,
FragmentManager.POP_BACK_STACK_INCLUSIVE);
} else {
super.onBackPressed();
}
}
#Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
return true;
}
#Override
protected void onStart() {
super.onStart();
mGoogleApiClient.connect();
//start google analytics
EasyTracker.getInstance(this).activityStart(this); // Add this method.
}
#Override
protected void onStop() {
super.onStop();
if (mGoogleApiClient.isConnected()) {
mGoogleApiClient.disconnect();
}
//stop google analytics
EasyTracker.getInstance(this).activityStop(this); // Add this method.
}
/**
* Runs when a GoogleApiClient object successfully connects.
*/
#Override
public void onConnected(Bundle connectionHint) {
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
return;
}
mLastLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
if (mLastLocation == null) {
Toast.makeText(this, "Location not found", Toast.LENGTH_LONG).show();
}
getCurrentLocation();
}
#Override
public void onConnectionFailed(ConnectionResult result) {
toast("No Google Service");
Log.i(TAG, "Connection failed: ConnectionResult.getErrorCode() = " + result.getErrorCode());
}
private void toast(String message) {
Toast.makeText(this, message,
Toast.LENGTH_LONG).show();
}
#Override
public void onConnectionSuspended(int cause) {
// The connection to Google Play services was lost for some reason
Log.i(TAG, "Connection suspended");
mGoogleApiClient.connect();
}
}
the map fragment:
FragmentWithMap.java
public class FragmentWithMap extends android.support.v4.app.Fragment {
private OnFragmentInteractionListener mListener;
private static final double LAT = 32.084;
private static final double LON = 34.8878;
Place place;
private GoogleMap mMap;
private View view;
private Marker marker;
int userIcon = FragmentWithDetails.userIcon;
public static FragmentWithMap newInstance(Place place) {
Bundle args = new Bundle();
if (place != null) {
args.putInt("id", place.getId());
args.putString("name", place.getName());
args.putString("address", place.getAddress());
args.putFloat("lat", place.getLat());
args.putFloat("lng", place.getLng());
}
FragmentWithMap fragment = new FragmentWithMap();
fragment.setArguments(args);
return fragment;
}
public FragmentWithMap() {
//empty public constructor
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null && getArguments().getString("name") != null) {
place = new Place(getArguments().getInt("id"), getArguments().getString("name"),
getArguments().getString("address"), getArguments().getFloat("lat"),
getArguments().getFloat("lng"));
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
if (view == null) {
view = inflater.inflate(R.layout.fragment_fragment_with_map, container, false);
}
setUpMapIfNeeded();
return view;
}
#Override
public void onDestroyView() {
super.onDestroyView();
android.support.v4.app.Fragment f = getFragmentManager()
.findFragmentById(R.id.fragmnet_container_map);
if (f != null) {
try {
getFragmentManager().beginTransaction().remove(f).commit();
} catch (IllegalStateException ise) {
Log.d("FragmentWithMap", "Already closed");
}
}
ViewGroup parentViewGroup = (ViewGroup) view.getParent();
if (parentViewGroup != null) {
parentViewGroup.removeAllViews();
}
}
public void onButtonPressed(Uri uri) {
if (mListener != null) {
mListener.onFragmentInteraction(uri);
}
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
mListener = (OnFragmentInteractionListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString()
+ " must implement OnFragmentInteractionListener");
}
}
#Override
public void onDetach() {
super.onDetach();
mListener = null;
}
public void showPlace(Place place) {
setPlace(place);
setUpMap();
}
public void setPlace(Place place) {
this.place = place;
}
public interface OnFragmentInteractionListener {
public void onFragmentInteraction(Uri uri);
}
private void setUpMapIfNeeded() {
// Do a null check
if (mMap == null) {
// Try to obtain the map from the SupportMapFragment.
Fragment mmm = getChildFragmentManager().findFragmentById(R.id.fragment_map2);
mMap = ((SupportMapFragment) mmm).getMap();
// Check if we were successful
if (mMap != null) {
setUpMap();
}
}
}
private void setUpMap() {
double lat = LAT;
double lng = LON;
String name = "You are here";
if (place != null) {
lat = place.getLat();
lng = place.getLng();
name = place.getName();
}
if (marker != null) {
marker.remove();
}
LatLng position = new LatLng(lat, lng);
MarkerOptions markerOptions = new MarkerOptions().
position(position).
title(name).
icon(BitmapDescriptorFactory.fromResource(userIcon)).
snippet("Your last recorded location");
marker = mMap.addMarker(markerOptions);
if (ActivityCompat.checkSelfPermission(getContext(), Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(getContext(), Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
return;
}
mMap.setMyLocationEnabled(true);
CameraUpdate cameraUpdate = CameraUpdateFactory.newLatLngZoom(position, 15);
mMap.animateCamera(cameraUpdate);
}
}
The XMLs:
activity_main.xml
"phone mode":
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/layout_single_fragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#android:color/darker_gray"
android:paddingBottom="16dp"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:paddingTop="16dp"
tools:context=".MainActivity">
<FrameLayout
android:id="#+id/fragmnet_container"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"></FrameLayout>
and "tablet mode"
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/layout_two_fragments"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#android:color/darker_gray"
android:paddingBottom="16dp"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:paddingTop="16dp"
tools:context=".MainActivity"
>
<FrameLayout
android:id="#+id/fragmnet_container"
android:layout_width="wrap_content"
android:layout_height="match_parent"></FrameLayout>
<FrameLayout
android:id="#+id/fragmnet_container_details"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1.31"></FrameLayout>
<FrameLayout
android:id="#+id/fragmnet_container_map"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="2"></FrameLayout>
I'd greatly appreciate any help you might offer...
Update:
The crashpoint is at the end of the mapfragment in the at the marker = mMap.addMarker(markerOptions); line. I guess I must not be handling the markers correctly... Still not clear why it works fine in single fragment mode, and not dual fragments.
You are trying to access UI elements in the onCreate() but , onCreate() is too early to call getView() and it will return null. Postpone the code that needs to touch the fragment's view hierarchy to onCreateView() or later in the fragment lifecycle. Since in fragment views can be created in onCreateView() method.
Try to include onActivityCreated() which calls when the fragment's activity has been created and this fragment view hierarchy instantiated.
Update: solved
The problem ended up being with the userIcon (which represents the cosmetic type of marker shown on the map). When the app first load, it for some reason returned 0 instead of null. Since it's merely a cosmetic feature I simply removed, and that solved the problem. Not the prettiest solution but it's the one I got, since time constraint prevent me from dedicated more time to this when more critical parts of the app still need tending; I hope it helps. I hope a more experienced programmer will likely be familiar enough with the marker system to offer alternative solutions/workarounds for those who wish to include custom markers.

Xamarin Forms - Highlight route for WinPhone 8.1 part

Since a long time, I'm trying to make work a polyline for crossplateform using.
I did it and it works well, I followed the Map Control tutorial in first, and then Highlight a Route on a Map tutorial.
I then update the code to make it reloads if a any changes comes, however, I'm getting an issue and I couldn't figure it out... It does works for Android & iOS.
polyline.Path = new Geopath(coordinates); throws Catastrophic failure (Exception from HRESULT: 0x8000FFFF (E_UNEXPECTED))
The problem is that my two others renderer (Android & iOS) works.. Maybe something isn't possible because I work with WinPhone8.1 unlike the tutorial, which is UWP.
public class CustomMapRenderer : MapRenderer
{
MapControl nativeMap;
CustomMap formsMap;
protected override void OnElementChanged(ElementChangedEventArgs<Map> e)
{
base.OnElementChanged(e);
if (e.OldElement != null)
{
nativeMap = Control as MapControl;
}
if (e.NewElement != null)
{
formsMap = (CustomMap)e.NewElement;
nativeMap = Control as MapControl;
UpdatePolyLine();
}
}
protected override void OnElementPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
if (this.Element == null || this.Control == null)
return;
if (e.PropertyName == CustomMap.RouteCoordinatesProperty.PropertyName)
{
UpdatePolyLine();
}
}
private void UpdatePolyLine()
{
if (nativeMap != null)
{
var coordinates = new List<BasicGeoposition>();
foreach (var position in formsMap.RouteCoordinates)
{
coordinates.Add(new BasicGeoposition() { Latitude = position.Latitude, Longitude = position.Longitude });
}
var polyline = new MapPolyline();
polyline.StrokeColor = Color.FromArgb(128, 255, 0, 0);
polyline.StrokeThickness = 5;
polyline.Path = new Geopath(coordinates);
nativeMap.MapElements.Add(polyline);
}
}
}
I also read that a key is needed, so maybe I doesn't use this key in a good way.. I tried with UWP Public Key and WinPhone8.X and earlier Key, but without success too..
Does someone has an idea? This part a really big problem in my app..
Thank in advance !
After a long time, I found why it didn't works...
If you're doing like me, if you do a HttpRequest to something as Google Direction API, then the result will comes after the first passage in the OnElementChanged().
Because formsMap.RouteCoordinates isn't null but empty, the Catastrophic failure (Exception from HRESULT: 0x8000FFFF (E_UNEXPECTED)) is thrown..
This is the good CustomMapRenderer for PolyLine use
using PROJECT;
using PROJECT.UWP;
using System.Collections.Generic;
using Windows.Devices.Geolocation;
using Windows.UI.Xaml.Controls.Maps;
using Xamarin.Forms.Maps;
using Xamarin.Forms.Maps.UWP;
using Xamarin.Forms.Platform.UWP;
[assembly: ExportRenderer(typeof(CustomMap), typeof(CustomMapRenderer))]
namespace PROJECT.UWP
{
public class CustomMapRenderer : MapRenderer
{
MapControl nativeMap;
CustomMap formsMap;
protected override void OnElementChanged(ElementChangedEventArgs<Map> e)
{
base.OnElementChanged(e);
if (e.OldElement != null)
{
nativeMap = Control as MapControl;
}
if (e.NewElement != null)
{
formsMap = (CustomMap)e.NewElement;
nativeMap = Control as MapControl;
UpdatePolyLine();
}
}
protected override void OnElementPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
if (this.Element == null || this.Control == null)
return;
if (e.PropertyName == CustomMap.RouteCoordinatesProperty.PropertyName)
{
UpdatePolyLine();
}
}
private void UpdatePolyLine()
{
if (formsMap != null && formsMap.RouteCoordinates.Count > 0)
{
List<BasicGeoposition> coordinates = new List<BasicGeoposition>();
foreach (var position in formsMap.RouteCoordinates)
{
coordinates.Add(new BasicGeoposition() { Latitude = position.Latitude, Longitude = position.Longitude });
}
Geopath path = new Geopath(coordinates);
MapPolyline polyline = new MapPolyline();
polyline.StrokeColor = Windows.UI.Color.FromArgb(128, 255, 0, 0);
polyline.StrokeThickness = 5;
polyline.Path = path;
nativeMap.MapElements.Add(polyline);
}
}
}
}

ReverseGeocodeQuery giving error

ReverseGeocodeQuery is giving error
1.in "GeoCoordinate(47.60887, -122.34094); " method must have a return type
2.in "reverseGeocode.GeoCoordinate line " reverseGeocode is a field but its used like a type..
ReverseGeocodeQuery reverseGeocode = new ReverseGeocodeQuery();
reverseGeocode.GeoCoordinate = new GeoCoordinate(47.60887, -122.34094);
reverseGeocode.QueryCompleted += reverseGeocode_QueryCompleted;
reverseGeocode.QueryAsync();
void reverseGeocode_QueryCompleted(objectsender,QueryCompletedEventArgs<IList<MapLocation>> e)
{
MapAddress geoAddress = e.Result[0].Information.Address;
}
i used namespace-- using Microsoft.Phone.Maps.Services;
how to rectify this errors..
GOT THE ANSWER
GeoCoordinateWatcher myLocationWatcher;
private GeoCoordinate MyCoordinate = null;
private async void GetCurrentCoordinate()
{
Geolocator geolocator = new Geolocator();
geolocator.DesiredAccuracy = PositionAccuracy.High;
try
{
Geoposition currentPosition = await geolocator.GetGeopositionAsync(TimeSpan.FromMinutes(1), TimeSpan.FromSeconds(10));
_accuracy = currentPosition.Coordinate.Accuracy;
MyCoordinate = new GeoCoordinate(currentPosition.Coordinate.Latitude, currentPosition.Coordinate.Longitude);
if (MyReverseGeocodeQuery == null || !MyReverseGeocodeQuery.IsBusy)
{
MyReverseGeocodeQuery = new ReverseGeocodeQuery();
MyReverseGeocodeQuery.GeoCoordinate = new GeoCoordinate(MyCoordinate.Latitude, MyCoordinate.Longitude);
LongitudeTextBlock.Text = MyCoordinate.Longitude.ToString();
LatitudeTextBlock.Text = MyCoordinate.Latitude.ToString();
MyReverseGeocodeQuery.QueryCompleted += ReverseGeocodeQuery_QueryCompleted;
MyReverseGeocodeQuery.QueryAsync();
}
}
catch (Exception ex)
{
// ...
}
}
public void ReverseGeocodeQuery_QueryCompleted(object sender, QueryCompletedEventArgs<IList<MapLocation>> e)
{
if (e.Error == null)
{
if (e.Result.Count > 0)
{
MapAddress address = e.Result[0].Information.Address;
labelResults.Text = "Current Location: " + address.City + ", " + address.State;
}
}
}
public void Button_Click(object sender, RoutedEventArgs e)
{
GetCurrentCoordinate();
}

Save/ load QuickAccessToolBar

I 'm using Microsoft.Windows.Controls.Ribbon, and i would like save and load QuickAccessToolBar.
How I Can find QuickAccessToolBar items, in ribbon control?
This is my idea to save ribbon QuickAccessToolBar
OnClosing application : Get QuickAccessToolBar items, and locaize on Ribbon items. And then serialize
OnLoad : Read serilize object, and add insert items QuickAccessToolBar
Finally i did it!
I'm based on WPF Ribbon Sample to save/load. It used datacontext to localize control on RibbonControl, and i didn't like, so i isued QuickAccessToolBarId to localize the control.
This is the solution:
- OnClosing Application:
I save QuickAccessToolBar, search items on ribbon control by QuickAccessToolBar, and save path. Note: When item is in application menufirst path is -1.A
- OnLoadApplication:
Load items , and seerch on ribbon control by path.
And this is the code:
RibbonHelper:
class RibbonHelper
{
Ribbon ribbon;
public RibbonHelper(Ribbon ribbon)
{
this.ribbon = ribbon;
}
string _qatFileName = "qat.xml";
internal void Save()
{
try
{
SaveQatItems();
}
catch { }
}
internal void Load()
{
try
{
LoadQatItems();
}
catch
{
}
}
#region Save Qat
private void SaveQatItems()
{
QatItemCollection qatItems = GetQatItemsToSave(ribbon.QuickAccessToolBar);
if (qatItems != null)
{
QatItemCollection remainingItems = new QatItemCollection();
remainingItems.AddRange(qatItems);
SaveQatItemsOfApplicationMenu(remainingItems);
SaveQatItemsOfTabs(remainingItems);
SaveQatItems(qatItems);
}
}
private void SaveQatItems(QatItemCollection qatItems)
{
XmlWriter xmlWriter = XmlWriter.Create(_qatFileName);
XamlWriter.Save(qatItems, xmlWriter);
xmlWriter.Close();
}
private void SaveQatItemsOfApplicationMenu(QatItemCollection remainingItems)
{
if (ribbon.ApplicationMenu != null)
{
if (remainingItems != null)
{
remainingItems.ForEach(qat =>
{
qat.ControlIndices.Add(-1);
});
for (int index = 0; index < ribbon.ApplicationMenu.Items.Count && remainingItems.Count > 0; index++)
{
SaveQatItemsAmongChildren(remainingItems, ribbon.ApplicationMenu.Items[index],index);
}
remainingItems.ForEach(qat =>
{
qat.ControlIndices.Clear();
});
}
}
}
private void SaveQatItemsOfTabs(QatItemCollection remainingItems)
{
if (ribbon.Items != null)
{
if (remainingItems != null)
{
for (int tabIndex = 0; tabIndex < ribbon.Items.Count && remainingItems.Count > 0; tabIndex++)
{
RibbonTab tab = ribbon.Items[tabIndex] as RibbonTab;
SaveQatItemsAmongChildren(remainingItems, tab, tabIndex);
}
}
}
}
private void SaveQatItemsAmongChildren(QatItemCollection remainingItems, object control, int controlIndex)
{
if (control == null)
{
return;
}
//Añaidmos el control index a los pendientes
remainingItems.ForEach(qat =>
{
qat.ControlIndices.Add(controlIndex);
});
SaveQatItemsAmongChildrenInner(remainingItems, control);
//Eliminamos el control index de los pendientes ya que no estan dentro de ese control
remainingItems.ForEach(qat =>
{
int last = qat.ControlIndices.Count - 1;
qat.ControlIndices.RemoveAt(last);
});
}
private void SaveQatItemsAmongChildrenInner(QatItemCollection remainingItems, object parent)
{
SaveQatItemsIfMatchesControl(remainingItems, parent);
if (remainingItems.Count == 0 || IsLeaf(parent))
{
return;
}
int childIndex = 0;
DependencyObject dependencyObject = parent as DependencyObject;
if (dependencyObject != null)
{
IEnumerable children = LogicalTreeHelper.GetChildren(dependencyObject);
foreach (object child in children)
{
SaveQatItemsAmongChildren(remainingItems, child, childIndex);
childIndex++;
}
}
if (childIndex != 0)
{
return;
}
// if we failed to get any logical children, enumerate the visual ones
Visual visual = parent as Visual;
if (visual == null)
{
return;
}
for (childIndex = 0; childIndex < VisualTreeHelper.GetChildrenCount(visual); childIndex++)
{
Visual child = VisualTreeHelper.GetChild(visual, childIndex) as Visual;
SaveQatItemsAmongChildren(remainingItems, child, childIndex);
}
}
private bool IsLeaf(object element)
{
if ((element is RibbonButton) ||
(element is RibbonToggleButton) ||
(element is RibbonRadioButton) ||
(element is RibbonCheckBox) ||
(element is RibbonTextBox) ||
(element is RibbonSeparator))
{
return true;
}
RibbonMenuItem menuItem = element as RibbonMenuItem;
if (menuItem != null &&
menuItem.Items.Count == 0)
{
return true;
}
return false;
}
private bool SaveQatItemsIfMatchesControl(QatItemCollection remainingItems, object control)
{
bool matched = false;
FrameworkElement element = control as FrameworkElement;
if (element != null)
{
object getQuickAccessToolBarId = RibbonControlService.GetQuickAccessToolBarId(element);
if (getQuickAccessToolBarId != null)
{
int remove = remainingItems.RemoveAll(qat => qat.QuickAccessToolBarIdHashCode == getQuickAccessToolBarId.GetHashCode());
matched = remove > 0;
}
}
return matched;
}
private QatItemCollection GetQatItemsToSave(RibbonQuickAccessToolBar qat)
{
QatItemCollection qatItems = new QatItemCollection();
if (qat != null && qat.Items != null && qat.Items.Count > 0)
{
foreach (var item in qat.Items)
{
FrameworkElement element = item as FrameworkElement;
if (element != null)
{
object getQuickAccessToolBarId = RibbonControlService.GetQuickAccessToolBarId(element);
if (getQuickAccessToolBarId != null)
{
QatItem qatItem = new QatItem(getQuickAccessToolBarId.GetHashCode());
qatItems.Add(qatItem);
}
}
}
}
return qatItems;
}
#endregion
#region load qat
private void LoadQatItems()
{
if (ribbon.QuickAccessToolBar == null)
{
ribbon.QuickAccessToolBar = new RibbonQuickAccessToolBar();
}
QatItemCollection qatItems = GetQatItemsToLoad();
if ((qatItems != null) && (qatItems.Count > 0))
{
SearchInApplicationMenu(qatItems);
SearchInTabs(qatItems);
qatItems.Where(qat => qat.Owner != null).ToList().ForEach(qat =>
{
if (RibbonCommands.AddToQuickAccessToolBarCommand.CanExecute(null, qat.Owner))
{
RibbonCommands.AddToQuickAccessToolBarCommand.Execute(null, qat.Owner);
}
});
}
}
private void SearchInApplicationMenu(QatItemCollection qatItems)
{
if (qatItems != null)
{
int remainingItemsCount = qatItems.Count(qat=>qat.Owner==null);
QatItemCollection matchedItems = new QatItemCollection();
for (int index = 0; index < ribbon.ApplicationMenu.Items.Count && remainingItemsCount > 0; index++)
{
matchedItems.Clear();
matchedItems.AddRange(qatItems.Where(qat => qat.ControlIndices[0] == -1)); //-1 is applicationMenu
//remove -1
matchedItems.ForEach(qat =>
{
qat.ControlIndices.RemoveAt(0);
}
);
object item = ribbon.ApplicationMenu.Items[index];
if (item != null)
{
if (!IsLeaf(item))
{
LoadQatItemsAmongChildren(matchedItems, 0, index, item, ref remainingItemsCount);
}
else
{
LoadQatItemIfMatchesControl(matchedItems, new QatItemCollection(), 0, index, item, ref remainingItemsCount);
}
}
//Add -1
matchedItems.ForEach(qat =>
{
qat.ControlIndices.Insert(0, -1);
});
}
}
}
private void SearchInTabs(QatItemCollection qatItems)
{
int remainingItemsCount = qatItems.Count(qat => qat.Owner == null);
QatItemCollection matchedItems = new QatItemCollection();
for (int tabIndex = 0; tabIndex < ribbon.Items.Count && remainingItemsCount > 0; tabIndex++)
{
matchedItems.Clear();
matchedItems.AddRange(qatItems.Where(qat => qat.ControlIndices[0] == tabIndex));
RibbonTab tab = ribbon.Items[tabIndex] as RibbonTab;
if (tab != null)
{
LoadQatItemsAmongChildren(matchedItems, 0, tabIndex, tab, ref remainingItemsCount);
}
}
}
private void LoadQatItemsAmongChildren(
QatItemCollection previouslyMatchedItems,
int matchLevel,
int controlIndex,
object parent,
ref int remainingItemsCount)
{
if (previouslyMatchedItems.Count == 0)
{
return;
}
if (IsLeaf(parent))
{
return;
}
int childIndex = 0;
DependencyObject dependencyObject = parent as DependencyObject;
if (dependencyObject != null)
{
IEnumerable children = LogicalTreeHelper.GetChildren(dependencyObject);
foreach (object child in children)
{
if (remainingItemsCount == 0)
{
break;
}
QatItemCollection matchedItems = new QatItemCollection();
LoadQatItemIfMatchesControl(previouslyMatchedItems, matchedItems, matchLevel + 1, childIndex, child, ref remainingItemsCount);
LoadQatItemsAmongChildren(matchedItems, matchLevel + 1, childIndex, child, ref remainingItemsCount);
childIndex++;
}
}
if (childIndex != 0)
{
return;
}
// if we failed to get any logical children, enumerate the visual ones
Visual visual = parent as Visual;
if (visual == null)
{
return;
}
for (childIndex = 0; childIndex < VisualTreeHelper.GetChildrenCount(visual); childIndex++)
{
if (remainingItemsCount == 0)
{
break;
}
Visual child = VisualTreeHelper.GetChild(visual, childIndex) as Visual;
QatItemCollection matchedItems = new QatItemCollection();
LoadQatItemIfMatchesControl(previouslyMatchedItems, matchedItems, matchLevel + 1, childIndex, child, ref remainingItemsCount);
LoadQatItemsAmongChildren(matchedItems, matchLevel + 1, childIndex, child, ref remainingItemsCount);
}
}
private void LoadQatItemIfMatchesControl(
QatItemCollection previouslyMatchedItems,
QatItemCollection matchedItems,
int matchLevel,
int controlIndex,
object control,
ref int remainingItemsCount)
{
for (int qatIndex = 0; qatIndex < previouslyMatchedItems.Count; qatIndex++)
{
QatItem qatItem = previouslyMatchedItems[qatIndex];
if (qatItem.ControlIndices[matchLevel] == controlIndex)
{
if (qatItem.ControlIndices.Count == matchLevel + 1)
{
qatItem.Owner = control as Control; ;
remainingItemsCount--;
}
else
{
matchedItems.Add(qatItem);
}
}
}
}
private QatItemCollection GetQatItemsToLoad()
{
try
{
if (File.Exists(_qatFileName))
{
using (XmlReader xmlReader = XmlReader.Create(_qatFileName))
{
QatItemCollection qatItems = (QatItemCollection)XamlReader.Load(xmlReader);
xmlReader.Close();
return qatItems;
}
}
}
catch
{
//Do nothing, return null;
}
return null;
}
#endregion
}
Classes to serialize:
public class QatItem {
public QatItem()
{
}
public QatItem(int qatbIdHashCode)
{
QuickAccessToolBarIdHashCode = qatbIdHashCode;
}
public Int32Collection ControlIndices
{
get
{
if (_controlIndices == null)
{
_controlIndices = new Int32Collection();
}
return _controlIndices;
}
set
{
_controlIndices = value;
}
}
Int32Collection _controlIndices;
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public int QuickAccessToolBarIdHashCode { get; set; }
//Is only for load
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public Control Owner { get; set; }
}
public class QatItemCollection : List<QatItem>
{
}
And this is the code to save/load from window
RibbonHelper helper;
protected override void OnClosing(CancelEventArgs e)
{
helper.Save();
base.OnClosing(e);
}
private void RibbonWindow_Loaded(object sender, RoutedEventArgs e)
{
helper = new RibbonHelper(ribbon);
helper.Load();
}