Referring to image file in WPF project in Visual Studio - c#

I'd like to load images into a WPF project with a short pathname. Details follow.
I've got a WPF solution that looks like this:
Solution 'GB" (16 projects)
ABApp
Properties
References
... ...
ImageApp
Properties
References
images
mona.jpg
App.xaml
App.xaml.cs
Window1.xaml
Window1.xaml.cs
I want to look at the ImageApp project.
The App.xaml file looks like this:
<Application x:Class="GB.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="Window1.xaml">
<Application.Resources>
</Application.Resources>
</Application>
and App.xaml.cs simply defines the class App to derive from Application.
The Window1.xaml file constructs a UI, and then Window1.xaml.cs builds a drawing area in which various image stuff will be displayed.
Inside that C# file, to load up the image images/mona.jpg that I want to display, I end up writing something like this:
Image myImage;
BitmapImage myBitmapImage = new BitmapImage();
myBitmapImage.BeginInit();
myBitmapImage.UriSource =
new Uri("../../images/mona.jpg", UriKind.RelativeOrAbsolute);
myBitmapImage.EndInit();
//set image source
FormatConvertedBitmap newFormatedBitmapSource = new FormatConvertedBitmap();
newFormatedBitmapSource.BeginInit();
newFormatedBitmapSource.Source = myBitmapImage;
newFormatedBitmapSource.DestinationFormat = PixelFormats.Bgra32;
newFormatedBitmapSource.EndInit();
bmpSource = newFormatedBitmapSource;
myImage.Source = bmpSource;
BuildRenderTransform();
(I apologize for that code -- it's a kind of simplification of what's really going on, so it may not be letter perfect.)
My question is about the Uri: I have to write ../../ at the front of the Uri so that the executing program (which ends up in ImageApp/bin/Debug) knows it has to go up two levels and then down into the images folder. Is there some way that I can just write something like new Uri("images/mona.jpg", ...) instead? Can I tell WPF that the source directory should be used as the starting path for relative searches?
I confess, the whole Uri thing is mostly baffling to me, despite my having read the microsoft help articles and several StackExchange questions/answers..
I have the suspicion (and vague memory) that by adding something to the xaml for the project, I can make this happen, but I just can't seem to do it.
Any ideas?

I'm not sure (can not check right now), but try to specify something like this
new Uri("/ImageApp;component/images/mona.jpg");
And ensure you have ImageApp in references

Related

My WPF UserControl can't locate resources when I use it with a project other than the one it was built in

So I built a WPF user control as part of a larger solution. I'm building another app where this user control would work nice. I added a reference to the DLL from the new app, wired it up and compiled. The window loads and I can see the image that it's telling me it can't find. After the main window displays and the user control is populated, an exception is thrown saying...
System.IO.IOException: 'Cannot locate resource 'resources/nosortnofilter.png'.'
The user control is a DataGrid with some extensions added to it. The column it threw on was "id". As you can see in the image, the red arrow shows the nosortnofilter.png image being displayed in all columns. So why is it throwing this exception?
The line of code it throws on is here.
If ImageName = "" Then ImageName = "NoSortNoFilter"
img.Source = New BitmapImage(New Uri("pack://application:,,,/Resources/" & ImageName & ".png"))
So it all looks good from my perspective. Hoping someone can see what I'm not seeing.
EDIT: Found a solution. This works. But it still doesn't answer the questions why the original pack:// formatted URI only worked with the original solution.
img.Source = New BitmapImage(New Uri($"Resources/{ImageName}.png", UriKind.Relative))
EDIT: Thanks to rfmodulator for giving me the correct URI for DLL's.
img.Source = New BitmapImage(New Uri("pack://application:,,,/AdvancedSortFilterDataGrid;component/Resources/" & ImageName & ".png"))
This is the URI of a resource in the Application's assembly:
pack://application:,,,/Resources/[RESOURCENAME]
To get a resource in a DLL, the URI looks more like this:
pack://application:,,,/[DLLNAME];component/Resources/[RESOURCENAME]
For details, see Pack URIs in WPF.

Overwriting and Image Open and Currently Binded to In WPF Program

I am binding to 5 different images in my program and wish to leave the capability of the user to replace or update the photos under the same name. So when updating these pictures, the binding will be notified and change while the program is running.
The program is a Digital VMB (visual management board) at my workplace, so it needs to remain running and have these photos be updated on the server without a hitch. Currently I am binding to a property in my C# which is a string containing the image location.
In c#:
public string OpenFilePathProp { get; set; }
In XAML:
<Image x:Name="OpenWOImage" Source="{Binding OpenFilePathProp}" Stretch="Fill" Margin="25,0,25,0"/>
When the user goes to copy and replace the image with the newer one, they can't as it's "currently open in another process". Which I suppose is the data binding in my WPF.
Can this be overcome by opening the images into a filestream and then binding to the stream? If so, I'm completely unsure on how to bind to a filestream; I'm quite new to WPF AND C#.
Thanks for the help. I HAVE tried to look for a solution to this, but I think I'm just getting confused and I don't think it will resolve my problem since it seems the binding is what's "keeping the image open" and I'm not sure how to bind to an Image object AND close that object to allow for overwriting
EDIT: Thought I should mention that I've managed to copy the images in question to the AppData folder for my VMB program,
like,
string AppData = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\";
System.IO.File.Copy(Properties.Settings.Default.OpenWOFilePath, System.IO.Path.Combine(AppData, "ROAMaintenanceVMB\\OpenWOFilePath_Copy.jpeg"), true);
this way I can "check" every so often to see that someone has overwritten the photos on the server, and THEORETICALLY copy the "new" photos to the AppData folder, overwriting the previous versions. THIS is where the issue of the images already being open in another program arises.
Following Peter Duniho suggestion about using WriteableBitmap worked in my instance.
string imagePath = "";
Uri imageUri = new Uri(imagePath);
BitmapImage bitmapImage = new BitmapImage(imageUri);
ImageProperty = new WriteableBitmap(bitmapImage);
<Image Source="{Binding ImageProperty}"/>
What's going on here is:
BitmapImage is created from the given path
WriteableBitmap is created based on the BitmapImage (a "deep copy"?)
The important thing here is the original image is not locked, as the binding is tied to the copy of the image of WriteableBitmap - not to the image itself, so the image can be deleted / replaced freely.

