I'm creating a Xamarin.Forms application and I'm trying to implement an AIML bot based on this tutorial: https://www.effacestudios.com/how-to-create-artificial-intelligence-chatbot/. I've added all the references and I've added a config and aiml folder into my directory. This is the code for when a button is clicked:
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
}
private void Button_Clicked(object sender, EventArgs e)
{
string settingsPath = Path.Combine(Environment.CurrentDirectory, Path.Combine("config", "Settings.xml"));
string otherPath = #"C:/Users/PAVILION/Desktop/AimlTest/AimlTest/AimlTest/bin/Debug/netstandard2.0/config/Settings.xml";
Bot AI = new Bot();
AI.loadSettings(otherPath);
AI.loadAIMLFromFiles();
AI.isAcceptingUserInput = false;
User myuser = new User("User1", AI);
AI.isAcceptingUserInput = true;
Request r = new Request(UserEntry.Text, myuser, AI);
Result res = AI.Chat(r);
BotEntry.Text = "Tutorial Bot: " + res.Output;
}
}
Any time I input text into the Entry and tap the button I get an Unable to find specified file on the loadSettings();. I believe the function is looking for a Settings.xml and even though I've directed it to the exact file it still cannot be found. Any help is appreciated.
You need to decompile aiml dll and then change loadsetting path to constant environment.specialfolder.loadapplication.
make sure you have placed your all required file there first.
Related
I'm aware this question has been asked already - but none provided a resolution.
I have read these links:
Xamarin Forum, Stack Overflow Q and some others.
I have a relatively simple project at the moment and I keep getting the error "The name 'Resource' does not exist in the current context"
I can restart the project & it will work and "resource" is underlined in red and I can still debug the project.
Then after a few tries it goes and complains that it's not in the current context.
I did not make any changes to the project - I have come back to it now from a while ago.
So I'm going to guess that updates to VS 2015 have broken it.
My Code example:
using System;
using Android.App;
using Android.Content;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Android.OS;
using Android.Views.InputMethods;
using Android.Graphics.Drawables;
using Android.Graphics;
namespace Designer
{
[Activity(Label = "Designer", MainLauncher = true)]
public class MainActivity : Activity
{
// Global Varialble
Button butSignIn;
EditText tbxUsername;
TextView txtErrorMsg;
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
// Set our view from the "main" layout resource
SetContentView(Resource.Layout.Main);
butSignIn = FindViewById<Button>(Resource.Id.butSignIn);
butSignIn.Click += ButSignIn_Click;
tbxUsername = FindViewById<EditText>(Resource.Id.txtUsername);
txtErrorMsg = FindViewById<TextView>(Resource.Id.txtErrorMessage);
ActionBar.SetDisplayShowTitleEnabled(false);
ColorDrawable colorDrawable = new ColorDrawable(Color.ParseColor("#ff70bc1e"));
ActionBar.SetBackgroundDrawable(colorDrawable);
}
private void ButSignIn_Click(object sender, System.EventArgs e)
{
if (tbxUsername.Text == "Azmodan")
{
Intent intent = new Intent(this, typeof(MenuActivity));
this.StartActivity(intent);
this.Finish(); // this will close the activity and will close app if we try go back
}
else
{
txtErrorMsg.Visibility = ViewStates.Visible;
txtErrorMsg.Text = "inccorect login details, please try again";
}
}
}
}
Any help would be appreciated.
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;
}
I created a class that connected to the API to retrieve the required data using httpclient. That file was called in the code behind file of the view and worked perfectly. Than I decided to implement the MVVM approach. As a result, I moved the code that initialized the rest service class to the view-model.
After doing that, i stopped getting the data. To investigate, I stated the the debugging session with the breakpoint placed at the line where i initialize the rest service class. Than i executed that line. By doing that, I found out that a huge android mono exception is thrown and the debugging session if stopped. The app exits the debugging session.
This has happened for the first time since i stated developing my app in Xamarin Forms. I have no idea about why it is breaking like that. Your help will be greatly appreciated.
This is the code that was working properly.
In the view code behind file
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class SubtaskPage : ContentPage
{
protected override void OnAppearing()
{
base.OnAppearing();
PopulateSubtaskData();
}
private async void PopulateSubtaskData()
{
lstSubtasks.IsRefreshing = true;
try
{
RestService rs = new RestService();
SResponse = await rs.GetSubtasksAsync(Convert.ToInt32(Application.Current.Properties["UserId"]));
if (SResponse.Status == 1)
{
lstSubtasks.ItemsSource = SResponse.Subtasks;
}
else
{
await DisplayAlert("Error", SResponse.Message, "Ok");
}
}
catch (Exception E)
{
Debug.WriteLine(#"GetSubtasksAsync -> ERROR {0}", E.Message);
}
lstSubtasks.IsRefreshing = false;
}
}
The rest service class is as follows
This class is in a separate folder named "Services". ip and url have been changed for security reason.
class RestService
{
HttpClient client;
public List<Ticket> Tickets { get; private set; }
string Server1 = "server ip";
string Server2 = "server ip";
public RestService()
{
client = new HttpClient();
client.MaxResponseContentBufferSize = 256000;
}
public async Task<SubtasksResponse> GetSubtasksAsync(int UserId)
{
SubtasksResponse SubtaskResponse = new SubtasksResponse();
string ApiUrl = "URL";
string Url = "";
HttpResponseMessage response;
if (CrossConnectivity.Current.IsConnected)
{
Url = await GetActiveServerAsync();
if (Url != "")
{
var uri = string.Format(Url + ApiUrl, UserId);
try
{
response = await client.GetAsync(uri);
if (response.IsSuccessStatusCode)
{
var content = await response.Content.ReadAsStringAsync();
SubtaskResponse.Subtasks = JsonConvert.DeserializeObject<List<Ticket>>(content);
SubtaskResponse.Status = 1;
}
else
{
SubtaskResponse.Subtasks = null;
SubtaskResponse.Status = 0;
SubtaskResponse.Message = "Attempt to fetch data from server was unsuccessful. Please try again";
}
}
catch (Exception E)
{
SubtaskResponse.Subtasks = null;
SubtaskResponse.Status = 0;
SubtaskResponse.Message = "Error occured while fetching data from the server. Please try again";
}
}
else
{
SubtaskResponse.Subtasks = null;
SubtaskResponse.Status = 0;
SubtaskResponse.Message = "Remote Server Not Responding! Please try again later";
}
}
else
{
SubtaskResponse.Subtasks = null;
SubtaskResponse.Status = 0;
SubtaskResponse.Message = "No Network Connection Found! Please connect to a network and try again";
}
return SubtaskResponse;
}
}
}
This was working fine until I added the view model into the mix.
This is how I am calling the function in the view model.
async Task<SubtasksResponse> PopulateSubtaskList()
{
RestService rs = new RestService();
IsBusy = true;
_subtaskList = await rs.GetSubtasksAsync(Convert.ToInt32(Application.Current.Properties["UserId"]));
IsBusy = false;
return _subtaskList;
}
"RestService rs = new RestService();" this is the line where the code breaks.
Here is the image of the exception that occurs when the code breaks.
Hope you get the clear picture of the situation. Please let me know if additional information is required.
Thanks
Don't do this. If you want to call rest from a mvvm Xamarin Forms app I can advice Refit. All the difficult work is already done for you and abstracted away. With a few lines of code you are up and running.
BTW the error message you are showing probably has nothing to do with your code but is a bug in a recent Xamarin version. See here: https://bugzilla.xamarin.com/show_bug.cgi?id=56787
Found the answer on this page (https://releases.xamarin.com/common-issues-in-the-xamarin-15-2-2-release-being-tracked-by-the-xamarin-team/).
The solution is as follows
Download the missing Mono.Posix file and unzip the archive.
Right-click the Mono.Posix.dll file in Explorer and select Properties.
Check the Digital Signatures tab to ensure the file shows a valid Xamarin Inc. signature.
At the bottom of the General tab, if an Unblock checkbox appears, enable it and select OK. (This checkbox appears depending on how the file was downloaded.)
For Visual Studio 2017, copy the Mono.Posix.dll file into the “Xamarin.VisualStudio” extension directory. For example, for a default installation of the Enterprise edition, copy the file into:
C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\Common7\IDE\Extensions\Xamarin.VisualStudio
For Visual Studio 2015, copy the file into the “Xamarin\Xamarin” extension directory:
C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\IDE\Extensions\Xamarin\Xamarin\
Quit and restart Visual Studio.
For more detail, visit the link given above.
I am developing a Xamarin Forms application which is basically a WebView where the user have access to some files which is supposed the user have to be able to download.
To achieve this in Android, I have this CustomRenderer for the WebView in the Android project, basically I get the cookies (files are under authentication) to send them to the DownloadManager:
public class CustomWebViewRenderer : WebViewRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.WebView> e)
{
base.OnElementChanged(e);
if (e.NewElement != null)
{
var customWebView = Element as CustomWebView;
Control.Settings.AllowContentAccess = true;
Control.Settings.AllowUniversalAccessFromFileURLs = true;
Control.Settings.DomStorageEnabled = true;
Control.Settings.JavaScriptEnabled = true;
Control.Download += OnWebViewDownload;
}
}
private void OnWebViewDownload(object sender, DownloadEventArgs e)
{
var source = AUri.Parse(e.Url);
var request = new DownloadManager.Request(source);
request.AllowScanningByMediaScanner();
var cookieString = CookieManager.Instance.GetCookie(e.Url);
request.AddRequestHeader("Cookie", cookieString);
request.AddRequestHeader("User-Agent", e.UserAgent);
request.SetNotificationVisibility(DownloadVisibility.VisibleNotifyCompleted);
request.SetDestinationInExternalPublicDir(AEnvironment.DirectoryDownloads, source.LastPathSegment);
var manager = (DownloadManager)MainActivity.Current.GetSystemService("download");
manager.Enqueue(request);
}
}
The download starts in the background and everyone is happy.
My problem started when I noticed that this behavior is not available in iOS, since the file is displayed on the webview not giving me any option to download or showing the "Open in..." dialog. In plus, after trying to implement a CustomRenderer for the iOS platform too, I see no handler, property or method in the UIWebView or the WKWebView which allows me to manage the download or share the file in another app.
I need to be able to download the file in iOS, or at least, show the "Open in" bar. Any suggestions? Thanks in advance.
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)?