Check if a file exists in the project in WinRT - windows-8

I have a WinRT Metro project which displays images based on a selected item. However, some of the images selected will not exist. What I want to be able to do is trap the case where they don't exist and display an alternative.
Here is my code so far:
internal string GetMyImage(string imageDescription)
{
string myImage = string.Format("Assets/MyImages/{0}.jpg", imageDescription.Replace(" ", ""));
// Need to check here if the above asset actually exists
return myImage;
}
Example calls:
GetMyImage("First Picture");
GetMyImage("Second Picture");
So Assets/MyImages/SecondPicture.jpg exists, but Assets/MyImages/FirstPicture.jpg does not.
At first I thought of using the WinRT equivalent of File.Exists(), but there doesn't appear to be one. Without having to go to the extent of trying to open the file and catching an error, can I simply check if either the file exists, or the file exists in the project?

You could use GetFilesAsync from here to enumerate the existing files. This seems to make sense considering you have multiple files which might not exist.
Gets a list of all files in the current folder and its sub-folders. Files are filtered and sorted based on the specified CommonFileQuery.
var folder = await StorageFolder.GetFolderFromPathAsync("Assets/MyImages/");
var files = await folder.GetFilesAsync(CommonFileQuery.OrderByName);
var file = files.FirstOrDefault(x => x.Name == "fileName");
if (file != null)
{
//do stuff
}
Edit:
As #Filip Skakun pointed out, the resource manager has a resource mapping on which you can call ContainsKey which has the benefit of checking for qualified resources as well (i.e. localized, scaled etc).
Edit 2:
Windows 8.1 introduced a new method for getting files and folders:
var result = await ApplicationData.Current.LocalFolder.TryGetItemAsync("fileName") as IStorageFile;
if (result != null)
//file exists
else
//file doesn't exist

There's two ways you can handle it.
1) Catch the FileNotFoundException when trying to get the file:
Windows.Storage.StorageFolder installedLocation =
Windows.ApplicationModel.Package.Current.InstalledLocation;
try
{
// Don't forget to decorate your method or event with async when using await
var file = await installedLocation.GetFileAsync(fileName);
// Exception wasn't raised, therefore the file exists
System.Diagnostics.Debug.WriteLine("We have the file!");
}
catch (System.IO.FileNotFoundException fileNotFoundEx)
{
System.Diagnostics.Debug.WriteLine("File doesn't exist. Use default.");
}
catch (Exception ex)
{
// Handle unknown error
}
2) as mydogisbox recommends, using LINQ. Although the method I tested is slightly different:
Windows.Storage.StorageFolder installedLocation =
Windows.ApplicationModel.Package.Current.InstalledLocation;
var files = await installedLocation.GetFilesAsync(CommonFileQuery.OrderByName);
var file = files.FirstOrDefault(x => x.Name == fileName);
if (file != null)
{
System.Diagnostics.Debug.WriteLine("We have the file!");
}
else
{
System.Diagnostics.Debug.WriteLine("No File. Use default.");
}

BitmapImage has an ImageFailed event that fires if the image can't be loaded. This would let you try to load the original image, and then react if it's not there.
Of course, this requires that you instantiate the BitmapImage yourself, rather than just build the Uri.

Sample checking for resource availability for c++ /cx (tested with Windows Phone 8.1):
std::wstring resPath = L"Img/my.bmp";
std::wstring resKey = L"Files/" + resPath;
bool exists = Windows::ApplicationModel::Resources::Core::ResourceManager::Current->MainResourceMap->HasKey(ref new Platform::String(resKey.c_str()));

Related

non-invocable member 'File' cannot be used like a method error message- what am I missing?

I have a Blazor Application which had files uploaded to a upload folder on the web server. I am in the process of trying to figure out the code to download an uploaded file in the browser for retrieval and viewing. Right now the code is as below (the download part from code examples on the internet)
public void FileDetailsToolbarClickHandler(Syncfusion.Blazor.Navigations.ClickEventArgs args)
{
string path = null;
string uploads = System.IO.Path.Combine(System.IO.Directory.GetCurrentDirectory(), "wwwroot\\uploads");
path = uploads + "\\" + SelectedFileName;
if (args.Item.Text == "Delete")
{
//Code for Deleting goes here
//UploadRef.Remove();
if (System.IO.File.Exists(path))
{
System.IO.File.Delete(path);
}
FileDetailsService.FileDetailsDelete(SelectedFileId); //NavigationManager.NavigateTo($"/ServiceRequestNotes/servicerequestnoteadd");
NavigationManager.NavigateTo($"/ServiceRequests/serviceRequestsaddedit2/{Id}", forceLoad: true);
}
else
{
// its a download
IFileProvider provider = new PhysicalFileProvider(uploads);
IFileInfo fileinfo = provider.GetFileInfo(path + SelectedFileName);
var readStream = fileinfo.CreateReadStream();
var mimeType = "application/pdf";
return File(readStream, mimeType, SelectedFileName);
}
}
On the last statement I am a getting the following error message
non-invocable member 'File' cannot be used like a method error message
What am I missing or do I need to change or add to have the output from the readstream render to the browser?
The blazor application is a blazor server app not WASM. It does not make use of API controllers.
Any advice?
This is a void method. You can't return anything at all. Also, if you're trying to instantiate a File object, you'd have to use the new keyword.