Locked resources (image files) management

The application is a desktop document management system. Image files (of scanned docs) are stored within a shared network folder and its indices within a database. Now, when the image of a selected document page is displayed the user has the option to delete it (via a contextual menu). The problem is, if I try to do this then it throws an exception (the resource is locked) which has all the sense given that it's being shown on screen. So, currently I maintain a persistent delete queue. Once the app starts I go to the queue and delete the pages of the documents whose indices were deleted from DB and given that they aren't being displayed the deletion succeed but this seems to be pretty bad code (I mean it works, but not as clean as it should, I guess).
How bad my quick solution is. Given that the app is single-user then the user needs to star the app to use it. Is this a very bad idea or can I implemented using another path.
The images are shown (within the document viewer) by binding it to the current file:
View:
<Image Name="PageViewedPath" Margin="20" Grid.Column="0" />
ViewModel:
public string PageViewedPath { get; set; }
And once the user clicks next or previous I change (within the ViewModel the PageViewedPath). Maybe the problem is this binding which I can't control in detail, I'm using Caliburn Micro so that's why just by setting the image name the binding is done.
I think maybe overriding this binding and creating a hardcopy of the image before is being shown must work but I'm not sure if it will and worse, how to do it.
I've had a similar problem in an application I developed that was using an image pool. Although the image was not displayed anymore, the file was locked and could not be deleted.
I solved my problem by loading images with BitmapCacheOption.OnLoad, something like this:
Image myImage = new Image();
BitmapImage bi = new BitmapImage();
bi.BeginInit();
bi.CacheOption = BitmapCacheOption.OnLoad;
bi.UriSource = imageUri;
// End initialization.
bi.EndInit();
myImage.Source = bi;
Here's a link to an msdn post that shows how to use BitmapCacheOption from xaml:
http://social.msdn.microsoft.com/forums/en-US/wpf/thread/3cb97997-941f-42a8-a03b-f84b152c1139/
If you code lock the files from your own code - stop locking. You probably missing some using/Dispose calls somewhere around loading an image.
If it is not your code or you need to handle failures due to using shared files location - your solution may be ok. Also most users will not expect such behavior - my normal expectation is that file is either deleted instantaneously or never.

How to properly use image resource in WPF application

What is the best way to store static images (like toolbox icons) in a WPF app?
Right now I have Images directory and use them like this:
<dxb:BarButtonItem x:Name="rbSignOut" Content="Sign out" Glyph="Images/Icons/close-16x16.png" LargeGlyph="Images/Icons/close-32x32.png" />
I think it's not the best practice because when I move XAML file in to a subfolder, I need to change all paths. Also, it just does not seems right to store paths in code. So how do I do it properly?
Instead of your path, which is relative to the XAML file:
Glyph="Images/Icons/close-16x16.png"
Use a path which is relevant to the application root (using a leading forward slash)
Glyph="/Images/Icons/close-16x16.png"
No matter where your XAML file is, your image will always be referenced from the root. As long as you don't move your images, you'll always be fine.
Use a ResourceDictionary together with your images. You can add it to the generic.xaml ResourceDictionary so you'll only have to change one path if you move it and you can use the images in every xaml file.
Just Right-Click and change your image's "Build action" to "Content" and use like this
<Image Source="/WPFApplication1;component/Images/Image.png" />
I felt it as the best approach to use Images,Video etc as the Files are not embedded into the assembly.

WPF Dynamic Image Loading into ResourceDictionary programmatically

Morning folks,
I've been trying to cut out some of my app's processing when I stumbled upon a suggestion on SO to load all images into a resource dictionary via BitmapImages, then referencing them rather than loading an image each time. My problem is that I need to do this all programmatically, so:
<BitmapImage x:Key="MyImageSource" UriSource="../Media/Image.png" />
has become:
BitmapImage bI = new BitmapImage();
Uri imgUri = new Uri(fI.FullName, UriKind.RelativeOrAbsolute);
bI.UriSource = imgUri;
DataTemplateKey dTK = new DataTemplateKey(typeof(BitmapImage));
imageDictionary.Add(dTK, bI);
Which I think should work, but as it loops due to the images loading based on database content, I immediatly get a key already added error on the second loop-through. Is there any way to create a datatemplatekey that I can name myself rather than have it based on the type?
Thanks,
Becky
It is not possible to add a key to the datatemplate but maybe you fix your problem by creating a DataTemplateSelector. On the link below you can find very good information on how to do that:
http://www.switchonthecode.com/tutorials/wpf-tutorial-how-to-use-a-datatemplateselector

Categories

Resources