SQLite support for Universal Windows App - windows

I am using Xamarin Forms to develop an app and using SQlite to store the user details. Just started with windows(Windows 10). Does SQLite has support for UWP, I have referred some sites and its saying it does support. but when I am trying, the connection is always null.
The code i am using:
public SQLite.Net.SQLiteConnection GetConnection()
{
var sqliteFilename = "Sample.db3";
string path = Path.Combin(ApplicationData.Current.LocalFolder.Path, sqliteFilename);
if (!File.Exists(path))
{
File.Create(path + sqliteFilename);
}
var plat = new SQLite.Net.Platform.WinRT.SQLitePlatformWinRT();
var conn = new SQLite.Net.SQLiteConnection(plat,path);
return conn;
}
}
Any help or suggestion would be much appreciated.
Note: I have installed the SQLite.Net-PCL and added reference to SQLite for Universal App Platform

Inside your App.cs I have a static variable called:
public static LocalDatabase Database { get; private set; }
public App()
{
Database = new LocalDatabase();...
}
And then you can access your Database class on any place of your controller like: App.Database
For reference LocalDatabase class will contain:
public class LocalDatabase
{
static readonly object locker = new object ();
static SQLiteConnection database;
string DatabasePath {
get {
const string sqliteFilename = "LocalDatabaseSQLite.db3";
#if __IOS__
string documentsPath = Environment.GetFolderPath (Environment.SpecialFolder.Personal); // Documents folder
string libraryPath = Path.Combine (documentsPath, "..", "Library"); // Library folder
var path = Path.Combine (libraryPath, sqliteFilename);
#else
#if __ANDROID__
string documentsPath = Environment.GetFolderPath(Environment.SpecialFolder.Personal); // Documents folder
var path = Path.Combine(documentsPath, sqliteFilename);
#else
// WinPhone
var path = Path.Combine(Windows.Storage.ApplicationData.Current.LocalFolder.Path, sqliteFilename); ;
#endif
#endif
return path;
}
}
public LocalDatabase ()
{
database = new SQLiteConnection (DatabasePath);
database.CreateTable<UserSQLModel> ();
//All your create tables...
}
}

Related

Xamarin Forms save image from an url into device's gallery

I am working on Xamarin Forms (with iOS and Android). What I want to do is to allow users to download image from an url by using DependencyService. I tried run in IOS emulator and the image did save into the emulator but does not show up in the gallery.
Appreciate help in that and following is my code:
In ViewModel:
public void DownloadImage()
{
IFileService fileSvc = DependencyService.Get<IFileService>();
WebClient wc = new WebClient();
byte[] bytes = wc.DownloadData(ImgUrl);
Stream stream = new MemoryStream(bytes);
fileSvc.SavePicture(DateTime.Now.ToString(), stream, "temp");
}
In Xamarin.iOS
public void SavePicture(string name, Stream data, string location = "temp")
{
var documentsPath = Environment.GetFolderPath(Environment.SpecialFolder.Personal);
string imageFilename = Path.Combine(documentsPath, "Images", location);
Directory.CreateDirectory(imageFilename);
string filePath = Path.Combine(documentsPath, name);
byte[] bArray = new byte[data.Length];
using (FileStream fs = new FileStream(filePath, FileMode.OpenOrCreate))
{
using (data)
{
data.Read(bArray, 0, (int)data.Length);
}
int length = bArray.Length;
fs.Write(bArray, 0, length);
}
}
In Xamarin.Droid
public void SavePicture(string name, Stream data, string location = "temp")
{
var documentsPath = Environment.GetFolderPath(Environment.SpecialFolder.Personal);
documentsPath = Path.Combine(documentsPath, "Images", location);
Directory.CreateDirectory(documentsPath);
string filePath = Path.Combine(documentsPath, name);
byte[] bArray = new byte[data.Length];
using (FileStream fs = new FileStream(filePath, FileMode.OpenOrCreate))
{
using (data)
{
data.Read(bArray, 0, (int)data.Length);
}
int length = bArray.Length;
fs.Write(bArray, 0, length);
}
}
If you Want to save image into Gallery, please follow the code below.
Firstly, create Create the IMediaService Interface in PCL.
public interface IMediaService
{
void SaveImageFromByte(byte[] imageByte,string filename);
}
Then implement this interface in Platform-specific
Xamarin.Android Project
public class MediaService : IMediaService
{
Context CurrentContext => CrossCurrentActivity.Current.Activity;
public void SaveImageFromByte(byte[] imageByte, string filename)
{
try
{
Java.IO.File storagePath = Android.OS.Environment.GetExternalStoragePublicDirectory(Android.OS.Environment.DirectoryPictures);
string path = System.IO.Path.Combine(storagePath.ToString(), filename);
System.IO.File.WriteAllBytes(path, imageByte);
var mediaScanIntent = new Intent(Intent.ActionMediaScannerScanFile);
mediaScanIntent.SetData(Android.Net.Uri.FromFile(new Java.IO.File(path)));
CurrentContext.SendBroadcast(mediaScanIntent);
}
catch (Exception ex)
{
}
}
}
implement this interface in Platform-specific
Xamarin.iOS Project
public class MediaService : IMediaService
{
public void SaveImageFromByte(byte[] imageByte,string fileName)
{
var imageData = new UIImage(NSData.FromArray(imageByte));
imageData.SaveToPhotosAlbum((image, error) =>
{
//you can retrieve the saved UI Image as well if needed using
//var i = image as UIImage;
if (error != null)
{
Console.WriteLine(error.ToString());
}
});
}
}
For accessing the CurrentContext Install the NuGet Package (Plugin.CurrentActivity) from NuGet Package Manager, also check for the external storage permission.