Exception when listing created sub-directory in documents directory

I am using the official API to list a directory I had created for some purpose and have pushed few files into it. Now I want to list them out.
Here's how I am creating first
final Directory extDir = await getApplicationDocumentsDirectory();
// final String dirPath = '${extDir.path}/Movies/flutter_test';
final String dirPath = '${extDir.path}/mydir';
await new Directory(dirPath).create(recursive: true);
Here's what I am doing to read in a different page.
final Directory extDir = await getApplicationDocumentsDirectory();
// final String dirPath = '${extDir.path}/Pictures/flutter_test';
final String dirPath = '${extDir.path}/mydir';
final String thumbDirPath = '$dirPath/thumbs';
final Directory imgDir = Directory.fromUri(Uri.file(dirPath));
dirExists = imgDir.existsSync();
fileCount = 0;
if(dirExists) {
print("my dir exists");
// thumbDir.list(recursive: false, followLinks: false)
fileCount = await imgDir.list(recursive: false).length;
print('mydir images count $fileCount');
if(fileCount > 1) { // we think one is always the directory itself?
try {
imgDir.list(recursive: false, followLinks: false)
.listen((FileSystemEntity entity) {
The code breaks here giving the following exception message
type '() => Null' is not a subtype of type '(Object) => FutureOr<dynamic>'
I have to also tell you this doesn't happen when I am listing the external storage directory. Am I doing something wrong while creating my directory?
EDIT
I have now upgraded flutter to 0.7.3 on my Mac, and have a new problem altogether. The application won't run at all.
Okay, I found a solution myself. Apparently tinkering with the large provider API has given me different way to list the items, which actually told me I was trying to run listeners twice.
fileCount = await imgDir.list(recursive: false).length;
and
imgDir.list(recursive: false, followLinks: false)
.listen((FileSystemEntity entity) {
from original code cannot be written one after the other, as the first one finishes the listener. This I found out by altering my own code and listing directories this way instead.
Stream<FileSystemEntity> files = imgDir.list(recursive: false, followLinks: false);
will add as many events as many files according to API.. and then create a regular generic list
List<FileSystemEntity> entities = await files.toList();
and then you perform usual iteration using iterator or for() loop like
for(FileSystemEntity entity in entities) {
... // every file now is available

UWP App: `Image.SetSource` hangs computer on `StorageFiles` outside of `KnownPlaces`

This one is hard to explain, so I give you some actual and pseudo code:
try
{
// If source (a string) points towards a file that is available with
// StorageFile.GetFileFromPathAsync(), just open the file that way.
// If that is not possible, use the path to look up an Access Token
// and use the file from the StorageFolder gotten via that token.
StorageFile file = await GetFileFromAccessList(source);
if (file != null)
{
bitmap = new BitmapImage();
using (IRandomAccessStream fileStream = await file.OpenAsync(FileAccessMode.Read))
{
await bitmap.SetSourceAsync(fileStream);
}
}
}
catch (Exception e)
{
string s = e.Message;
bitmap = null;
}
with the following method:
public async Task<StorageFile> GetFileFromAccessList(string path)
{
StorageFile result = null;
if (String.IsNullOrEmpty(path) == false)
try
{
// Try to access to file directly...
result = await StorageFile.GetFileFromPathAsync(path);
}
catch (Exception)
{
result = null;
try
{
// See if the folder this thing is in is in the access list...
StorageFolder folder = await GetFolderFromAccessList(Path.GetFullPath(path));
// If there is a folder, try that.
if (folder != null)
result = await folder.GetFileAsync(Path.GetFileName(path));
}
catch (Exception)
{
result = null;
}
}
return result;
}
The resulting bitmap is used in Image.SetSource() as an ImageSource.
Now what kills me: this call works perfectly, fast and rock solid for files stored within the apps folder or KnownFolders. So it works like a charm when I don't need an Access Token. Windows.Storage.AccessCache.StorageApplicationPermissions.FutureAccessList.GetFolderAsync(token)
However, it breaks if I have to use an access token, just not all the time
This code does not break immediately: it breaks when I try to open more than 5-7 source files at the same time.
Repeat that: this works if I display 5-7 images. If I try to open more, it freezes the PC. No such problem occurs when I open StorageFiles without tokens.
I can access such files using normal file operations. I can create bitmaps from them, process them, the work.
I just cannot make them a source of an XAML Image.
Any thoughts?
Ah clarity.
So it turns out that using the DataContextChanged event to refresh the bitmap through Image.SetSource() is the murder weapon.
The solution: declare a property of type BitmapSource. Bind the Image.Source to that property. Update the property with the loaded bitmap upon Image.Loaded and Image.DataContextChanged. Works stable and fast now in all conditions I was able to test.

How to Read a pre-built Text File in a Windows Phone Application

I've been trying to read a pre-built file with Car Maintenance tips, there's one in each line of my "Tips.txt" file. I've tried to follow around 4 or 5 different approaches but It's not working, it compiles but I get an exception. Here's what I've got:
using (IsolatedStorageFile store = IsolatedStorageFile.GetUserStoreForApplication())
{
using (StreamReader sr = new StreamReader(store.OpenFile("Tips.txt", FileMode.Open, FileAccess.Read)))
{
string line;
while ((line = sr.ReadLine()) != null)
{
(App.Current as App).MyTips.Insert(new DoubleNode(line));
}
}
}
I'm getting this "Operation not permitted on IsolatedStorageFileStream", from the info inside the 2nd using statement. I tried with the build action of my "Tips.txt" set to resource, and content, yet I get the same result.
Thanks in advance.
Since you've added it to your project directory, you can't read it using Isolated Storage methods. There are various ways you can load the file. One way would be to set the text file's build type to Resource, then read it in as a stream:
//Replace 'MyProject' with the name of your XAP/Project
Stream txtStream = Application.GetResourceStream(new Uri("/MyProject;component/myTextFile.txt",
UriKind.Relative)).Stream;
using(StreamReader sr = new StreamReader(txtStream))
{
//your code
}

How do I use Sitecore.Data.Serialization.Manager.LoadItem(path,LoadOptions) to restore a item to Sitecore?

I am trying to use the sitecore API to serialize and restore sitecore items. I have created a WCF app to retrieve an Item name given a ID or sitecore path (/sitecore/content/home), retrieve a list of the names of the items children give an id or path. I can also Serialize the content tree.
public void BackupItemTree(string id)
{
Database db = Sitecore.Configuration.Factory.GetDatabase("master");
Item itm = db.GetItem(id);
Sitecore.Data.Serialization.Manager.DumpTree(itm);
}
The above code works great. After running it can see that the content tree has been serialized.
However when I try to restore the serialized items useing the following:
public void RestoreItemTree(string path)
{
try
{
using (new Sitecore.SecurityModel.SecurityDisabler())
{
Database db = Sitecore.Configuration.Factory.GetDatabase("master");
Data.Serialization.LoadOptions opt = new Data.Serialization.LoadOptions(db);
opt.ForceUpdate = true;
Sitecore.Data.Serialization.Manager.LoadItem(path, opt);
//Sitecore.Data.Serialization.Manager.LoadTree(path, opt);
}
}
catch (Exception ex)
{
throw ex;
}
}
With this code I get no errors. It runs, but if I check SiteCore it didn't do anything. I have tested using the Office Core example. The path I sent in, which might be the issue is:
C:\inetpub\wwwroot\sitecoretest\Data\serialization\master\sitecore\content\Home\Standard-Items\Teasers\Our-Clients.item
and
C:\inetpub\wwwroot\sitecorebfahnestockinet\Data\serialization\master\sitecore\content\Home\Standard-Items\Teasers\Our-Clients
Neither seems to do anything. I changed the teaser title of the item and am trying to restore to before the but every time the change is still present.
Any help would be appreciated as the SiteCore documentation is very limited.
You can always check how the Sitecore code works using Reflector, the following method is called when you click "Revert Item" in back-end:
protected virtual Item LoadItem(Item item, LoadOptions options)
{
Assert.ArgumentNotNull(item, "item");
return Manager.LoadItem(PathUtils.GetFilePath(new ItemReference(item).ToString()), options);
}
In LoadOptions you can specify whether you want to overwrite ("Revert Item") or just update ("Update Item") it.
See Sitecore.Shell.Framework.Commands.Serialization.LoadItemCommand for more info.
You have the correct LoadOptions for forcing an overwrite (aka Revert).
I suspect that the path you are using for the .item file wrong. I would suggest modifying your method to take a path to a Sitecore item. Using that path, you should leverage other serialization APIs to determine where the file should be.
public void RestoreItemTree(string itemPath)
{
Sitecore.Data.Database db = Sitecore.Configuration.Factory.GetDatabase("master");
Sitecore.Data.Serialization.ItemReference itemReference = new Sitecore.Data.Serialization.ItemReference(db.Name, itemPath);
string path = Sitecore.Data.Serialization.PathUtils.GetFilePath(itemReference.ToString());
Sitecore.Data.Serialization.LoadOptions opt = new Sitecore.Data.Serialization.LoadOptions(db);
opt.ForceUpdate = true;
using (new Sitecore.SecurityModel.SecurityDisabler())
{
Sitecore.Data.Serialization.Manager.LoadItem(path, opt);
}
}
Took me a while to work out, but you have to remove .item when restoring the tree
try this
public void RestoreItemTree(string itemPath)
{
var db = Factory.GetDatabase("master");
var itemReference = new ItemReference(db.Name, itemPath);
var path = PathUtils.GetFilePath(itemReference.ToString());
if (!System.IO.File.Exists(path))
{
throw new Exception("File not found " + path);
}
var opt = new LoadOptions(db);
opt.ForceUpdate = true;
using (new SecurityDisabler())
{
Manager.LoadItem(path, opt);
Manager.LoadTree(path.Replace(".item", ""), opt);
}
}