WPF Dynamic Image Loading into ResourceDictionary programmatically - c#

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

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.

Image doesn't appear when changing its source in Windows Phone

When I want to change an image's source, the image simply disappears.
The code I'm using:
tactImg.Source=tactImgList[i];
tactImgList = new BitmapImage[32];
tactImgList[0] = new BitmapImage(new Uri("ms-appx:///Assets/Images/1.png", UriKind.Absolute));
What am I doing wrong? Is there something I need to add to an xaml file or I'm making the global array wrong?
You don't need to use ms-appx in Windows Phone 8 projects , it's for WinRT projects.
Make sure your image's Build type is Content , remove the ms-appx part and since your image has relative uri , set your UriKind to Relative.
First, fill in the data, and then change the source.
tactImgList = new BitmapImage[32];
tactImgList[0] = new BitmapImage(new Uri("ms-appx:///Assets/Images/1.png", UriKind.Absolute));
tactImg.Source=tactImgList[i];
Or use ObservableCollection for storing images.

Referring to image file in WPF project in Visual Studio

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

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.

Categories

Resources