Xamarin Prism cannot navigate with parameters

for my app i create my own buttons using a frame and adding a tapgesture to it. here i use the navigation of prism to go to a specific page with a parameter. however. the viewmodel i'm going to does not trigger the Navigated to method. here is some code.
during debugging it seems that the adding of the parameters is no problem. however the constructor for the viewmodel is called instead.
button
public class FolderButton : Frame
{
public FolderButton(Folder folder, INavigationService navigationService)
{
var navParams = new NavigationParameters();
navParams.Add("folder", folder);
GestureRecognizers.Add(new TapGestureRecognizer()
{
Command = new Command(async () => { await navigationService.NavigateAsync("FolderInventory", navParams); }),
});
BackgroundColor = Color.CornflowerBlue;
var thickness = new Thickness();
thickness.Bottom = 10;
thickness.Left = 10;
thickness.Right = 10;
thickness.Top = 10;
Margin = thickness;
CornerRadius = 5;
var completeStack = new StackLayout();
var imgStack = new StackLayout();
imgStack.Padding = thickness;
imgStack.Children.Add(new Image { Source = "folder.png" });
completeStack.Children.Add(imgStack);
var lblStack = new StackLayout();
lblStack.Padding = thickness;
lblStack.Children.Add(new Label
{
Text = folder.Name,
HorizontalTextAlignment = TextAlignment.Center,
VerticalTextAlignment = TextAlignment.Start
});
completeStack.Children.Add(lblStack);
Content = completeStack;
}
}
called viewmodel
public class FolderInventoryViewModel : BindableBase, INavigatedAware
{
public Folder Folder => _folder;
private readonly INavigationService _navigationService;
private Folder _folder;
private readonly ISQLiteService _sqlService;
private List<Frame> _buttons;
public List<Frame> Buttons
{
get => _buttons;
set => _buttons = value;
}
public FolderInventoryViewModel(Folder folder, INavigationService navigationService, ISQLiteService sqlService)
{
_folder = folder;
_sqlService = sqlService;
_navigationService = navigationService;
GetItemsForFolder();
}
private void GetItemsForFolder()
{
var itemList = _sqlService.GetAllFolderItems(Folder.Name);
foreach (var item in itemList)
{
var itemButton = new ItemButton(_navigationService, item);
_buttons.Add(itemButton);
}
}
public void OnNavigatedFrom(NavigationParameters parameters)
{
if (parameters["folder"] is Folder folder)
{
_folder = folder;
}
}
public void OnNavigatedTo(NavigationParameters parameters)
{
if (parameters["folder"] is Folder folder)
{
_folder = folder;
}
}
}
This is not the essence of using the framework. To properly use the Prism with its NavigationParameters you first properly maintain the MVVM idea behind it.
E.g.
<Button Command="{Binding testCommand}" text="TestButton"/>
Your ViewModel (Pardon about this, you need to inject NavigationService to your ViewModel's constructor)
private DelegateCommand _testCommand;
public DelegateCommand testCommand =>
_testCommand?? (_testCommand= new DelegateCommand(ExecuteTest));
private void ExecuteTest()
{
NavigationParameters navigationParameters = new NavigationParameters();
navigationParameters.Add("yourParameterId", value);
NavigationService.NavigateAsync("YourPage", navigationParameters);
}
And then onto your next page
Inherit INavigationAware to your NextPage : YourNextPage: BaseViewModel, INavigationAware
INavigationAware has 3 methods NavigatingTo, NavigatedTo, NavigatedFrom
Inside OnNavigatedTo you can call the parameters you have passed
public void OnNavigatedTo(NavigationParameters parameters)
{
//You can check if parameters has value before passing it inside
if(parameters.ContainsKey("YourParameterId")
{
yourItem = (dataType)parameters[YourParameterId];
}
}
Also note: The constructor will always be called first before the Navigating methods

FreshMvvm PushNewNavigationServiceModal not working

I'm trying to change from FreshNavigationContainer to FreshMasterDetailNavigationContainer when the user is loggedin within the method SuccessfulLogin by using freshMvvm method PushNewNavigationServiceModal but nothing is happening.
public void SuccessfulLogin()
{
App.IsLoggedIn = true;
var masterDetailNav = new FreshMasterDetailNavigationContainer();
masterDetailNav.Init("Menu");
masterDetailNav.AddPage<ProfilePageModel>("Profile", null);
CoreMethods.PushNewNavigationServiceModal(masterDetailNav);
}
Edit :
I just noticed that after using this method navigation isn't working anymore.
You need to use CoreMethods.SwitchOutRootNavigation
First Setup your NavigationStacks
public class NavigationStacks
{
public static string LoginNavigationStack = "LoginNavigationStack";
public static string MainAppStack = "MainAppStack";
}
In you App.xaml.cs define the Navigations
FreshNavigationContainer loginMain;
FreshMasterDetailNavigationContainer masterDetailNav;
var loginPage = FreshPageModelResolver.ResolvePageModel<UserLoginPageModel>();
loginMain = new FreshNavigationContainer(loginPage, NavigationStacks.LoginNavigationStack);
var masterDetailNav = new FreshMasterDetailNavigationContainer(NavigationStacks.MainAppStack);
masterDetailNav.Init("Menu");
masterDetailNav.AddPage<ProfilePageModel>("Profile", null);
Then in your Login ViewModel
public void SuccessfulLogin()
{
App.IsLoggedIn = true;
CoreMethods.SwitchOutRootNavigation(NavigationStacks.MainAppStack);
}

using existing SqlCe database in windows phone

I have a SqlCe database which i made for another project. Now i want to use it for a windows phone project. My database structure is
I copied my database into my project folder and set it's build action as "content" and copy to output directory as "copy always".
In my main page i used this:
private const string Con_String = #"isostore:/mydb.sdf";
public MainPage()
{
InitializeComponent();
IsolatedStorageFile iso = IsolatedStorageFile.GetUserStoreForApplication();
using (mTableDatabaseContext context = new mTableDatabaseContext(Con_String))
{
if (!context.DatabaseExists())
{
context.CreateDatabase();
}
if (!iso.FileExists("mydb.sdf"))
{
MoveReferenceDatabase();
}
}
}
public static void MoveReferenceDatabase()
{
IsolatedStorageFile iso = IsolatedStorageFile.GetUserStoreForApplication();
using (Stream input = Application.GetResourceStream(new Uri("mydb.sdf", UriKind.Relative)).Stream)
{
using (IsolatedStorageFileStream output = iso.CreateFile("mydb.sdf"))
{
byte[] readBuffer = new byte[4096];
int bytesRead = -1;
while ((bytesRead = input.Read(readBuffer, 0, readBuffer.Length)) > 0)
{
output.Write(readBuffer, 0, bytesRead);
}
}
}
}
and my mTableDatabaseContext class is like that:
public class mTableDatabaseContext:DataContext
{
public mTableDatabaseContext(string connectionString): base(connectionString)
{
}
public Table<dic> my_dics
{
get
{
return this.GetTable<dic>();
}
}
public Table<learn_table> my_learn_tables
{
get
{
return this.GetTable<learn_table>();
}
}
}
But i cant use my database and copy of my database cant be performed???
What can i do to do this??
How can i do this?? Can anyone help me??
You should use
private const string Con_String = #"Data Source=isostore:/mydb.sdf";
instead of
private const string Con_String = #"isostore:/mydb.sdf";

How to use Razor Section multiple times in a View & PartialView (merge) without overriding it?

In the _Layout.cshtml file, I have a section at the bottom of the body called "ScriptsContent" declared like this:
#RenderSection("ScriptsContent", required: false)
In my view, I can then use this section to add scripts to be executed. But what if I also have a PartialView that also need to use this section to add additional scripts?
View
#section ScriptsContent
{
<script type="text/javascript">
alert(1);
</script>
}
#Html.Partial("PartialView")
PartialView
#section ScriptsContent
{
<script type="text/javascript">
alert(2);
</script>
}
Result
Only the first script is rendered. The second script doesn't exist in source code of the webpage.
Razor seems to only output the first #section ScriptsContent that it sees. What I would like to know is if there's a way to merge each call to the section.
If we cannot do this, what do you propose?
Here's a solution for that problem. It's from this blog: http://blog.logrythmik.com/post/A-Script-Block-Templated-Delegate-for-Inline-Scripts-in-Razor-Partials.aspx
public static class ViewPageExtensions
{
private const string SCRIPTBLOCK_BUILDER = "ScriptBlockBuilder";
public static MvcHtmlString ScriptBlock(this WebViewPage webPage, Func<dynamic, HelperResult> template)
{
if (!webPage.IsAjax)
{
var scriptBuilder = webPage.Context.Items[SCRIPTBLOCK_BUILDER] as StringBuilder ?? new StringBuilder();
scriptBuilder.Append(template(null).ToHtmlString());
webPage.Context.Items[SCRIPTBLOCK_BUILDER] = scriptBuilder;
return new MvcHtmlString(string.Empty);
}
return new MvcHtmlString(template(null).ToHtmlString());
}
public static MvcHtmlString WriteScriptBlocks(this WebViewPage webPage)
{
var scriptBuilder = webPage.Context.Items[SCRIPTBLOCK_BUILDER] as StringBuilder ?? new StringBuilder();
return new MvcHtmlString(scriptBuilder.ToString());
}
}
so anywwhere in your View or PartialView you can use this:
#this.ScriptBlock(
#<script type='text/javascript'>
alert(1);
</script>
)
and in your _Layout or MasterView, use this:
#this.WriteScriptBlocks()
There is no way to share sections between a view and partial views.
Absent a ScriptManager-like solution, you could have a collection of script files (initialized in your view and stored either in HttpContext.Items or in ViewData) to which the partial view would append the script file names it requires. Then towards the end of your view you would declare a section that fetches that collection and emits the right script tags.
The problem with the accepted answer is that it breaks Output Caching. The trick to solving this is to overwrite the OutputCache attribute with your own implementation. Unfortunately we can't extend the original attribute since it has lots of internal methods which we need to access.
I actually use Donut Output Caching which overwrites the OutputCache attribute itself. There are alternative libraries which also use their own OutputCache attribute so I will explain the steps I made to get it to work so that you can apply it to whichever one you're using.
First you need to copy the existing OutputCache attribute and place it within your application. You can get the existing attribute by looking at the source code.
Now add the following property to the class. This is where we store the script blocks so we can render the correct ones when retrieving from the cache.
public static ConcurrentDictionary<string, StringBuilder> ScriptBlocks = new ConcurrentDictionary<string, StringBuilder>();
Now inside the OnActionExecuting method you need to store the cache key (the unique identifier for the output cache) inside the current requests collection. For example:
filterContext.HttpContext.Items["OutputCacheKey"] = cacheKey;
Now modify the ViewPageExtensions class by adding the following (replacing CustomOutputCacheAttribute with the name of your attribute):
var outputCacheKey = webPage.Context.Items["OutputCacheKey"] as string;
if (outputCacheKey != null)
CustomOutputCacheAttribute.ScriptBlocks.AddOrUpdate(outputCacheKey, new StringBuilder(template(null).ToHtmlString()), (k, sb) => {
sb.Append(template(null).ToHtmlString());
return sb;
});
before:
return new MvcHtmlString(string.Empty);
Note: For a slight performance boost you'll also want to make sure you only call "template(null).ToHtmlString()" once.
Now return to your custom OutputCache attribute and add the following only when you are retrieving from the cache inside the OnActionExecuting method:
if (ScriptBlocks.ContainsKey(cacheKey)) {
var scriptBuilder = filterContext.HttpContext.Items["ScriptBlockBuilder"] as StringBuilder ?? new StringBuilder();
scriptBuilder.Append(ScriptBlocks[cacheKey].ToString());
filterContext.HttpContext.Items["ScriptBlockBuilder"] = scriptBuilder;
}
Here's the final code of my attribute:
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.Mvc;
using System.Web.UI;
using DevTrends.MvcDonutCaching;
public class CustomOutputCacheAttribute : ActionFilterAttribute, IExceptionFilter {
private readonly IKeyGenerator _keyGenerator;
private readonly IDonutHoleFiller _donutHoleFiller;
private readonly IExtendedOutputCacheManager _outputCacheManager;
private readonly ICacheSettingsManager _cacheSettingsManager;
private readonly ICacheHeadersHelper _cacheHeadersHelper;
private bool? _noStore;
private CacheSettings _cacheSettings;
public int Duration { get; set; }
public string VaryByParam { get; set; }
public string VaryByCustom { get; set; }
public string CacheProfile { get; set; }
public OutputCacheLocation Location { get; set; }
public bool NoStore {
get { return _noStore ?? false; }
set { _noStore = value; }
}
public static ConcurrentDictionary<string, StringBuilder> ScriptBlocks = new ConcurrentDictionary<string, StringBuilder>();
public DonutOutputCacheAttribute() {
var keyBuilder = new KeyBuilder();
_keyGenerator = new KeyGenerator(keyBuilder);
_donutHoleFiller = new DonutHoleFiller(new EncryptingActionSettingsSerialiser(new ActionSettingsSerialiser(), new Encryptor()));
_outputCacheManager = new OutputCacheManager(OutputCache.Instance, keyBuilder);
_cacheSettingsManager = new CacheSettingsManager();
_cacheHeadersHelper = new CacheHeadersHelper();
Duration = -1;
Location = (OutputCacheLocation)(-1);
}
public override void OnActionExecuting(ActionExecutingContext filterContext) {
_cacheSettings = BuildCacheSettings();
var cacheKey = _keyGenerator.GenerateKey(filterContext, _cacheSettings);
if (_cacheSettings.IsServerCachingEnabled) {
var cachedItem = _outputCacheManager.GetItem(cacheKey);
if (cachedItem != null) {
filterContext.Result = new ContentResult {
Content = _donutHoleFiller.ReplaceDonutHoleContent(cachedItem.Content, filterContext),
ContentType = cachedItem.ContentType
};
if (ScriptBlocks.ContainsKey(cacheKey)) {
var scriptBuilder = filterContext.HttpContext.Items["ScriptBlockBuilder"] as StringBuilder ?? new StringBuilder();
scriptBuilder.Append(ScriptBlocks[cacheKey].ToString());
filterContext.HttpContext.Items["ScriptBlockBuilder"] = scriptBuilder;
}
}
}
if (filterContext.Result == null) {
filterContext.HttpContext.Items["OutputCacheKey"] = cacheKey;
var cachingWriter = new StringWriter(CultureInfo.InvariantCulture);
var originalWriter = filterContext.HttpContext.Response.Output;
filterContext.HttpContext.Response.Output = cachingWriter;
filterContext.HttpContext.Items[cacheKey] = new Action<bool>(hasErrors => {
filterContext.HttpContext.Items.Remove(cacheKey);
filterContext.HttpContext.Response.Output = originalWriter;
if (!hasErrors) {
var cacheItem = new CacheItem {
Content = cachingWriter.ToString(),
ContentType = filterContext.HttpContext.Response.ContentType
};
filterContext.HttpContext.Response.Write(_donutHoleFiller.RemoveDonutHoleWrappers(cacheItem.Content, filterContext));
if (_cacheSettings.IsServerCachingEnabled && filterContext.HttpContext.Response.StatusCode == 200)
_outputCacheManager.AddItem(cacheKey, cacheItem, DateTime.UtcNow.AddSeconds(_cacheSettings.Duration));
}
});
}
}
public override void OnResultExecuted(ResultExecutedContext filterContext) {
ExecuteCallback(filterContext, false);
if (!filterContext.IsChildAction)
_cacheHeadersHelper.SetCacheHeaders(filterContext.HttpContext.Response, _cacheSettings);
}
public void OnException(ExceptionContext filterContext) {
if (_cacheSettings != null)
ExecuteCallback(filterContext, true);
}
private void ExecuteCallback(ControllerContext context, bool hasErrors) {
var cacheKey = _keyGenerator.GenerateKey(context, _cacheSettings);
var callback = context.HttpContext.Items[cacheKey] as Action<bool>;
if (callback != null)
callback.Invoke(hasErrors);
}
private CacheSettings BuildCacheSettings() {
CacheSettings cacheSettings;
if (string.IsNullOrEmpty(CacheProfile)) {
cacheSettings = new CacheSettings {
IsCachingEnabled = _cacheSettingsManager.IsCachingEnabledGlobally,
Duration = Duration,
VaryByCustom = VaryByCustom,
VaryByParam = VaryByParam,
Location = (int)Location == -1 ? OutputCacheLocation.Server : Location,
NoStore = NoStore
};
} else {
var cacheProfile = _cacheSettingsManager.RetrieveOutputCacheProfile(CacheProfile);
cacheSettings = new CacheSettings {
IsCachingEnabled = _cacheSettingsManager.IsCachingEnabledGlobally && cacheProfile.Enabled,
Duration = Duration == -1 ? cacheProfile.Duration : Duration,
VaryByCustom = VaryByCustom ?? cacheProfile.VaryByCustom,
VaryByParam = VaryByParam ?? cacheProfile.VaryByParam,
Location = (int)Location == -1 ? ((int)cacheProfile.Location == -1 ? OutputCacheLocation.Server : cacheProfile.Location) : Location,
NoStore = _noStore.HasValue ? _noStore.Value : cacheProfile.NoStore
};
}
if (cacheSettings.Duration == -1)
throw new HttpException("The directive or the configuration settings profile must specify the 'duration' attribute.");
if (cacheSettings.Duration < 0)
throw new HttpException("The 'duration' attribute must have a value that is greater than or equal to zero.");
return cacheSettings;
}
}
I also had to modify the Donut Output Cache library to make IExtendedOutputCacheManager and the OutputCacheManager constructor public.
Please note this has been extracted from my application and may require some minor tweaks. You should also place WriteScriptBlocks at the bottom of the page so it is not called until after all child actions are triggered.
Hope this helps.

Resources