Flip View Data Binding and file permissions - c#

I am learning the basics of UWP and app making in Windows 10.
I am trying to make a flip view with data that is pulled off a folder. It didn't display any images, so I tried manually adding images like so,
PrivateSet_images.Add(new BitmapImage(new Uri("ms-appx:///Assets/Spot/1.png")));
PrivateSet_images.Add(new BitmapImage(new Uri("ms-appx:///Assets/Spot/2.png")));
PrivateSet_images.Add(new BitmapImage(new Uri("ms-appx:///Assets/Spot/jpg.jpg")));
PrivateSet_images.Add(new BitmapImage(new Uri("ms-appx:///Assets/Spot/jpeg.jpeg")));
PrivateSet_images.Add(new BitmapImage(new Uri("ms-appx:///Assets/Spot/jpg.png")));
PrivateSet_images.Add(new BitmapImage(new Uri("ms-appx:///Assets/Spot/jpeg.png")));
PrivateSet_images.Add(new BitmapImage(new Uri("F:\\Test Sp Folder\\1.png")));
PrivateSet_images.Add(new BitmapImage(new Uri("F:/Test Sp Folder/1.png")));
All the ms-appx assets are read and displayed successfully (so not a file-type / file-extension problem). As for permissions to the folder, I used a folder picker to access a few files, so there are no permission issues (as described here). I checked the debugger, and the files are read properly, but the last two aren't displayed (which point to the same file, I wanted to make sure it wasn't the '/' or '\\' preventing them from being displayed.)
XAML Code:
<FlipView x:Name="FlipViwe" ItemsSource="{x:Bind ViewModel.Images}" Visibility="Visible">
<FlipView.ItemTemplate>
<DataTemplate>
<Image Source="{Binding}" Stretch="Fill"/>
</DataTemplate>
</FlipView.ItemTemplate>
</FlipView>
I don't seem to be able to solve this with solutions or similar questions like Bind a Collection as ItemsSource, Flipview not showing any pictures and Show image files from a directory in a Flipview
What am I missing?
Thank You.

The UWP apps do not have permission to access all files on the device. By default, apps can access certain file system locations such as application install directory or application data locations. For more info, please see File access permissions.
"F:\Test Sp Folder\1.png" is a location that you app can't directly access. While dealing with files or folders in UWP, one important rule is Skip the path: stick to the StorageFile.
It is recommend to use a Folder​Picker to let the user pick the folder and add it to your app's FutureAccessList or MostRecentlyUsedList, in this way the they can be reloaded later without requiring the user to go through the picker. For more information, please check: How to track recently-used files and folders.

