Xamarin Copy File Cross Platform - xamarin

Is it possible to copy a file in Xamarin Cross Platform? e.g. copy a SQLlite db3 from one directory to another. All i can get is the path of the file.
I found solutions for Xamarain.Android and iOS but I want to have it combined in one Portable class.
EDIT
Maybe there are better solutions out there but here is what I got with PCL Sotrage.
IFile file = FileSystem.Current.GetFileFromPathAsync(src).Result;
IFolder rootFolder = FileSystem.Current.GetFolderFromPathAsync(dest).Result;
IFolder folder = rootFolder.CreateFolderAsync("MySubFolder", CreationCollisionOption.OpenIfExists).Result;
IFile newFile = folder.CreateFileAsync("TodoItem.db3", CreationCollisionOption.GenerateUniqueName).Result;
Stream str = file.OpenAsync(FileAccess.ReadAndWrite).Result;
Stream newStr = newFile.OpenAsync(FileAccess.ReadAndWrite).Result;
byte[] buffer = new byte[str.Length];
int n;
while ((n = str.Read(buffer, 0, buffer.Length)) != 0)
newStr.Write(buffer, 0, n);
str.Dispose();
newStr.Dispose();

I think a good solution is to use DependencyService.
For Example, in PCL create an Interface
public interface IFile {
void Copy ( string fromFile, string toFile );
}
In Android the platform-specific implementation
[assembly: Xamarin.Forms.Dependency (typeof (FileImplementation))]
namespace File.Droid {
public class FileImplementation : IFile
{
public FileImplementation() {}
public void Copy(string fromFile, string toFile)
{
System.IO.File.Copy(fromFile, toFile);
}
}
}
Then in your PCL you can call
DependencyService.Get<IFile>().Copy("myfile", "newfile");
With .NETStandard you could use System.IO directly in your PCL Project

The cool new way to do it would be to use a .Net Standard library instead of a PCL. .Net Standard 1.6 is supported on Xamarin.IOS and Xamarin.Android and include System.IO.File unlike PCL profiles.
You could also use a Shared Project instead of a PCL, since both X.IOS and X.Android include System.IO.File support, it would work pretty seamlessly in a Shared Project.
Otherwise, If you are using Xamarin Forms, I think Alessandro's DependencyService solution is a good one, and even if you aren't using Forms, the interface abstraction idea applies.

To avoid having to deal with different filesystems and their quirks on each platform, you can use the PCLStorage library to do quite a wide array of operations on all Xamarin.Forms platforms.
Take a look at it here: https://github.com/dsplaisted/PCLStorage

Related

Xamarin Forms Video Player Sample - Get Video Bytes for Uploading

