MVVMCross Manual Bind in MvxFragment with MvxViewPagerFragmentAdapter - xamarin

I'm using an implementation of Cheesebaron's MvxViewPagerFragmentAdapter example that can be found here http://blog.ostebaronen.dk/2013/07/fragments-and-viewpager-with-mvx.html
var fragments = new List<MvxViewPagerFragmentAdapter.FragmentInfo>
{
new MvxViewPagerFragmentAdapter.FragmentInfo
{
FragmentType = typeof(JobDetailsView),
Title = "Detail",
ViewModel = ViewModel
},
new MvxViewPagerFragmentAdapter.FragmentInfo
{
FragmentType = typeof(JobFeaturesView),
Title = "Info",
ViewModel = ViewModel
}
}
Within my JobDetailsView's OnCreateView, I can inflate my layout specified using BindingInflate and any bindings that I have specified in the XML layout work correctly.
I now have a requirement to bind some elements programmatically, which i have tried to do using CreateBindingSet, but the bindings do not work. I've tried a simple text property and a button click. Both of these work when specified in the XML.
public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Android.OS.Bundle savedInstanceState)
{
var ignored = base.OnCreateView(inflater, container, savedInstanceState);
this.EnsureBindingContextIsSet(savedInstanceState);
_view = this.BindingInflate(Resource.Layout.jobview_details, null);//jobview_withtabs_details
var signatureCard = _view.FindViewById<CardFeature>(Resource.Id.signature_cardview);
signatureCard.FindViewById<TextView>(Resource.Id.tv_basecard_header_title).Text = "Signature";
var signatureButton = signatureCard.FindViewById<Button>(Resource.Id.btn_basecard_footer).Text = "Capture";
var set = this.CreateBindingSet<JobDetailsView, JobWithTabsViewModel>();
set.Bind(signatureButton).To(vm => vm.SignatureClickCommand);
set.Apply();
return _view;
}
in my output window, i can see this, but i don't know what to do to fix it:
04-16 17:40:43.721 I/mono-stdout(27727): MvxBind:Error: 23.79 Empty binding target passed to MvxTargetBindingFactoryRegistry
MvxBind:Warning: 23.80 Failed to create target binding for binding for SignatureClickCommand
[0:] MvxBind:Warning: 23.80 Failed to create target binding for binding for SignatureClickCommand
04-16 17:40:43.731 I/mono-stdout(27727): MvxBind:Warning: 23.80 Failed to create target binding for binding for SignatureClickCommand
Anyone have any ideas?
UPDATE
In typical fashion, left it for an hour and realised my mistake.
I was being lazy by typing:
var signatureButton = signatureCard.FindViewById<Button>(Resource.Id.btn_basecard_footer).Text = "Capture"
Which was confusing the binding. Switched to:
var signatureButton = signatureCard.FindViewById<Button>(Resource.Id.btn_basecard_footer);
signatureButton.Text = "Capture";
And it works perfectly

An updated example using TabView and ViewPager is available here: https://github.com/MvvmCross/MvvmCross-AndroidSupport/tree/master/Samples
It uses the latest stuff from the Android design libraries.

Related

Xamarin.Forms App return data to calling App

