I'm currently developing a Xamarin.iOS App that gets a document from a web service that should then be edited offline on the tablet after being downloaded to the internal storage.
The most common answer was to use the UIDocumentInteractionController. However if I use the UIDocumentInteractionController then I can only create a copy of my original file and open this copy. To get it back into my app I have to make the user select the document from the 'UIDocumentPickerViewController'.
Is there a better way to make the `UIDocumentInteractionController' not create and open a copy of the original, or to at least get the url from the new documentcopy?
Code to open the file:
public void OpenFile()
{
var url = NSUrl.FromFilename(FilePath);
var controller = new UIDocumentInteractionController();
controller.Url = url;
controller.PresentOpenInMenu(table.Frame, table, true);
}
If that is not Possible: Are there different tools or controlls i could use to open and edit a MS-Office file directly?
Related
public void Save_Token(string _Token)
{
var Token_Location = #".\token.txt";
using (StreamWriter sw = new StreamWriter(Token_Location))
{
sw.WriteLine(_Token);
}
}
I tried to get the token from the api (json) and I deserialized and saved it. I would like to write to the file to save for later. But I want this application to be ran on anyone's PC. So I don't want to use the full path.
I also tried
Path.Combine(Environment.CurrentDirectory,Token_Location);
still nothing is written, unless I use the full path.
You can't guarantee that the current user has write access to the folder from where the file is executed. There is a special folder (APP_DATA) that applications are supposed to use when storing user data on a computer:
public void Save_Token(string _Token)
{
var tokenDirectory = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "YourCompanyOrOrganizationName");
var tokenFile = Path.Combine(tokenDirectory, "token.txt");
Directory.CreateDirectory(tokenDirectory);
File.WriteAllText(tokenFile, _Token);
}
Your file will then be stored in a path like "C:\Users\yourusername\AppData\Roaming\YourCompanyOrOrganizationName\token.txt"
It is generally a bad idea to use a relative path in software source code because the "current working directory" of the process that the relative path is relative to can change over the runtime of the application.
Activities like showing a file open dialog or using a third-party component can unexpectedly change the current working directory so that it is dangerous to assume a certain current working directory.
I'm using Xamarin iOS. I'd like to have our application open a .pdf file in the default reader. For Android I managed to get it done by following a two-fold process: (1) copy the file from the Assets folder to the Android device's Downloads folder, and (2) starting an activity to view the file.
I cannot find any similar resources for the iOS. We don't want to use the control in the Xamarin website, as it involves downloading lots of JavaScript (?) code, making the size of the app bigger, and also doesn't support pinching the screen to zoom. We want to use the OS's default pdf reader.
Thank you.
Method 1:
Set the Build Action to BundleResource. You can set the build action for a file by right-clicking on that file and and choosing Build Action in the menu that opens.
Create a UIWebView and add it to a view:
webView = new UIWebView (View.Bounds);
View.AddSubview(webView);
Load the file using NSUrl and NSUrlRequest classes:
string fileName = "Loading a Web Page.pdf"; // remember case-sensitive
string localDocUrl = Path.Combine (NSBundle.MainBundle.BundlePath, fileName);
webView.LoadRequest(new NSUrlRequest(new NSUrl(localDocUrl, false)));
webView.ScalesPageToFit = true;
Method 2:
public void OpenFile (NSUrl fileUrl)
{
var docControl = UIDocumentInteractionController.FromUrl (fileUrl);
var window = UIApplication.SharedApplication.KeyWindow;
var subViews = window.Subviews;
var lastView = subViews.Last ();
var frame = lastView.Frame;
docControl.PresentOpenInMenu (frame, lastView, true);
}
Windows API Code Pack for Microsoft can be downloaded from here. That is a really nice library and it has great examples. For example if I open the solution WindowsAPICodePack10 that comes in the zip from downloading the code pack (it only contains the libraries I added a win forms and wpf application)
then I am able to use the library very easily for example in my wpf application I can drag:
ExplorerBrowser user control (note I have to add references to the libraries that came with the solution)
and then with a button I can populate that control with this lines of code:
// Create a new CommonOpenFileDialog to allow users to select a folder/library
CommonOpenFileDialog cfd = new CommonOpenFileDialog();
// Set options to allow libraries and non filesystem items to be selected
cfd.IsFolderPicker = true;
cfd.AllowNonFileSystemItems = true;
// Show the dialog
CommonFileDialogResult result = cfd.ShowDialog();
// if the user didn't cancel
if (result == CommonFileDialogResult.Ok)
{
// Update the location on the ExplorerBrowser
ShellObject resultItem = cfd.FileAsShellObject;
explorerBrowser1.NavigationTarget = resultItem;
//explorerBrowser1.Navigate(resultItem);
}
and after that I am able to have something like:
That is amazing but I don't understand Microsoft. If they give you those libraries they should make it easy to customize that user control. the reason why I downloaded those libraries is because I need to place files from a specific directory on a stackpanel and be able to have the same functionality that you get with files on explorer (able to drag files, get context menu when right clicking file, dropping files to that container etc)
anyways I don't need all that functionality. from studing the library I think that user control contains a ShellContainer object and it's childern are ShellFiles maybe.
So from this library I will like to create a ShellFile object and place it in a StackPanel. after tedious studing of the library I finally found out how to instantiate an object from shellFile (ShellFile class is abstract) :
string filename = #"C:\Program Files (x86)\FileZilla FTP Client\filezilla.exe"; \\random file
ShellFile shellFile = ShellFile.FromFilePath(filename);
now it will be nice if I could place that file in a container. I am not able to instantiate a ShellConteiner object becaue it is abstract too. so how Will I bee able to place that shell file on a canvas for example?
or maybe I could extract the properties that I need and create a user control that will represent a shellFile. I know how to get the thumbnail I can do something like:
string filename = #"C:\Program Files (x86)\FileZilla FTP Client\filezilla.exe";
ShellFile shellFile = ShellFile.FromFilePath(filename);
System.Drawing.Bitmap btm = shellFile.Thumbnail.ExtraLargeBitmap;
I am having an xml file like:
<CurrentProject>
// Elements like
// last opened project file to reopen it when app starts
// and more global project independend settings
</CurrentProject>
Now I asked myself wether I should deliver this xml file with above empty elements with the installer for my app or should I create this file on the fly on application start if it does not exist else read the values from it.
Consider also that the user could delete this file and that should my application not prevent from working anymore.
What is better and why?
UPDATE:
What I did felt ok for me so I post my code here :) It just creates the xml + structure on the fly with some security checks...
public ProjectService(IProjectDataProvider provider)
{
_provider = provider;
string applicationPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
_projectPath = Path.Combine(applicationPath,#"TBM\Settings.XML");
if (!File.Exists(_projectPath))
{
string dirPath = Path.Combine(applicationPath, #"TBM");
if (!Directory.Exists(dirPath))
Directory.CreateDirectory(dirPath);
using (var stream = File.Create(_projectPath))
{
XElement projectElement = new XElement("Project");
projectElement.Add(new XElement("DatabasePath"));
projectElement.Save(stream, SaveOptions.DisableFormatting);
}
}
}
In a similar scenario, I recently went for creating the initial file on the fly. The main reason I chose this was the fact that I wasn't depending on this file being there and being valid. As this was a file that's often read from/written to, there's a chance that it could get corrupted (e.g. if the power is lost while the file is being written).
In my code I attempted to open this file for reading and then read the data. If anywhere during these steps I encountered an error, I simply recreated the file with default values and displayed a corresponding message to the user.
I start my application from withint Visual Studio 2010.
I add then some files into my application and each file type`s icon like icon from doc,docx,xls,pdf etc are added as String/Bitmap key/value pair to my IconImages.Resx file via
private void DumpTempResourceToRealResourceFile(IDictionary<String, Bitmap> tempResource)
{
using (ResXResourceWriter writer = new ResXResourceWriter("IconImages.Resx"))
{
foreach (KeyValuePair<String,Bitmap> item in tempResource)
{
writer.AddResource(item.Key, item.Value);
}
writer.Generate();
}
}
When the icons are added to the resource I close the application.
Then I start my application again with VS 2010 and add some files within my document application. The file types are written again to my IconImages.Resx.
Then I close my application and check the IconImages.Resx file under the \bin\ folder and the previous saved images are gone and I have new/different ones now.
Why can I not say OPEN a .resx file and append stuff to it? Everytime I create a ResourceWriter object with the same name "IconImages.Resx" I overwrite the previous added stuff and thats stupid.
How can my IconImages.Resx file stay alive over an application session without being overwritten by other stuff I add?
I haven't used ResXResourceWriter, but usually *Writer classes simply write a data file from scratch.
If you want to "append" new data you would typically have to use a *Reader class to deserialise the existing data into memory, then merge/add in any new data you wish to, and use a *Writer object to then write the resulting data back out. Take a look at ResXResourceReader to see if it supports what you need to do this.
I am having now a lookup table "FiletypeImage" with the filetype ".docx" and the raw binary data aka blob. This table gets retrieved in my documentService and cached in a static variable. with a Get and Add method which are called by my DocumentListViewModel. Its very fast thx to sqlite :)