I'm implementing a video player in a Xamarin Forms app just like the video player sample provided by Xamarin
https://learn.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/custom-renderer/video-player/
I'm able to select a video from the phone gallery, set the video player source to the selected video, and play the video. How do I get the actual stream or bytes of the selected video so that I can upload it to Blob Storage?
I've tried
using (FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read)) ..........
where fileName is the path and file name of the selected video as set to the video player source. It doesn't work as the Android file name string is not found. (When invoking this from xamarin forms). I realize the file name will be different even when on iOS. How do I reach down into the platform specific implementations and get the file bytes or stream of the selected file?
thanks
I would look into the libVLCSharp library which provides cross-platform .NET/Mono bindings for libVLC. They provide good support for Xamarin.Forms and the features you most likely need to implement the stream handling functionality. What you're trying to achieve won't be simple but it should be perfectly doable.
First, you should check out the documentation for Stream output:
Stream output is the name of the feature of VLC that allows to output any stream read by VLC to a file or as a network stream instead of displaying it.
Related tutorial: Stream to memory (smem) tutorial.
That should get you started but there will for sure be many caveats along the way. For example, if you try to play the video while capturing the bytes to be uploaded somewhere, you'll have to respect VERY tight timeframes. In case you take too long to process the stream, it will slow down the playback and the user experience suffers.
Edit: Another option you could look into is to interact directly with the MediaPlayer class of libVLC, as explained in this answer. The sample code is in C++ but the method names are very similar in the .NET bindings.
For example, the following piece of code:
libvlc_video_set_callbacks(mplayer,
lock_frame, unlock_frame,
0, user_data);
can be implemented with libVLCSharp by calling the SetVideoCallbacks(LibVLCVideoLockCb lockCb, LibVLCVideoUnlockCb unlockCb, LibVLCVideoDisplayCb displayCb) method in the binding library, as defined here.
You can do this pretty simply by using a DependencyService. You will need to adjust the below code to cater for a folder location that you're working with but, do this.
Change all of the "Test" namespaces to you're own project.
Add an interface into your shared project called IFileSystem that looks like this ...
using System;
namespace Test.Interfaces
{
public interface IFileSystem
{
byte[] GetFileInBytes(string fileName);
}
}
Create a dependency service down in each platform project. For this, I'm only supplying iOS and Android but as you'll see, the logic for both is essentially exactly the same, only the namespace differs ...
iOS
using System;
using System.IO;
using Test.Interfaces;
using Test.iOS.DependencyServices;
using Xamarin.Forms;
[assembly: Dependency(typeof(FileSystem))]
namespace Test.iOS.DependencyServices
{
public class FileSystem : IFileSystem
{
public byte[] GetFileInBytes(string fileName)
{
var folder = Environment.GetFolderPath(Environment.SpecialFolder.MyVideos);
fileName = Path.Combine(folder, fileName);
return File.Exists(fileName) ? File.ReadAllBytes(fileName) : null;
}
}
}
Android
using System;
using System.IO;
using Test.Interfaces;
using Test.Droid.DependencyServices;
using Xamarin.Forms;
[assembly: Dependency(typeof(FileSystem))]
namespace Test.Droid.DependencyServices
{
public class FileSystem : IFileSystem
{
public byte[] GetFileInBytes(string fileName)
{
var folder = Environment.GetFolderPath(Environment.SpecialFolder.MyVideos);
fileName = Path.Combine(folder, fileName);
return File.Exists(fileName) ? File.ReadAllBytes(fileName) : null;
}
}
}
... now call that from anywhere in your shared project.
var bytes = DependencyService.Get<IFileSystem>().GetFileInBytes("Test.mp4");
That should work for you, again though, you need to adjust the folder path to your appropriate location for each platform project. Essentially, this line is the one that may need to change ...
var folder = Environment.GetFolderPath(Environment.SpecialFolder.MyVideos);
Alternatively, change that code to suit your requirements. If the file path you've been given contains the fully qualified location, then remove the logic to add the folder altogether.
Here's hoping that works for you.

FHIR.net Property added to Practitioner

We're currently using FHIR.net library(STU3). The FHIR Server from which we are receiving information has added a practitionerRole property to the Practitioner. Thus when Reading a Practitioner, we get the following Exception:
Encountered unknown member 'practitionerRole' while de-serializing (at path 'line 1, pos 2') in Hl7.Fhir.Rest.HttpToEntryExtensions.parseResource(String bodyText, String contentType, ParserSettings settings, Boolean throwOnFormatException)
The only solution I could think of is to add a practitionerRole property in the Model\Generated\Practitioner.cs class that would go like that:
[FhirElement("practitionerRole", InSummary = true, Order = 115)]
[Cardinality(Min = 0, Max = -1)]
[DataMember]
public List<Hl7.Fhir.Model.PractitionerRole> PractitionerRole
{
get { if (_PractitionerRole == null) _PractitionerRole = new List<Hl7.Fhir.Model.PractitionerRole>(); return _PractitionerRole; }
set { _PractitionerRole = value; OnPropertyChanged("PractitionerRole"); }
}
private List<Hl7.Fhir.Model.PractitionerRole> _PractitionerRole;
Is there any other solution than that? If so, which one?
Thank you in advance
It sounds like you're talking to a DSTU2 server. You'll need some sort of a conversion layer between your system and theirs.
As stated by FHIR employees in https://sea-region.github.com/standardhealth/shr_spec/issues/187 , DSTU2 and STU3 are two different versions of FHIR standard. If you check their last commits (https://www.nuget.org/packages?q=Fhir) as in August 2019, you will see they are maintaining both standards. That is probably due to the hospitals using STU3 version and do not want to adapt to the new version of FHIR, which is DSTU2.
The problem arises when you want to reach a class, let's say Patient, that coexists in two versions. Compiler can not decide which "Patient" class you refer to.
Normally, you could specialize using imports or predescription such as :
Hl7.Fhir.Model.Patient p = new Hl7.Fhir.Model.Patient();
BUT, Patient classes in both versions are described as Hl7.Fhir.Model.Patient. Their namespace is "Hl7.Fhir.Model" and their class name is "Patient".
Normally, you could workaround using keyword:
extern alias
BUT, since model classes in FHIR are read only, you can not use both versions in same project.
You need to uninstall unwanted FHIR version and install wanted version. To do these in Visual Studio,
go to Solution Manager> right click on "Manage Nuget Packages" > Search "Fhir" > uninstall unwanted FHIR version > install wanted version
You can also follow the unanswered question below:
C# T4 Template equivalent for "extern alias"

