I need to convert bitmap to Imagesource. I have searched online but I can only find examples the other way around.
Do you please have any examples?
how to convert Bitmap to Imagesource Xamarin
You coudl convert the bitmap to stream first on the native platform, then get the imageSource from the stream. You could use DependencyService to achieve the function and call the method in the shared project.
Check the code:
Create an interface in the shared project.
public interface IGetFileStream
{
MemoryStream getStream();
}
Implement the interface in the required platform projects.
[assembly: Dependency(typeof(DroidGetStreamImplement))]
namespace App19F_9.Droid
{
public class DroidGetStreamImplement : IGetFileStream
{
public MemoryStream getStream()
{
var bitmap = ...;
var stream = new MemoryStream();
bitmap.Compress(Bitmap.CompressFormat.Png, 100, stream);
bitmap.Recycle();
return stream;
}
}
}
Resolve the platform implementations from shared code.
public partial class Page5 : ContentPage
{
public Page5()
{
InitializeComponent();
var stream = DependencyService.Get<IGetFileStream>().getStream();
image.Source = ImageSource.FromStream(stream);
}
}
Related
I created a cross platform application using Xamarin. I need to call native functions of iOS and Android platform in my project. Here is the code:
private static Func<IDownloadFile, string> _downloadPath = new Func<IDownloadFile, string>(file =>
{
if (Device.RuntimePlatform == Device.iOS)
{
string fileName = (new NSUrl(file.Url, false)).LastPathComponent;
return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), fileName);
}
else if (Device.RuntimePlatform == Device.Android)
{
string fileName = Android.Net.Uri.Parse(file.Url).Path.Split('/').Last();
return Path.Combine(Android.App.Application.Context.GetExternalFilesDir(Android.OS.Environment.DirectoryDownloads).AbsolutePath, fileName);
}
return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "");
});
This is the code from notification plugin https://github.com/thudugala/Plugin.LocalNotification.
The problem is when I use that code the Mono.Android and Xamarin.iOS references are being added to my shared project in Dependencies/Assemblies and then when I try to run application in the release mode there is a reference error - I noticed that in my Android project in bin/Release there is Xamarin.iOS reference but there is no reference in Android project. When I remove that reference from Dependencies/Assemblies and comment native calls in my code everything compiles correctly. I am confused because of this. Is my above code correctly or I need to call native functions in another way?
When using .net Standard the approach taken is using an interface that defines the functionality you want to expose then implement in each platform.
In Shared:
public interface IMyInterface
{
string GetUrlPath(string fileUrl);
}
iOS Implementation:
public class MyClass : IMyInterface
{
public string GetUrlPath(string fileUrl)
{
string fileName = (new NSUrl(file.Url, false)).LastPathComponent;
return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), fileName);
}
}
Android Implementation:
public class MyClass : IMyInterface
{
public string GetUrlPath(string fileUrl)
{
string fileName = (new NSUrl(file.Url, false)).LastPathComponent;
return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), fileName);
}
}
Then using either Xamarin.Forms DependencyService or any other IoC container you can match the Interface with the correct implementation.
In your shared code you will use the Interface and the implementation picked will be transparent.
This post shows a very complete example of how to do it.
I´m migratting a xamarin forms 3.x app with Prism to forms 4 with shell navigation.
Do I have to create my custom solution to pass complex parameters to the new page or Xamarin has some buildin feature to receive other than string parameters?
Thanks.
As far as I know, and, reading the docs, the only samples regard passing simple data, like string when navigating.
However, I was able to find an Issue (and Pull Request), for passing objects/ Models, for the next version (I assume this is the case you are referring to).
You can track it here.
I've run some tests which seems to be working. I'm relatively new to Xamarin, hence recommend caution and welcome any feedback for any potential issues I may be overlooking.
I wrote an extension to Shell to accept a data object parameter 'navigationData' as follows:-
await Shell.Current.GoToAsync(state, navigationData, animate);
The extension ...
namespace Xamarin.Forms
{
public static class ShellExtensions
{
public static async Task GoToAsync(this Shell shell, ShellNavigationState state, object navigationData, bool animate=false)
{
shell.Navigated += async (sender, e) =>
{
if ((Shell.Current?.CurrentItem?.CurrentItem as IShellSectionController)?.PresentedPage is MyContentPage
p) await p.InitializeAsync(navigationData).ConfigureAwait(false);
};
await shell.GoToAsync(state, animate);
}
}
}
As shown above the extension:-
hooks to the Shell 'Navigated' event,
retrieves the 'current view (page)' as 'MyContentPage' i.e. subclassed ContentPage,
calls an InitializeAsync method on the view passing in the
navigationData parameter
the view then calls an InitializeAsync
method on the binding context (view model) passing the
navigationData parameter onto the viewModel.
In the extension method above, 'MyContentPage' is a custom abstract subclass of ContentPage with an InitializeAsync(navigationData) method that simply calls a similar method on the viewModel (binding context of the view).
Similarily, ViewModels subclass a custom ViewModelBase class that has a virtual InitializeAsync(navigationData). This can be overridden in the viewModel with the desired implementation and handling of the navigation data.
Simplified sample of Views, ViewModels and related base classes shown below
using System.Threading.Tasks;
using MyXamarinApp.ViewModels;
using Xamarin.Forms;
namespace MyXamarinApp.Views
{
public ItemDetailPage : MyContent<ItemDetailViewModel>{}
public ItemPage : MyContentPage<ItemViewModel>{}
public abstract class MyContentPage<T> : MyContentPage where T : ViewModelBase
{
protected T Vm;
protected override ViewModelBase VmBase => Vm as ViewModelBase;
protected MyContentPage()
{
BindingContext = Vm = ViewModelLocator.Resolve<T>();
}
private Comand _showDetailCommand;
public Command ShowDetailCommand
{
get { return _showDetailCommand ??= new Command(async () =>
await Shell.Current.GoToAsync("itemDetail", new NavigationDataObject())); }
}
}
public abstract class MyContentPage : ContentPage
{
protected abstract ViewModelBase VmBase { get; }
public virtual async Task InitializeAsync(object navigationData)
{
await VmBase.InitializeAsync(navigationData);
}
}
}
public class NavigationDataObject
{
'Properties' etc.
}
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq.Expressions;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
namespace MyXamarinApp.ViewModels
{
public ItemViewModel : ViewModelBase{}
public ItemDetailViewModel : ViewModelBase
{
private NavigationDataObject _navData;
public override async Task InitializeAsync(object navigationData)
{
if (navigationData is NavigationDataObject navData)
{
_navData = navData;
}
await base.InitializeAsync(navigationData);
}
}
public abstract class ViewModelBase
{
public virtual Task InitializeAsync(object navigationData)
{
return Task.FromResult(false);
}
}
}
You can always serialize the model to a JSON string and un-serializes it on the other side?
async void Handle_ItemTapped(object sender, ItemTappedEventArgs e)
{
if (e.Item == null)
return;
DailyPnL PnLClicked = (DailyPnL)e.Item;
string jason = await Task.Run(() => JsonConvert.SerializeObject(PnLClicked));
await Shell.Current.GoToAsync($"viewdailypnl?pnlmodel={jason}");
//Deselect Item
((ListView)sender).SelectedItem = null;
}
Then in your code behind:
public string pnlmodel
{
set
{
string derulo = Uri.UnescapeDataString(value);
viewModel.PnL = Task.Run(() => JsonConvert.DeserializeObject<DailyPnL>(derulo)).Result;
}
}
There is a framework called Xamarin.Zero https://github.com/markjackmilian/Xam.Zero
It lets you use shell while giving you convenient ViewModel to ViewModel navigation, IOC.
You can user stored preferences to store complex data like:
private async void OnItemSelected(Item item)
{
if (item == null)
return;
var jsonstr = JsonConvert.SerializeObject(item);
//Clear the shared preferences in case there is any
Preferences.Clear();
//Store your complex json on a shared preference
Preferences.Set("Data", jsonstr);
await Shell.Current.GoToAsync(nameof(DetailsPage));
}
Retrieve it on the details page like:
bool hasKey = Preferences.ContainsKey("Data");
var content = Preferences.Get("Data", string.Empty);
Details details = hasKey ? JsonConvert.DeserializeObject<Model>(content) : null;
I have an interface
SQLiteConnection _connection = Getconnection();
public SQLite.SQLiteConnection GetConnection()
{
const string sqliteFilename = "TCRMobile.db3";
string documentsPath = System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal); // Documents folder
var dbPath = Path.Combine(documentsPath, sqliteFilename);
return new SQLite.SQLiteConnection(dbPath, SQLiteOpenFlags.ReadWrite | SQLiteOpenFlags.Create | SQLiteOpenFlags.FullMutex, false);
}
So when I kill my app or in any random case, the app crashed. And App Center says reason for crash as:
Cache.get_Connection ()
System.InvalidOperationException: You MUST call Xamarin.Forms.Init(); prior
to using it.
Device.get_PlatformServices ()
Device.GetAssemblies ()
DependencyService.Initialize ()
DependencyService.Get[T] (Xamarin.Forms.DependencyFetchTarget fetchTarget)
Cache.get_Connection ()
TCRMobile.DataAccess.DataAccessBase..cctor () [0x00005] in
<7ccb325064fd467288e39511a2bcad63>:0
I added global::Xamarin.Forms.Forms.Init(this, bundle); in MainActivity.cs file. But still it crashes.
Any help?
First of all, make sure that in your MainActivity.cs (Android) / AppDelegate.cs (iOS) the Forms.Init gets called before the making of the App.
So something like this would be the correct approach
global::Xamarin.Forms.Forms.Init(this, bundle);
LoadApplication(new App());
If the above is correct, check the flow.
You should have
An interface in your portable class
public interface ISQLite
{
SQLiteConnection GetConnection();
}
An implementation for each platform (so iOS/Android/UWP) containing an assembly tag
Android example
[assembly: Xamarin.Forms.Dependency(typeof(SqLiteAndroid))]
namespace Your.Namespace.Droid
{
public class SqLiteAndroid:ISQLite
{
public SQLiteConnection GetConnection()
{
//return connection here
}
}
}
and iOS example, same principle but notice the different namespace and assembly
[assembly: Xamarin.Forms.Dependency(typeof(SqLiteiOS))]
namespace Your.Namespace.iOS
{
public class SqLiteiOS:ISQLite
{
public SQLiteConnection GetConnection()
{
//return connection here
}
}
}
A call to the DependencyService to get the connection e.g. in your App.xaml.cs
string sqlConnection= DependencyService.Get<ISQLite>().GetConnection()
Let me know if this works for you, if not, please provide some more code.
I'm develop cross-platform mobile application that use NFC. I already check the xamarin android beam here. Now i'm trying implement the same sample using xamarin forms so i'm using dependency service to call the function from android project. I try to make simple message that pass from device to another but it didn't work. The problem is the implementation of NfcAdapter.IOnNdefPushCompleteCallback
PhoneBeam.cs
using System;
using System.Text;
using Android.App;
using MyApp.Droid;
using Android.Nfc;
using Xamarin.Forms;
[assembly: Dependency(typeof(PhoneBeam))]
namespace MyApp.Droid
{
public class PhoneBeam : Activity, NfcAdapter.ICreateNdefMessageCallback, NfcAdapter.IOnNdefPushCompleteCallback, iBeam
{
private NfcAdapter nfcAdapter;
public void Beam()
{
nfcAdapter = NfcAdapter.GetDefaultAdapter(MainActivity.Instance);
nfcAdapter.SetNdefPushMessageCallback(this, MainActivity.Instance);
nfcAdapter.SetOnNdefPushCompleteCallback(this, MainActivity.Instance);
}
public NdefMessage CreateNdefMessage(NfcEvent evt)
{
DateTime time = DateTime.Now;
var text = ("Beam me up!\n\n" + "Beam : " +
time.ToString("HH:mm:ss"));
NdefMessage msg = new NdefMessage(
new NdefRecord[]{ CreateMimeRecord (
"application/com.example.android.beam",
Encoding.UTF8.GetBytes (text)) });
return msg;
}
public NdefRecord CreateMimeRecord(String mimeType, byte[] payload)
{
byte[] mimeBytes = Encoding.UTF8.GetBytes(mimeType);
NdefRecord mimeRecord = new NdefRecord(
NdefRecord.TnfMimeMedia, mimeBytes, new byte[0], payload);
return mimeRecord;
}
}
}
It says 'PhoneBeam does not implement interface member NfcAdapter.IOnNdefPushCompleteCallback.OnNdefPushComplete(NfcEvent)'. Am i missing something?
Your class implements IOnNdefPushCompleteCallback, which has a public method OnNdefPushComplete that must be implemented in order to satisfy the Interface.
We're using ASP.NET WebAPI with Entity Framework (with lazy loading) and using Json.NET for serializing the data to JSON before returning the data to the client.
We are experiencing intermittent sudden spikes in memory usage which we suspect might originate with Json.NET not recognizing reference loops when serializing data (since Entity Framework might be doing some lazy loading voodoo with proxy classes which goes under the radar of Json.NET).
I thought I'd limit how deep Json.NET was allowed to go to serialize data (at least then we'd get a sensible exception when this happens so we could fix it in the data model), but I soon discovered that the MaxDepth property of JsonSerializerSettings only kicks in when DEserializing objects.
Is there any known way of imposing a limit on Json.NET when serializing?
I can't think of a way to do this out-of-the-box with Json.NET, since (as you correctly observe) MaxDepth is ignored when serializing. What you could do is to subclass JsonTextWriter and do the checks yourself:
public class MaxDepthJsonTextWriter : JsonTextWriter
{
public int? MaxDepth { get; set; }
public int MaxObservedDepth { get; private set; }
public MaxDepthJsonTextWriter(TextWriter writer, JsonSerializerSettings settings)
: base(writer)
{
this.MaxDepth = (settings == null ? null : settings.MaxDepth);
this.MaxObservedDepth = 0;
}
public MaxDepthJsonTextWriter(TextWriter writer, int? maxDepth)
: base(writer)
{
this.MaxDepth = maxDepth;
}
public override void WriteStartArray()
{
base.WriteStartArray();
CheckDepth();
}
public override void WriteStartConstructor(string name)
{
base.WriteStartConstructor(name);
CheckDepth();
}
public override void WriteStartObject()
{
base.WriteStartObject();
CheckDepth();
}
private void CheckDepth()
{
MaxObservedDepth = Math.Max(MaxObservedDepth, Top);
if (Top > MaxDepth)
throw new JsonSerializationException(string.Format("Depth {0} Exceeds MaxDepth {1} at path \"{2}\"", Top, MaxDepth, Path));
}
}
Then, to manually generate a JSON string, you would use it like this:
var settings = new JsonSerializerSettings { MaxDepth = 10 };
string json;
try
{
using (var writer = new StringWriter())
{
using (var jsonWriter = new MaxDepthJsonTextWriter(writer, settings))
{
JsonSerializer.Create(settings).Serialize(jsonWriter, myClass);
// Log the MaxObservedDepth here, if you want to.
}
json = writer.ToString();
}
Debug.WriteLine(json);
}
catch (Exception ex)
{
Debug.WriteLine(ex);
throw;
}
Demo fiddle here.
Since your tags include web-api, if you want to do this check inside web API calls, you could follow Rick Strahl's instructions to create a custom MediaTypeFormatter for JSON: Using an alternate JSON Serializer in ASP.NET Web API; then use the code above in the OnWriteToStreamAsync method when generating the json string.