Okay,
So with the answer form #Jayden, I managed to find a solution.
Here goes,
In a UWP app, using direct paths to files *may fail, reasons being either permissions, or the path being, as I like to put it, 'Virtual Directory'. One example is the Photos or the Music collection. All the files are populated and 'sent' to the requesting app. Also, the files may be from an another app. So storing the strings is pointless.
Protected view for files is provided by the StorageItems classes (i.e. StorageFolder and StorageFile). StorageItems are the canonical storage identifiers for Windows Store apps, not the path. Your life (and your app) will be easier if you think and work in terms of StorageItems rather than trying to convert back and forth between StorageItems and paths. A key property of the StorageFile is that it isn’t restricted to file system objects. For example, a StorageFile can represent a photo “file” the user selected from another app via the file picker contract . The app deals with the StorageFile and doesn’t need to know or care if the data originated on disk or in another app. Conversely, apps which demand to know where the data originated can run into trouble: the StorageFile may not have a Path or may have a non file-system path.
So to overcome that, one has to use StorageFile, that guarantees access to files (assuming you already have permissions to it). Also remember to store your access-permission!
The Windows.Storage.AccessCache namespace provides classes to remember StorageItems so they can be reloaded later without requiring the user to go through the picker. The StorageApplicationPermissions.FutureAccessList provides random access to items that have been previously used. The MostRecentlyUsedList allows keeping a list of recently used locations.
After going through multiple examples and countless trials, I hit upon the solution, which I realized is similar to a linked question.
public async void ImageViewGenerateAsync () {
var ImagesFolder = await StorageApplicationPermissions.
FutureAccessList.GetFolderAsync("FolderFoken");
var ImgFiles = await ImagesFolder.GetFilesAsync();
foreach( StorageFile file in ImgFiles ) {
if (file != null ) {
try {
var filestream = await file.OpenAsync(FileAccessMode.Read);
var img = new BitmapImage();
await img.SetSourceAsync (filestream);
PrivateSet_images.Add(img);
}
catch ( Exception ) {
}
}
}
It, instead of accessing the files through strings and Uri, uses StorageFile that handles giving the file to you. Then read the files through OpenAsync and set this stream as the source of the BitmapImage (Described here, scroll down to Using a stream source to show images from the Pictures library). I'm not sure of this is an optimized solution, but it works. I'd love to see if there is a better and optimized solution.
XAML:
<FlipView x:Name="FlipViweSpotlight" ItemsSource="{x:Bind ViewModel.Images}" Visibility="Visible">
<FlipView.ItemTemplate>
<DataTemplate>
<Image Source="{Binding}" Stretch="Uniform"/>
</DataTemplate>
</FlipView.ItemTemplate>
This is a rudimentary solution that I came up with, any improvements / optimizations would be welcome!
Thanks!

Related

Playing WPF music as a resource [duplicate]

I am trying to play a sound file in my WPF application. Currently I have the following call:
private void PlaySound(string uriPath)
{
Uri uri = new Uri(#"pack://application:,,,/Media/movepoint.wav");
var player = new MediaPlayer();
player.Open(uri);
player.Play();
}
Now if I specify Media/movepoint.wav as build action Content and load it as a relative or absolute file path it works fine, so I suspect this has something to do with the Pack URI, but I cannot for the life of me figure out what.
The objective is to store the file as a resource so that its not available in the output directory. I can provide either the WAV copy or the MP3 copy.
I tried this with an image file, which works the same as a sound file as far as the uri is concerned because it's just another resource. I used the code below which essentially matches what you have.
new Uri(#"pack://application:,,,/Resources/logo.png")
Make sure that your 'Media' folder is not nested in any other folder. If it is, you need to include that folder as well.
Using .NET Framework 4.0, VS2012.
This link gives a pretty good description of the whole "pack" scheme of things.
EDIT
More research on this topic seems to indicate that what you want to do might not be possible with audio or video files. The excerpt below is taken from the remarks section of this MSDN page.
Although you can declare an instance of this class in Extensible
Application Markup Language (XAML), you cannot load and play its media
without using code. To play media in XAML only, use a MediaElement.
Also, if you declare an instance in XAML, the only practical use is to
fill property element syntax for the Player property.
When distributing media with your application, you cannot use a media
file as a project resource. In your project file, you must instead set
the media type to Content and set CopyToOutputDirectory to
PreserveNewest or Always.
MediaPlayer can be used in two different modes, depending on what is
driving the player: independent mode or clock mode. In independent
mode, the MediaPlayer is analogous to an image and the media opened
through the Open method drives playback. In Clock mode, the
MediaPlayer can be thought of as a target for an animation, and thus
it will have corresponding Timeline and Clock entries in the Timing
tree which controls playback. For more information on media modes, see
the Multimedia Overview.
MediaPlayer is different from a MediaElement in that it is not a
control that can be added directly to the user interface (UI) of an
application. To display media loaded using MediaPlayer, a VideoDrawing
or DrawingContext must be used.
The following seems to work in .NET Framework 4.5:
var sri = Application.GetResourceStream(new Uri("pack://application:,,,/MyAssemblyName;component/Resources/CameraShutter.wav"));
if ((sri != null))
{
using (s == sri.Stream)
{
System.Media.SoundPlayer player = new System.Media.SoundPlayer(s);
player.Load();
player.Play();
}
}
CameraShutter.wav is embedded as Resource in my project (and resides inside Resources subfolder, as indicated in the pack URI).
You can also load a Stream into the SoundPlayer if the .wav file is an Embedded Resource. Note that in this example the resources are in a folder called Resources that is in the root of the project, that is why it is written {0}.Resources.{1}.
//the wav filename
string file = "emergency_alarm_002.wav";
//get the current assembly
var assembly = System.Reflection.Assembly.GetExecutingAssembly();
//load the embedded resource as a stream
var stream = assembly.GetManifestResourceStream(string.Format("{0}.Resources.{1}", assembly.GetName().Name, file));
//load the stream into the player
var player = new System.Media.SoundPlayer(stream);
//play the sound
player.Play();
This also seems to work and is maybe simpler to remember than that long line of pack or assembly stuff..
I opened the Resources.resx and dragged a sound file in there called aa_pickup.wav Then set the properties of it to Copy to Output Dir = Copy Always.
System.IO.Stream str = Properties.Resources.aa_pickup;
System.Media.SoundPlayer snd = new System.Media.SoundPlayer(str);
snd.Play();
Now.. if I could only work out how to change the volume.

Shortcut of universal app

I'm creating a Xamarin.Forms app and I want to have an option to create a Desktop shortcut (I already implemented on Android).
I have a protocol that I can use to launch my app, so this is not a concern, and I already saved another type of file in the Desktop to test, my only problem is that I can't create a .lnk file.
In my researches I saw a lot of explanations as to how to create a .lnk file programmatically, but all tutorials were related to WindowsForms or PowerShell scripts (as far as I know, UWP doesn't allow executing PS scripts).
So, is there a way of creating Desktop Shortcuts?
Edit after answer
When I create the shortcut using the Dialog, everything is fine, but when I create it in the app, the shortcut's icon doesn't change to my app's icon, it displays a confirmation when I run it and after I confirm, it displays an error message saying The target "" of this Internet Shortcut is not valid.
But if I change the file in any way (rename it, copy and paste it or change it's contents), it changes the icon to the correct one and when I confirm the dialog, it opens my app as expected. This proves that nothing is wrong with the file or its contents, but I don't know how to workaround this.
Edit
StorageFile shortcutFile = null;
try
{
shortcutFile = await ApplicationData.Current.LocalFolder.GetFileAsync("shortcut.url");
}
catch (Exception) { }
if (shortcutFile == null)
{
shortcutFile = await ApplicationData.Current.LocalFolder.CreateFileAsync("shortcut.tmp", CreationCollisionOption.ReplaceExisting);
await FileIO.WriteLinesAsync(shortcutFile, new string[] { "[InternetShortcut]", "URL=yourapp:///" });
string newShortcutName = shortcutFile.Path.Substring(0, shortcutFile.Path.Length - 4) + ".url";
File.Move(shortcutFile.Path, newShortcutName);
shortcutFile = await ApplicationData.Current.LocalFolder.GetFileAsync(newShortcutName.SplitWithoutEmpty('\\').Last());
}
FolderPicker savePicker = new FolderPicker
{
SuggestedStartLocation = PickerLocationId.Desktop
};
savePicker.FileTypeFilter.Add(".url");
StorageFolder folder = await savePicker.PickSingleFolderAsync();
if (folder != null)
{
// Works fine until here, then it throws an exception (Permission Denied)
await shortcutFile.CopyAsync(folder, shortcutFile.Name);
}
The Windows 10 alternative to desktop shortcut is a Live Tile, which is basically a live version of an Android icon. You can create a desktop shortuct by dragging the Live Tile to the desktop manually.
If you want a programmatic way and have already a registered URI protocol, you should be able to create a url shortcut instead of classic one. Let's see this step by step:
You can create a URL shortuct manually using the dialog:
Now this will create a .url file on your desktop, which behaves as a shortcut. You can see it in the listing of dir command:
Now try to rename the file to have a different extension using the ren command, for example:
ren YourApp.url YourApp.urltext
You can now open this file normally in a text editor to see its contents:
[{000352A0-0000-0000-C000-000000000012}]
Prop3=19,0
[InternetShortcut]
IDList=
URL=yourapp:///
From my testing it seems that the first two rows are unnecessary and the IDList property is also redundant. This means you can just do with the following:
[InternetShortcut]
URL=yourapp:///
If you rename the file back to have .url extension and double-click it, it will launch the app associated with the yourapp protocol, which is exactly what you need.
So to do this programmatically, you have to save a .url file with the contents we just came up with and save it where the user wants to have the shortcut created.
There is one disadvantage, that you have to keep in mind - UWP apps are sandboxed, so you cannot directly create files on desktop without the user's consent. The best approach I can see now is to use a FileSavePicker to let the user choose a folder where she wants to save the shortcut. It is still quite user friendly and it even gives her the flexibility to have the shortcut elsewhere than on the desktop.
Update
I have found this SO answer with an extremely detailed analysis of this problem. It thoroughly explains why we are hitting these problems - the URL files are interpreted by Internet Explorer and once interpreted, the URL info is stored as NTFS metadata. I would suggest creating the file with a temporary extension first and only then rename it to .url. I am not at my computer right now, but I will try when I get there :-)
Update 2
After some playing I have come up with the following and it "partially works on my PC". The shortcut is successfully created and even has the right icon, BUT each time it is opened it shows the "file from different computer" confirmation dialog, which can be turned off only through Properties.
FileSavePicker savePicker = new FileSavePicker
{
SuggestedStartLocation = PickerLocationId.Desktop
};
savePicker.FileTypeChoices.Add("Shortcut", new [] { ".url" });
var saveFile = await savePicker.PickSaveFileAsync();
if (saveFile != null)
{
await FileIO.WriteLinesAsync(
saveFile,
new string[] { "[InternetShortcut]", "URL=yourapp:///" });
}
I have found a much simpler way.
You just need to create a normal shortcut with the target
C:\Windows\explorer.exe shell:AppsFolder{PackageFamilyName}!App
I use the following code to generate the shortcut the first time the application runs (You'll need to add a COM reference to Windows Scripting Host):
string shortcutLocation = Path.Combine(Environment.SpecialFolder.Desktop, shortcutName + ".lnk");
WshShell shell = new();
IWshShortcut shortcut = (IWshShortcut)shell.CreateShortcut(shortcutLocation);
shortcut.IconLocation = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "icon.ico");
shortcut.Arguments = $"shell:AppsFolder\\{insert your PackageFamilyName}!App";
shortcut.TargetPath = Path.Combine(Environment.GetEnvironmentVariable("windir"), "explorer.exe");
shortcut.Save();
PackageFamilyName:
Your app family name should be a giant alphanumeric hash, the easiest way to get that is to install it somewhere and use the powershell command Get-AppxPackage https://learn.microsoft.com/en-us/powershell/module/appx/get-appxpackage?view=windowsserver2019-ps. It can also be obtained in code with Package.Current.Id.FamilyName.
Icon location: This is not necessary it should use the default icon for your app. I changed this because it used a version with an ugly blue background. Adding an icon to your build output folder and linking it as above lets you choose the icon.
It should also be noted that the mouseover text for the shortcut is windows explorer. Please let me know if anyone finds a way around this.
Another option might be to add an ExecutionAlias and create the shortcut directly to the alias.
In Package.appxmanifest
xmlns:uap5="http://schemas.microsoft.com/appx/manifest/uap/windows10/5"
<Extensions>
<uap5:Extension Category="windows.appExecutionAlias" EntryPoint="Windows.FullTrustApplication" Executable="MyApp\MyApp.exe">
<uap5:AppExecutionAlias>
<uap5:ExecutionAlias Alias="MyApp.exe" />
</uap5:AppExecutionAlias>
</uap5:Extension>
</Extensions>
Then make the shortcut for MyApp.exe

unable to setImage to UIButton in Xamarin C#

Unable to setImage for UIButton.
when set backgroundColor with Image its showing image which I want to set it "backButton.png"
When setImage to UIButton its not showing at all
backButton.SetImage (UIImage.FromFile ("/Images/backButton.png"), UIControlState.Normal);
I want to setImage to UIButton.
// Below is code
UIButton backButton = UIButton.FromType(UIButtonType.Custom);
backButton.Frame = new RectangleF (5, 5, 45, 30);
backButton.BackgroundColor = UIColor.FromPatternImage (UIImage.FromBundle ("/Images/backButton.png"));
backButton.SetImage (UIImage.FromFile ("/Images/backButton.png"), UIControlState.Normal);
backButton.TouchUpInside += (sender, ea) => {
this.NavigationController.PopViewControllerAnimated(true);
};
I don't know much about the Xamarin. But the directory structure presented in xcode project is different than the actual (after app compiles).
All the files and resources resides in same directory called main bundle.
And to access your resources you just ask for it from the main bundle. You don't have to specify the directory (in which resource resides) of you xcode project navigator.
You can read about more directory structure here
It's because when you set images from Visual Studio from property box, it sets the image path like images\image1.png [when the image1.png file is in \Resources\Images folder.
But MAC doesn't support "\" path, you'll need to provide path with "/".
I have come across recently against this very issue. I read that Apple recently enforced a change that all resources must reside within Resources directory when you create the project in Xamarin. You can create Image directory within the Resources directory and have your images there.
Now to read them back it is as simple as - if images are in Resources directory you can just use
UIImage.FromFile ("backButton.png")
But if your images are inside Resources/Images then use simply
UIImage.FromFile ("Images/backButton.png")
Note lack of backslash before the Images directory which now resides inside Resources directory.
This works for me. Sorry i don't recall the link that told me about the change and storage of Resources within the directory only but this fixed all my resource related issues.
In the code you posted:
backButton.BackgroundColor = UIColor.FromPatternImage (UIImage.FromBundle("/Images/backButton.png"));
backButton.SetImage (UIImage.FromFile ("/Images/backButton.png"), UIControlState.Normal);
You use in one line UIImage.FromFile and in the other line UIImage.FromBundle. If I understood you correct the "FromBundle" version works, so try to use this one for the SetImage as well.

Null Reference Exception when StreamResourceInfo attempts to get a ResourceStream?

I'm following one of the MSDN Introduction to Windows Phone Development labs, and have run into a problem with this lab (Introduction to Controls Available for Windows Phone Applications). The lab provides both the starting files, and the end files (i.e., what the program should look like upon completion of the lab).
The particular part of the lab that has me stumped is the point where I'm reading in a series of images from an Assets folder, then displaying them in a ListBox on screen. Whenever this code tries to run, it throws a Null Reference Exception:
public static BitmapImage GetImage(string filename)
{
string imgLocation = Application.Current.Resources["ImagesLocation"].ToString();
StreamResourceInfo imageResource = Application.GetResourceStream(new Uri(imgLocation + filename, UriKind.Relative));
BitmapImage image = new BitmapImage();
image.SetSource(imageResource.Stream);
return image;
}
I've dug into as much as I can, and imageResource always winds up Null somehow, and I can't for the life of me figure out where it's going wrong.
I've included a link to the two projects here (129 MB, sorry for that). Everything under the "Begin" folder is what I've done so far (and throws an Exception when I attempt to navigate to the Images page during runtime). Everything under the "End" folder is what it's supposed to end up looking like, and is functional.
I'm very new to C# and WP7 development, so any help would be greatly appreciated. Thank you!
Try to change the build for the .bmp to "Resource".
Here's a couple of links explaining it:
http://forums.silverlight.net/t/238891.aspx/1
Application.GetResourceStream called on a Content Resource still return null
The problem is that when you set your images directory in App.xaml file, there is a mistake in the tutorial. You should set the application resource, ImagesLocation like this:
<system:String x:Key="ImagesLocation">Begin;component/Assets/Images/</system:String>
Where Begin is your project name ;component/ is needed as separator, and finally the Assets/Images/ is the relative path to your images directory.

C# - Loading image from file resource in different assembly

C# - Loading image from file resource in different assembly
I have a PNG image file which is stored in a project called SomeProject and displayed various times using XAML in that same project. In a different assembly, I now wish to access that same image. Previously I was simply specifying a relative path to the actual file which worked fine. However, when I build a release installer, the image files are packed into the SomeProject.DLL.
Is there any easy way I can access the PNG file from another assembly without simply resorting to copying the file locally to the second project? I though it might be possible using 'pack://' but I'm not having much luck.
// SomeOtherProject.SomeClass.cs ...
Image logo = new Image();
BitmapImage logoSource = new BitmapImage();
eChamSource.BeginInit();
// Following line works fine is Visual Studio, but obviously not after installation
// logoSource.UriSource = new Uri(#"..\SomeProject\Resources\Images\logo.png", UriKind.Relative);
logoSource.UriSource = new Uri("pack://application:,,,/SomeProject;component/Resources/Images/logo.png");
logoSource.EndInit();
logo.Width = 100; logo.Height = 100;
logo.Source = logoSource;
Any advice would be good.
If the images you wish to use as Content is in another assembly, you must copy them to the main projects directory.
You can use a Build event to do this:
Right click project that contains images -> Properties -> Buil Events -> edit post build to copy images to main project directory.
Then you have to use it as
pack://application:,,,/ContentFile.xaml
(Or)
If you need it in subfolder
pack://application:,,,/Subfolder/ContentFile.xaml
Have a look at this hfor more information http://msdn.microsoft.com/en-us/library/aa970069.aspx
Try to load your other assembly as followed:
Application.LoadComponent(new Uri(#"AnotherAssembly;;;component\AnotherResourceFilePath/logo.png", UriKind.Relative)));
LoadComponent function returns an object. It is up to you to cast it to the appropriate type.

Categories

Resources