WP7 app version

A Windows Phone 7 app, it seems, has two places with version number - one in AssemblyInfo.cs (via AssemblyVersion/AssemblyFileVersion attributes), the other is WMAppManifest.xml. Those two seem uncorrelated - changing one does not affect the other. The Marketplace, it seems, uses the one from the manifest - can someone please confirm this?
The real question is - how do I retrieve the one from manifest programmatically to display on the About screen?
The WmAppManifest.xml number is in use. First two digits are relevant for Marketplace (it is checked when you do the update) next two are for your internal usage.
This is a regular XML file, open it as a XDocument and parse it. An example.
EDIT: the example is extraneous. For just the version, use:
string Version = XDocument.Load("WMAppManifest.xml")
.Root.Element("App").Attribute("Version").Value;
To get App Version from "WMappManifest.xml", this solution might be a bit more efficient than lukas solution:
For WP7:
var xmlReaderSettings = new XmlReaderSettings
{
XmlResolver = new XmlXapResolver()
};
using (var xmlReader = XmlReader.Create("WMAppManifest.xml", xmlReaderSettings))
{
xmlReader.ReadToDescendant("App");
return xmlReader.GetAttribute("Version");
}
For WP8:
using (var stream = new FileStream("WMAppManifest.xml", FileMode.Open, FileAccess.Read))
{
string appVersion = XElement.Load(stream).Element("App").Attribute("Version").Value;
}

Including DirectShow library into Qt for video thumbnail