So, either I am asking incorrectly, or it isn't possible, let's see which...
If my app (Xamarin.Forms) is launched from another app, in order to get a url from my app, how do I return that data to the calling app? I wrongly assumed SetResult and Finish, I also wrongly assumed StartActivityForResult, but there has to be a way to do this. I know how to get data INTO my app from another app, but not the same in return.
POSSIBLE PARTIAL SOLUTION -- UPDATE, FAILS
So I have to setup an interface in my PCL, and call the method from the listview item selected handler, in the Android app I can then do this:
Intent result = new Intent("com.example.RESULT_ACTION", Uri.parse("content://result_url"));
setResult(Activity.RESULT_OK, result);
finish();
(source: https://developer.android.com/training/basics/intents/filters.html)
Is this looking right, and how would I implement the same thing on iOS?
END
I deleted my previous question because I couldn't explain the problem clearly, so here goes.
I have a Xamarin Forms app, I want to use a section of this app as a gallery. Currently I have images displayed in a list, and I have an Intent filter set that launches this page when you select the app as the source for an image (such as upload image on Facebook).
My issue is that I don't know how to return the data (the selected image) back to the app / webpage that made the request. In android I understand that you would use StartActivityForResult and OnActivityResult to handle this, but I am using Xamarin Forms (Android, iOS, UWP) and can't really find a solution that could be used cross-platform.
Just a link to documentation that covers this would be great, but if you have an example then even better.
Thanks
EDIT
Here is the code used to launch the app, I am interested in getting data back from the Intent.ActionPick after the user has selected an image from a ListView, which is in a ContentPage in the PCL.
[Activity(Label = "", Icon = "#drawable/icon", Theme = "#style/DefaultTheme", MainLauncher = true, LaunchMode = LaunchMode.SingleTop,
ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
[IntentFilter(new[] { Intent.ActionSend }, Categories = new[] { Intent.CategoryDefault }, DataMimeType = #"*/*")]
[IntentFilter(new[] { Intent.ActionView, Intent.ActionPick, Intent.ActionGetContent }, Categories = new[] { Intent.CategoryDefault, Intent.CategoryOpenable }, DataMimeType = #"*/*")]
public class MainActivity : FormsAppCompatActivity
{
protected override void OnCreate(Bundle bundle)
{
try
{
base.OnCreate(bundle);
CurrentPlatform.Init();
Xamarin.Forms.Forms.Init(this, bundle);
App _app = new App();
LoadApplication(_app);
if (Intent.Action == Intent.ActionSend)
{
var image = Intent.ClipData.GetItemAt(0);
var imageStream = ContentResolver.OpenInputStream(image.Uri);
var memOfImage = new System.IO.MemoryStream();
imageStream.CopyTo(memOfImage);
_app.UploadManager(memOfImage.ToArray()); //This allows me to upload images to my app
}
else if (Intent.Action == Intent.ActionPick)
{
_app.SelectManager(); //here is where I need help
}
else
{
_app.AuthManager(); //this is the default route
}
}
catch (Exception e)
{
}
}
It seems you cannot use remote URI to provide to calling app. Some posts I checked suggest to store the file locally and provide it's path to calling app. To avoid memory leak with many files stored I suggest to use the same file name then you will have only one file at any moment.
One more note. I tested this solution in facebook. Skype doesn't seem to accept that and, again, the posts I checked saying that Skype doesn't handle Intent properly (not sure what that means).
Now to solution. In main activity for example in OnCreate method add the follow.
ReturnImagePage is the name of my page class where I select an image
Xamarin.Forms.MessagingCenter.Subscribe<ReturnImagePage, string>(this, "imageUri", (sender, requestedUri) => {
Intent share = new Intent();
string uri = "file://" + requestedUri;
share.SetData(Android.Net.Uri.Parse(uri));
// OR
//Android.Net.Uri uri = Android.Net.Uri.Parse(requestedUri);
//Intent share = new Intent(Intent.ActionSend);
//share.PutExtra(Intent.ExtraStream, uri);
//share.SetType("image/*");
//share.AddFlags(ActivityFlags.GrantReadUriPermission);
SetResult(Result.Ok, share);
Finish();
});
Above will listen for the message when the image is selected.
Then in XFroms code when image is selected dowload it, store it, get path and send to Activity using it's path. Below is my test path
MessagingCenter.Send<ReturnImagePage, string>(this, "imageUri", "/storage/emulated/0/Android/data/ButtonRendererDemo.Droid/files/Pictures/temp/IMG_20170207_174559_21.jpg");
You can use static public class to save and access results like:
public static class StaticClass
{
public static int Result;
}

NullPointerException on set label text

Whenever I try to set the text of a label from a different ViewController on a storyboard, i get a NullPointerException:
System.NullReferenceException: Object reference not set to an instance of an object in the line UIApplication.Main(args, null, "AppDelegate");
Both of the view controllers are using the same class.
This is my code:
async partial void LoginBtn_TouchUpInside(UIButton sender)
{
loadingIndicator.StartAnimating();
var uname = username.Text;
var pwd = password.Text;
Uri loginUri = new Uri($"http://<loginapi>:8080/api/login?user={uname}&pwd={pwd}");
WebClient c = new WebClient();
string[] userinfo = parseJsonToArray(await c.DownloadStringTaskAsync(loginUri));
welcomeLabel.Text = "Welcome, " + userinfo[0]; //index 0 of userinfo contains the user's full name.
loadingIndicator.StopAnimating();
PerformSegue("loggedInSegue", this);
}
I have verified that it is getting the correct information by logging it to the console, and everything else works perfectly fine if I comment out the welcomeLabel.Text part.
You can enable all exception in your Visual Studio or Xamarin Studio so that you can break at line contain the null reference. Check this to enable all exceptions
http://www.stefandevo.com/2015/12/20/xamarin-studio-tip-break-on-all-exceptions/

Xamarin.Mac - How to highlight the selected text in a PDF file

I'm actualy trying to add a markup annotation in a PDF with PDFKit, in Xamarin.Mac, so for OS X.
So my goal is to highlight permanently, as an annotation, a selected text in the PDF File, and save it to retrieve it when I open the file later.
The thing is, I can get the current selection and store it into a variable :
PdfSelection currentSelection = m_aPdfView.CurrentSelection;
And I can create an object PdfAnnotationMarkup :
//Create the markup annotation
var annot = new PdfAnnotationMarkup();
//add characteristics to the annotation
annot.Contents = currentSelectionText;
annot.MarkupType = PdfMarkupType.Highlight;
annot.Color = NSColor.Yellow;
annot.ShouldDisplay = true;
But I can't find, even though I checked a lot of different documentations, how to link the two of them.
There is no method giving the location of the currentSelection, or any hint to go in that direction.
Would anyone know of a way to make this possible ?
PS: I found that the subclasses of PDFAnnotation are deprecated on the Apple Developer Website , but not on the Xamarin Website, is there any way of knowing if both of them are related of entirely different ?
Thanks in advance for your help
EDIT : Here is the code I got and works perfectly. Thanks to svn's answers
//Get the current selection on the PDF file opened in the PdfView
PdfSelection currentSelection = m_aPdfView.CurrentSelection;
//Check if there is an actual selection right now
if (currentSelection != null)
{
currentSelection.GetBoundsForPage(currentSelection.Pages[0]);
//Create the markup annotation
var annot = new PdfAnnotationMarkup();
//add characteristics to the annotation
annot.Contents = "Test";
annot.MarkupType = PdfMarkupType.Highlight;
annot.Color = NSColor.Yellow;
annot.ShouldDisplay = true;
annot.ShouldPrint = true;
annot.UserName = "MyName";
//getting the current page
PdfPage currentPage = currentSelection.Pages[0];
//getting the bounds from the current selection and adding it to the annotation
var locationRect = currentSelection.GetBoundsForPage(currentPage);
getValuLabel.StringValue = locationRect.ToString();
//converting the CGRect object into CGPoints
CoreGraphics.CGPoint upperLeft = locationRect.Location;
CoreGraphics.CGPoint lowerLeft = new CoreGraphics.CGPoint(locationRect.X, (locationRect.Y + locationRect.Height));
CoreGraphics.CGPoint upperRight = new CoreGraphics.CGPoint((locationRect.X + locationRect.Width), locationRect.Y);
CoreGraphics.CGPoint lowerRight = new CoreGraphics.CGPoint((locationRect.X + locationRect.Width), (locationRect.Y + locationRect.Height));
//adding the CGPoints to a NSMutableArray
NSMutableArray pointsArray = new NSMutableArray();
pointsArray.Add(NSValue.FromCGPoint(lowerLeft));
pointsArray.Add(NSValue.FromCGPoint(lowerRight));
pointsArray.Add(NSValue.FromCGPoint(upperLeft));
pointsArray.Add(NSValue.FromCGPoint(upperRight));
//setting the quadrilateralPoints
annot.WeakQuadrilateralPoints = pointsArray;
//add the annotation to the PDF file current page
currentPage.AddAnnotation(annot);
//Tell the PdfView to update the display
m_aPdfView.NeedsDisplay = true;
A selection can span multiple pages. To get the location of a selection use:
var locationRect = currentSelection.GetBoundsForPage(currentSelection.Pages[0]);
You should be able to instantiate PdfAnnotationMarkup with bounds but the xamarin implementation does not expose that constuctor. But is does expose a bounds property
var annot = new PdfAnnotationMarkup();
annot.bounds = locationRect;
I have not tested this.

Geofence is not being triggered in the background in windows phone 8.1

I'm trying to implement geofencing in Windows phone 8.1. First I wanted to create a sample Project to understand how it Works, but i couldnt make it works. What I'm trying to achieve is basically, I'll set the coordinates and close the app by pressing back button and it will trigger a toast notification when the phone is in the area of interest.
I've created a blank Windows phone(silverlight) 8.1 Project(geofence_test_01) and added a Windows RT Component Project(BackgroundTask) into the same solution. Added a reference for BackgroundTask in the geofence_test_01 Project.
ID_CAP_LOCATION is enabled in the app manifest.
MainPage.xaml has only one button to start geofencing.
<Button Name="btnStart" Content="Start" Click="btnStart_Click"/>
In btnSave_Click, I call a method which creates the geofence and registers the background task.
private void btnStart_Click(object sender, RoutedEventArgs e)
{
Init_BackgroundGeofence();
registerBackgroundTask();
}
private async Task Init_BackgroundGeofence()
{
//----------------- Crating Geofence ---------------
var geofenceMonitor = GeofenceMonitor.Current;
var geoId = "building9";
var positionBuilding9 = new BasicGeoposition()
{
Latitude = 47.6397,
Longitude = -122.1289
};
var geofence = new Geofence(geoId, new Geocircle(positionBuilding9, 100),
MonitoredGeofenceStates.Entered | MonitoredGeofenceStates.Exited,
false, TimeSpan.FromSeconds(10));
geofenceMonitor.Geofences.Add(geofence);
}
private async Task registerBackgroundTask()
{
//----------------- Register Background Task ---------------
var backgroundAccessStatus =
await BackgroundExecutionManager.RequestAccessAsync();
var geofenceTaskBuilder = new BackgroundTaskBuilder
{
Name = "GeofenceBackgroundTask",
TaskEntryPoint = "BackgroundTask.GeofenceBackgroundTask"
};
var trigger = new LocationTrigger(LocationTriggerType.Geofence);
geofenceTaskBuilder.SetTrigger(trigger);
var geofenceTask = geofenceTaskBuilder.Register();
}
And finally, in BackgroundTask, I've the following code:
namespace BackgroundTask
{
public sealed class GeofenceBackGroundTask : IBackgroundTask
{
public void Run(IBackgroundTaskInstance taskInstance)
{
var geofenceMonitor = GeofenceMonitor.Current;
var geoReports = geofenceMonitor.ReadReports();
var geoId = "building9";
foreach (var geofenceStateChangeReport in geoReports)
{
var id = geofenceStateChangeReport.Geofence.Id;
var newState = geofenceStateChangeReport.NewState;
if (id == geoId && newState == GeofenceState.Entered)
{
//------ Call NotifyUser method when Entered -------
notifyUser();
}
}
}
private void notifyUser()
{
var toastTemplate = ToastTemplateType.ToastText02;
var toastXML = ToastNotificationManager.GetTemplateContent(toastTemplate);
var textElements = toastXML.GetElementsByTagName("text");
textElements[0].AppendChild(toastXML.CreateTextNode("You are in!"));
var toast = new ToastNotification(toastXML);
ToastNotificationManager.CreateToastNotifier().Show(toast);
}
}
}
I get no error when building and deploying this in the emulator. I set a breakpoint in the backgroundTask but I've not seen that part of code is called yet. It never hits the breakpoint. I test it by using Additional Tools of the emulator, in Location tab, by clicking somewhere in my geofence area on the map, waiting for a while, but it never hits the breakpoint. Hope somebody can tell me what i am missing here...
I've checked these following links to build this application:
http://www.jayway.com/2014/04/22/windows-phone-8-1-for-developers-geolocation-and-geofencing/
Geofence in the Background Windows Phone 8.1 (WinRT)
Toast notification & Geofence Windows Phone 8.1
http://java.dzone.com/articles/geofencing-windows-phone-81
Thanks
You can download the project here:
https://drive.google.com/file/d/0B8Q_biJCWl4-QndYczR0cjNhNlE/view?usp=sharing
---- Some clues
Thanks to Romasz, I've checked the Lifecycle events and i see "no background tasks" even after registerBackgroundTask() is executed.... Apparently there is something wrong/missing in registerBackgroundTask() method.
I've tried to build my sample (it was easier for me to build a new one) basing on your code and it seems to be working. You can take a look at it at my GitHub.
There are couple of things that may have gone wrong in your case:
remember to add capabilities in WMAppManifest file (IS_CAP_LOCATION) and Package.appxmanifest (Location)
check the names (of namespaces, classes and so on) in BackgroundTask
check if your BackgroundTask project is Windows Runtime Componenet and is added to your main project as a reference
I know you have done some of this things already, but take a look at my sample, try to run it and maybe try to build your own from the very beginning.
Did you add your background task in the Package.appxmanifest under Declarations with the correct supported task types (Namely Location)?

Send bitmap parameter to another xaml page

In Windows Phone 8.1 , i have a ListView. My list is populated with an ObservableColection of Pictures. In class Pictures i have pictureName , and bitmapImage.
In ListView_Item_Click , i want to click a Picture and send it to another xaml page.
BitmapImage img = new BitmapImage();
img = ((Picture)e.ClickedItem).Image;//imi selectez imaginea care doresc!!
var image = new Image();
image.Source = img;
Frame.Navigate(typeof(Page2), image); in mainpage.xaml.cs
I wouldn't pass BitmapImage as a parameter of Frame.Navigate - it's not serializable and there will be a problem with SuspensionManager or Resuming/Suspending events.
The solution depends on your images - where to they come from - if it's a file, then you can just pass a path to that file and then in OnNavigated (for example), set the ImageSource from file.
Other method may be to set BitmapImage in target page, before it's navigated to - for example use static property:
public class TargetPage : Page, INotifyPropertyChanged
{
private static BitmapImage bmpImage;
public static BitmapImage BmpImage
{
get { return bmpImage; }
set { bmpImage = value; RaisePropertyChanged("BmpImage"); }
}
// rest of the code
Then you can just set the image before navigating:
TargetPage.BmpImage = img;
Frame.Navigate(typeof(TargetPage));
Also you should remember about Suspending and Resuming events and the case when your app is being terminated while it's Suspended. In every case you should somehow remember the source of the image - using SuspensionManager, PageState, Settings or other method.

Resources