I write a Windows 10 Universal App like the default Photo App in C#. The Photo App allows to show all images in the directory where the user opened the file with the Photo App. But when the user opened a file with my App I get only the FileActivatedEventArgs with allows to display the file the user opened. I found no solution to show the user the other files from the directory of this file too. I think the problem is to get the permission to access that files because when the folder of the file is in the picture library it works. But the Windows Photo App can this everywhere so I think there must be a solution ...
Edit: I have tried to extract a very simple sample code from my project that show the relevant part in only a few lines of code
public static async Task<BitmapImage> LoadImage(StorageFile file)
{
BitmapImage bitmapImage = new BitmapImage();
FileRandomAccessStream stream = (FileRandomAccessStream)await file.OpenAsync(FileAccessMode.Read);
bitmapImage.SetSource(stream);
return bitmapImage;
}
private async void setImages(FileActivatedEventArgs args)
{
StorageFile si = (StorageFile)App.args.Files.First();
StorageFolder st = await si.GetParentAsync();
StorageApplicationPermissions.FutureAccessList.Add(st);
IReadOnlyList<StorageFile> sflist = await st.GetFilesAsync();
foreach (StorageFile sf in sflist)
{
imageList.Add(await LoadImage(sf));
}
}
Yes, you have NO access rights for the folder. In this case, GetParentAsync() may fall.
You should use "IFileActivatedEventArgsWithNeighboringFiles" to parse the neighboring files. By using this interface, OS's File Broker process passed the neighboring files to you.
https://msdn.microsoft.com/en-us/library/windows/apps/windows.applicationmodel.activation.ifileactivatedeventargswithneighboringfiles
Note - This API was added from Win8.1. And, Win8.0 ver of Photo app can't show the neighboring files when it was activated by FileActivated. Win8.1 ver of Photo app may use this API.
You may need to add the following to the Package.appxmanifest file so you can access the Pictures Library then you should be able to get this to work:
<Capabilities>
<uap:Capability Name="picturesLibrary"/>
</Capabilities>
Related
I am struggling to create my first UWP program in C#. I have run into a problem with reading/writing .rtf files and have not been able to work out a solution nor find one in the forums.
My program is an application for reading and writing a daily journal. The daily journal entries are displayed and edited in a RichEditBox. Next to the RichEditBox is a CalendarDatePicker.
When the CalendarDatePicker value changes, the program creates a file name based on the CalendarDatePicker date. For example, if the CalendarDatePicker's value was 7/22/2018, my program would turn that into the following file name: "2018_7_22.rtf" and then assign that to a string named fileName.
All of the above is working as desired. Here is the problem I am having:
When the value of the CalendarDatePicker changes, the program is supposed to immediately load the .rtf file (if it exists) from storage into the RichEditBox. And, when I press the SAVE button, the program is
supposed to save the RichEditBox contents to storage. Both reading and writing the file is supposed to
use the name derived from the CalendarDatePicker value rather than opening up a picker for either
opening or saving the file.
I have not been able to find any documentation about how to read and write a .rtf file for the RichEditBox without using a picker. I do not want to use a picker because I want that the given journal entry can only be read or written according to the file name that is based on the current value of the CalendarDatePicker.
Here is what I am trying to do:
String filePath = Windows.Storage.ApplicationData.Current.LocalFolder.toString;
// this returns error: "cannot convert method group 'ToString' to non-delegate type string"
String fileName = "2018_22_7.rtf"
// this is an example of a string my program would create according to the CalendarDatePicker's value.
At the end of my question is the code from the RichEditBox documentation. I want do away with the portion that uses the picker and replace the following line:
Windows.Storage.StorageFile file = await savePicker.PickSaveFileAsync();
with:
Windows.Storage.StorageFile file = filePath + fileName;
Is it possible to do this or am I forced to use a picker with the RichEditBox?
I will deeply appreciate any help I can get in solving this problem. I am
melting from frustration! Thank you!
Here is the code from the RichEditBox documentation:
private async void SaveButton_Click(object sender, RoutedEventArgs e)
{
Windows.Storage.Pickers.FileSavePicker savePicker = new Windows.Storage.Pickers.FileSavePicker();
savePicker.SuggestedStartLocation = Windows.Storage.Pickers.PickerLocationId.DocumentsLibrary;
// Dropdown of file types the user can save the file as
savePicker.FileTypeChoices.Add("Rich Text", new List<string>() { ".rtf" });
// Default file name if the user does not type one in or select a file to replace
savePicker.SuggestedFileName = "New Document";
Windows.Storage.StorageFile file = await savePicker.PickSaveFileAsync();
if (file != null)
{
// Prevent updates to the remote version of the file until we
// finish making changes and call CompleteUpdatesAsync.
Windows.Storage.CachedFileManager.DeferUpdates(file);
// write to file
Windows.Storage.Streams.IRandomAccessStream randAccStream =
await file.OpenAsync(Windows.Storage.FileAccessMode.ReadWrite);
editor.Document.SaveToStream(Windows.UI.Text.TextGetOptions.FormatRtf, randAccStream);
// Let Windows know that we're finished changing the file so the
// other app can update the remote version of the file.
Windows.Storage.Provider.FileUpdateStatus status = await Windows.Storage.CachedFileManager.CompleteUpdatesAsync(file);
if (status != Windows.Storage.Provider.FileUpdateStatus.Complete)
{
Windows.UI.Popups.MessageDialog errorBox =
new Windows.UI.Popups.MessageDialog("File " + file.Name + " couldn't be saved.");
await errorBox.ShowAsync();
}
}
}
Universal Windows Apps (apps) can access certain file system locations by default.
Before window version 17134, if you don't want use a picker to access the file, your UWP app only can access the files in the Application install directory, Application data locations, Removable devices and some Locations that UWP apps can access with specific Capability such as the Music and Pictures Libraries. But you can not write into the Application install directory. In this case, you can try to save the file in above location except the Application install directory. Such as the Application data locations then you can create and get the file using the following code. Please see the File access permissions for more details.
StorageFolder localFolder = ApplicationData.Current.LocalFolder;
//Createa file
StorageFile fileToSave = await localFolder.CreateFileAsync("YourFileName");
//Get file
StorageFile file = await localFolder.GetFileAsync("YourFileName");
If your app target on version 17134 and later, you can access all files that the user has access to using the broadFileSystemAccess Capability, this capability works for APIs in the Windows.Storage namespace, you can get the file using the path as following code, here is a sample.
StorageFolder folder = await StorageFolder.GetFolderFromPathAsync(path);
FileOpenPicker picker = new FileOpenPicker();
picker.ViewMode = PickerViewMode.Thumbnail;
picker.SuggestedStartLocation = PickerLocationId.ComputerFolder;
picker.FileTypeFilter.Add(".txt");
A user chooses a file to open. How can I store/copy/save that file to localstorage for future use, so every time the app opens, it picks automatically that file?
After the user opens the file using the FileOpenPicker you can "cache" access to it using StorageApplicationPermissions API.
Once you have the StorageFile you want to open automatically, you can "cache" your access to it using the following code:
string token = StorageApplicationPermissions.FutureAccessList.Add( file );
What you get back is a string token, which you can save for example in the app settings. Next time the app is opened, you can retrieve the file again using the following code:
StorageFile file =
await StorageApplicationPermissions.FutureAccessList.GetFileAsync(token);
Note that this API has limitation of at most 1000 items stored, so if you expect that more could be added, you will have to ensure the older files are removed otherwise you would not be able to add new files.
There is also alternative - StorageApplicationPermissions.MostRecentlyUsedList which you can use the same way as the FutureAccessList, but it has the advantage of automatically managing the list. It can store up to 25 items, but it is able to automatically remove the oldest ones when not needed anymore.
Also note, that this APIs can cache access not only to files but also to folders (StorageFolder).
Copying the file to AppData folder
If you just want to create a local copy of the picked file, you can copy it to the local folder of the app.
var file = await picker.PickSingleFileAsync();
if ( file != null )
{
await file.CopyAsync( ApplicationData.Current.LocalFolder );
}
StorageFile file = await openPicker.PickSingleFileAsync();
if (file != null)
{
var yourPath = file.Path;
}
but It won't work as you expect. But remember you can't open file from location you (your app) don't have access to.
edit: yeah, I see in comments that I have missed some part of the qestion ;)
the easiest way to store the information for future re-use would be propably to use LocalSettings
https://msdn.microsoft.com/library/windows/apps/windows.storage.applicationdata.localsettings.aspx
(sorry for the link, but there is no use in copying info from there)
You could:
1) Store the file name in your project settings;
YourNameSpace.Properties.Settings.fileToLoad;
2) write the file name in a local file (look at TextWriter namespace);
3) store the file name in your database if your application is data-driven
... and others.
I am presuming here that you're using WinForms or Console app. If you are using a webForm, you would need to store the file name in a cookie so you could attach the right file to the right user before they log in or give you credenstials. For Webforms, then, look into the use of cookies.
Just to add to the above suggestions, following example from Official Microsoft document shows how to Store file for future access:
var openPicker = new FileOpenPicker();
StorageFile file = await openPicker.PickSingleFileAsync();
// Process picked file
if (file != null)
{
// Store file for future access
Windows.Storage.AccessCache.StorageApplicationPermissions.FutureAccessList.Add(file);
}
else
{
// The user didn't pick a file
}
This is really annoying problem and it's going to drive me mad. I like to read information such like files, directories ect. but my app cannot find anything OUTSIDE its folder it runs in.
I'm using Visual Studio 2015 and developing Windows Universal apps.
This routine under works very well if I change the directory inside the folder my app run like "Assets" and any other folder. But outside of my app folder result is zero, not even any errors :-(
Ok, Here is the simple code, What I Do Wrong?
private void GetThem_Click(object sender, RoutedEventArgs e)
{
string myDir = #"c:\mydir\";
string[] files;
files = Directory.GetFiles(myDir,"*.jpg");
foreach (string stuff in files)
{
RESULT.Text = RESULT.Text + stuff + " , ";
}
}
A quick search would have given you the answer : It is not possible to access the file system like a classic desktop app. The answer of #Rico Suter explain you what you can acces and how :
Directories which are declared in the manifest file (e.g. Documents, Pictures, Videos folder)
Directories and files which the user manually selected with the FileOpenPicker or FolderPicker
Files from the FutureAccessList or MostRecentlyUsedList
Files which are opened with a file extension association or via sharing
Once a file is picked by the user, you can add it to MostRecentlyUsedList or FutureAccessList to use it again later using this snippet (C#) from MSDN :
StorageFile file = await savePicker.PickSaveFileAsync();
if (file != null)
{
// Add to MRU with metadata (For example, a string that represents the date)
string mruToken = Windows.Storage.AccessCache.StorageApplicationPermissions.MostRecentlyUsedList.Add(file, "20120716");
// Add to FA without metadata
string faToken = Windows.Storage.AccessCache.StorageApplicationPermissions.FutureAccessList.Add(file);
}
Then store the retrieved token because you will need it to access the file using GetFileAsync(token)
I'm trying to play songs from a local machine by using the directory path to the song.
MediaElement.Source = new Uri(#"D:\Music\Artist\Album\Song.mp3", UriKind.Absolute);
Is this even possible to get to work or can Windows 8 apps only use URI schemes like mss-appx: to access package data?
When I try and run the code I get a message on the MediaElement control "Invalid Source"
Windows Store apps do not have full access to the file system. They can directly access (by path) only limited locations (i.e. their install and applicationdata folders).
The MediaElement can load items from paths it can directly access, but this is not generally useful since these locations have URIs (ms-appx: and ms-appdata:) which will target the right location regardless of what the actual Path is.
Typically songs are in the Music library, which the MediaElement cannot directly access. It can get brokered access through the MusicLibrary capability, but that doesn't allow access by path. The app will need to get to the file through the KnownFolders object:
private async void Button_Click(object sender, RoutedEventArgs e)
{
StorageFolder musicLib = Windows.Storage.KnownFolders.MusicLibrary;
StorageFile song = await musicLib.GetFileAsync(#"Artist\Album\Song.mp3");
var stream = await song.OpenReadAsync();
me.SetSource(stream, stream.ContentType);
}
If the song isn't in a library that can be permitted by capability then the user will need to grant permission through a FolderPicker or such. The user can pick the root of the music location and the app can cache that with the Windows.Storage.AccessCache classes so the user doesn't need to pick the folder multiple times or individually pick files.
I discuss this in more detail in my blog entry Skip the path: stick to the StorageFile
You need to use the file open picker to select a file in D drive.
FileOpenPicker openPicker = new FileOpenPicker();
openPicker.ViewMode = PickerViewMode.Thumbnail;
openPicker.SuggestedStartLocation = PickerLocationId.MusicLibrary;
openPicker.FileTypeFilter.Add(".mp3");
StorageFile file = await openPicker.PickSingleFileAsync();
IRandomAccessStreamWithContentType content = await file.OpenReadAsync();
Debug.WriteLine("Content Type: " + content.ContentType);
player.SetSource(content, content.ContentType);
This link has the answer (in case you can use the application folder)
MediaElement.Source = new Uri("ms-appx-web:///Assets/Song.mp3", UriKind.Absolute);
I am trying to open documents but getting error. How do I resolve it?
This is headache for me, Any kind of document is not opening in my application.
I am trying to open PDF file using "PDF Reader" but getting error like this:
"Unable to Open"
Please suggest me.
See my code below.
string file = "test.docx";
IsolatedStorageFile isf = IsolatedStorageFile.GetUserStoreForApplication();
if (isf.FileExists(file))
{
isf.DeleteFile(file);
}
var filerun = await ApplicationData.Current.LocalFolder.CreateFileAsync(file);
StorageFolder folder = ApplicationData.Current.LocalFolder;
StorageFile fileopen = await folder.GetFileAsync(file);
await Launcher.LaunchFileAsync(fileopen);
It seems that you are creating a totaly empty file and then try to open it with Word or PDFReader.
On Windows Phone you cannot open with Word an emty file just named filename.docx - try to create on computer a textfile file.txt, rename it to file.docx, copy to your phone, and then open via Files App - it won't work.
File extension only helps to determine the file type, but the most important is what is inside the file.
You should be able to open for example a file created with Word. Here is a sample example how I've done it - add a docx file (created for example on computer with Word) to your solution and change its Build Action to Content. Then try to open it like this:
private async void firstBtn_Click(object sender, RoutedEventArgs e)
{
StorageFolder folder = Windows.ApplicationModel.Package.Current.InstalledLocation;
StorageFile file = await folder.GetFileAsync("sample.docx");
await Launcher.LaunchFileAsync(file);
}
As I've tried - should work without problems. If you encounter some, here is a working sample.
Nothing also stands on your way to prepare some empty docx templates and then inside the app just copy as new files and open them. You may also try to find an API to create Office files.