I'm trying to implement http://msdn.microsoft.com/en-us/library/dd377634%28v=VS.85%29.aspx on Qt, to generate a poster frame/thumbnail for video files.
I have installed both Windows Vista and Windows 7 SDK. I put:
#include "qedit.h"
in my code (noting there is also one in C:\Qt\2010.04\mingw\include), I add:
win32:INCLUDEPATH += $$quote(C:/WindowsSDK/v6.0/Include)
to my *.pro file. I compile and get " error: sal.h: No such file or directory". Finding this in VC++ I add
win32:INCLUDEPATH += $$quote(C:/Program Files/Microsoft Visual Studio 10.0/VC/include)
And now have 1400 compile errors. So, I abandon that and just add:
win32:LIBS += C:/WindowsSDK/v7.1/Lib/strmiids.lib
to my *.pro file and try to run (without including any headers):
IMediaDet mediadet;
But then I get "error: IMediaDet: No such file or directory".
#include "qedit.h"
gives me the same error (it looks like it's pointing to the Qt version) and
#include "C:/WindowsSDK/v6.0/Include/qedit.h"
goes back to generating 1000's of compile errors.
Sigh, so much trouble for what should be 10 lines of code...
Thanks for your comments and help
Since you say you are "a C++/Qt newbie" then I suspect that the real issue may be that you are attempting to load the library yourself rather than simply linking your application to it?
To link an external library into your application with Qt all you need to do is modify the appropriate .pro file. For example if the library is called libfoo.dll you just add
LIBS += -L/path/to/lib -lfoo
You can find more information about this in the relevant section of the qmake manual. Note that qmake commonly employs Unix-like notation and transparently does the right thing on Windows.
Having done this you can include the library's headers and use whatever classes and functions it provides. Note that you can also modify the project file to append an include path to help pick up the headers eg.
INCLUDEPATH += /path/to/headers
Again, more information in the relevant section of the qmake manual.
Note that both these project variables work with relative paths and will happily work with .. to mean "go up a directory" on all platforms.
Note that qedit.h requires dxtrans.h, which is part of DirectX9 SDK.
You can find dxtrans.h in DirectX SDK from August 2006. Note that dxtrans.h is removed from newer DirectX SDKs.
Do you have access to the source of the external library? The following assumes that you do.
What I do when I need to extract a class from a library with only functions resolved, is to use a factory function in the library.
// Library.h
class SomeClass {
public:
SomeClass(std::string name);
// ... class declaration goes here
};
In the cpp file, I use a proxy function outside the extern "C" when my constructor requires C++ parameters (e.g. types such as std::string), which I pass as a pointer to prevent the compiler from messing up the signature between C and C++. You can avoid the extra step if your constructor doesn't require parameters, and call new SomeClass() directly from the exported function.
// Library.cpp
#include "Library.h"
SomeClass::SomeClass(std::string name)
{
// implementation details
}
// Proxy function to handle C++ types
SomeClass *ImplCreateClass(std::string* name) { return new SomeClass(*name); }
extern "C"
{
// Notice the pass-by-pointer for C++ types
SomeClass *CreateClass(std::string* name) { return ImplCreateClass(name); }
}
Then, in the application that uses the library :
// Application.cpp
#include "Library.h"
typedef SomeClass* (*FactoryFunction)(std::string*);
// ...
QLibrary library(QString("MyLibrary"));
FactoryFunction factory = reinterpret_cast(library.resolve("CreateClass"));
std::string name("foobar");
SomeClass *myInstance = factory(&name);
You now hold an instance of the class declared in the library.

Convert a Visual Studio resource file to a text file?

I know there are tools to get text files to resource files for Visual Studio. But I want to get the text from my resource files to a text file so they can be translated. Or is there a better way to do this?
You could use Resx Editor, a small translation-oriented file editor.
Target audience: translators.
Supported file format: Microsoft RESX 2.0
Here is a link to Joannès Vermoel's (the author of the free tool) weblog entry about it.
In the end I just used a quick hack:
public class Export
{
public string Run()
{
var resources = new StringBuilder();
var assembly = Assembly.GetExecutingAssembly();
var types = from t in assembly.GetTypes()
where t != typeof(Export)
select t;
foreach (Type t in types)
{
resources.AppendLine(t.Name);
resources.AppendLine("Key, Value");
var props = from p in t.GetProperties()
where !p.CanWrite && p.Name != "ResourceManager"
select p;
foreach (PropertyInfo p in props)
{
resources.AppendFormat("\"{0}\",\"{1}\"\n", p.Name, p.GetValue(null));
}
resources.AppendLine();
}
return resources.ToString();
}
}
Add this code to the project which contains your.resx files (mine are in a separate "Languages" project) then use the following code to save the result into a .csv so that it can be loaded with a spreadsheet editor.
var hack = new Languages.Export();
var resourcesSummary = hack.Run();
var cultureName = System.Threading.Thread.CurrentThread.CurrentCulture.Name;
using (TextWriter file = File.CreateText(#"C:\resources." + cultureName + ".csv"))
{
file.Write(resourcesSummary);
}
This does not allow you to import files from the .csv back to your .resx files so that they can be compiled. It would be nice to have a utility that would do that.
You can use Simple Resx Editor, it has some interesting features that will help you into the translation process.
Even though it is counter intuitive, it's a better idea to translate the exe rather than the resource file. Read why here:
http://www.apptranslator.com/misconceptions.html
You may want to have a look at Excel Resource Transfer. It is
an Add-In for Microsoft Excel to import and export texts from resource files.
There is a trial version. The full version costs 25,- Euro.
If you're doing this for a web project, a better way to do internationalization (including translation) is to use the i18n nuget package. Not only does work better with templates but it has other nice-to-haves like localized URLs.
Here's an example from the github repo:
<div id="content">
<h2>[[[Welcome to my web app!]]]</h2>
<h3><span>[[[Amazing slogan here]]]</span></h3>
<p>[[[Ad copy that would make Hiten Shah fall off his chair!]]]</p>
<span class="button" title="[[[Click to see plans and pricing]]]">
<a href="#Url.Action("Plans", "Home", new { area = "" })">
<strong>[[[SEE PLANS & PRICING]]]</strong>
<span>[[[Free unicorn with all plans!]]]</span>
</a>
</span>
</div>
Running a post-build task generates a PO database that can be provided to translators that use PO editing tools (like POEdit) to provide locale-specific text.
You could use winres.exe from Microsoft, it lets you localize windows forms without having to use Visual Studio. It doesn't save the resources to a text file, but the idea is that the localization expert for each culture could use the tool to generate a localized versions of the application.
Here's a better explanation:
http://msdn.microsoft.com/en-us/library/8bxdx003(VS.80).aspx

Resources