using resource dictionary as central collection of all images - c#

i have a project with a lot of assemblies (> 100). many of those assemblies have subfolders like "images". many wpf-windows/user-controls for example have a "\images\close.png". that means that i have many "close.png" pictures instead of just a single one.
now i want to create a central place for all images/resources. what i did:
created a new class-libary/assembly called "a.b.c.d.e.Core.Resources"
added a resourcedictionary called "ImageDictionary.xaml"
created a subfolder "Images"
copied my images to this subfolder. for example "a.b.c.d.e.Core.Resources\images\close.png"
setting the built property of the image to "resource"
declared the image in the "ImageDictionary.xaml" like this "< ImageSource x:Key="Image_close">close.png< /ImageSource>"
using the dictionary in the wpf window where i want to use the "close.png" image like this
< Window.Resources>
< ResourceDictionary Source="pack://application:,,,/a.b.c.d.e.Core.Resources;component/Images/ImageDictionary.xaml"/>
< /Window.Resources >
trying to use the image declared in the central resource dictionary "ImageDictionary.xaml" like this < Button>< Image Source="{StaticResource Image_close}">< /Image>< /Button>
in the designer mode of VS the image is beeing displayed but when i start the project and open my wpf window i get an error like
"{"The File or Assembly \"a.b.c.d.e.Core.Resources, Culture=neutral\" or one of its dependencys can't be found. The system can't find the given file.":"a.b.c.d.c.e.Resources, Culture=neutral"} (i translated the error message from german to english :) )
Does anyone have any idea what i did wrong and why i can't get the central resourcedictionary getting to work properly? Thanks for any ideas!!!
Greetings from Germany
edit:
i also have a reference to "a.b.c.d.e.Core.Resources" in the assembly where my wpf window is
edit 2:
System.Windows.Markup.XamlParseException: Message=RowNumber "7" and RowPosition "10" of "Setting the Property "System.Windows.ResourceDictionary.Source" caused an exception".

Ok, the first idea I have is, that the file cannot be found because of the maximum path length limitation of the WinApi. I'm not sure about it, because I don't know anything about the internals of the resource loading mechanism.
Please try to start the program from a shorter path. Perhaps, it'll solve the problem.
EDIT
Just an idea, is your ImageDictionary.xaml declared as resource? If not, you should set its build step to "resource".
EDIT2
Next idea. Please empty the ImageDictionary.xaml by commenting out the elements. Uncomment the dictionary element by element. Perhaps, you'll find the reason for your problem, this way.

Related

Using an SVG as a Ribbon SmallImageSource, with SharpVectors?

I've successfully been able to use a static .svg file as an image in WPF by following the guidance in another question.
The basic approach there is to use the SharpVectors library, and do:
<svgc:SvgViewbox Source="path/to/file.svg"/>
In place of an <Image .../> tag.
However I am struggling trying to find a similar method to use an SVG within a System.Windows.Controls.Ribbon - where i'd like to use it as the SmallImageSource of a RibbonMenuButton.
I have tried the following:
<RibbonMenuButton Label="Test">
<RibbonMenuButton.SmallImageSource>
<svgc:SvgViewbox Source="path/to/file.svg"/>
</RibbonMenuButton.SmallImageSource>
</RibbonMenuButton>
Which produces the compiler error message:
The specified value cannot be assigned. The following type was
expected: "ImageSource".
I think the key problem is that an svgc:SvgViewBox is not an "image source", but I don't know how to properly convert or otherwise work around this.
I'm open to alternate approaches which don't use SharpVectors, but it is extremely convenient to have source image files in SVG format and not have to manually convert to any other format.
SharpVectors includes a converter extension which can be used to 'output' an ImageSource.
This is documented in section "1.2 WPF Extensions and Type Converters" of their usage guidelines.
Example:
<RibbonMenuButton Label="Test" LargeImageSource="{svgc:SvgImage path/to/file.svg}"/>
(where svgc is the defined name of the SharpVectors namespace in your XAML.)
The svgc:SvgImage binding extension produces a DrawingImage which is a type of ImageSource. This works perfectly at runtime with the SVG image rendered into the button.
Unfortunately at design-time the button image is blank.
Please try using the newly added property; AppName, which is used to try and resolve the URI of the resource file at design-time.
See the samples for the SvgImage and newly added SvgImageConverter, especially the toolbar demo using the SVG icons.
https://github.com/ElinamLLC/SharpVectors/tree/master/TutorialSamples/ControlSamplesWpf
SvgImageConverter provides binding support, if you need it unlike the SvgImage.

Change Image at Runtime Based On RadioButton Selection

I need to change the background image at runtime, based on which RadioButton the user clicks. I'm doing this in a WPF project in Visual Studio, and I need to put the code in the Checked event in the xaml.cs file
I have an Image control called imgBackground, with 6 images in its Source collection, which are listed in an Images folder in the Solution Explorer.
I've tried:
this.imgBackground.Source = "filename.jpg";
both with and without the quotes, and with various paths (I've tried too many different variations to list them all here) and nothing works - everything I've tried just gives an error in the editor, before I even try to build and run anything (the error given varies depending on what I'm trying at the time).
If you are using relative paths as filenames like
this.imgBackground.Source = "filename.jpg";
then these files must be in the same directory as the .exe of your program is.
One workaround would be to use absolute paths like
this.imgBackground.Source = #"C:\MyFolder\MyProject\filename.jpg";
Or, even further use the packaging mechanism of WPF or pack your images as resources into your assembly. Look at this thread.
EDIT:
For your clarification:
The Source-property demands an System.Windows.Media.ImageSource-object, which you must provide.
Do it like this:
BitmapImage bi3 = new BitmapImage();
bi3.BeginInit();
bi3.UriSource = new Uri("filename.jpg", UriKind.Relative);
bi3.EndInit();
this.imgBackground.Source = bi3;
Please refer to this documentation here.

How do I cast an icon from a resource file to an image for use on a button?

I'm trying to use an icon that I've added as a resource as the image on a button. I know it's possible because I can do it in other projects through the designer. However, I'm trying to do this with code. I added the icon as a resource to my project by following the steps in the accepted answer to this question. The resource is named CancelButtonIcon.
Now, I'm trying to add that icon as the image on a standard button with this code:
this.CancelButton.Image = (System.Drawing.Image)Properties.Resources.CancelButtonIcon;
However, I get an error message:
Cannot convert type 'System.Drawing.Icon' to 'System.Drawing.Image'
In the code that Visual Studio automatically generates when I use the designer, it looks like this:
((System.Drawing.Image)(resources.GetObject("SaveButton.Image")));
which results from manually adding a resource through the Properties window. How can I convert this icon resource to an image so it can be used on the button? Adding it through the designer is not an option (this button is created programmatically and thus isn't present in the designer).
You can use the Icon.ToBitmap method for this purpose. Note that a Bitmap is an Image.
CancelButton.Image = Properties.Resources.CancelButtonIcon.ToBitmap();
Not sure why, but any time I tried using the accepted answer's approach, the .ToBitmap() call was giving me array index out of bounds exceptions. I solved this by doing it this way instead:
System.Drawing.Icon.FromHandle(Properties.Resources.CancelButtonIcon.Handle).ToBitmap();

Load Images in WPF application

I am not familiar with WPF, and I just feel quite confusing.
I am trying to create a little computer game, and there are elements I want to display dynamically. I use Image class and add the images to a canvas. But I'm not sure whether it's a good practice. I feel that adding controls to canvas seem to be a little wired. And I'm a little concerned about the performance, because I may need many images.
The real problem is, I can't load the images from the image files. I see an example in a text book like this (XMAL):
<Image Panel.ZIndex="0" Margin="0,0,0,0" Name ="image1">
<Image.Source>
<BitmapImage UriSource="Bell.gif" />
</Image.Source>
</Image>
Where Bell.gif is added into the project.
And I tried to copy this in code to create an image.
new Image { Source = new BitmapImage(new Uri("Blockade.bmp"))}
But I got invalid Uri exception. After some search in the Internet, I found that loading resources dynamically seems to be difficult. Can I load the files added to the project dynamically?
If I use absolute path then it's OK. But I can't expect every computer will put the files in the same location. Can I use relative path?
I tried
new Image { Source = new BitmapImage(new Uri(#"Pictures\Blank Land.bmp", UriKind.Relative)) }
But it doesn't work. (The image is blank)
Thanks.
I deleted the code. I just found the solution in "Pack URIs in WPF" in MSDN.
I can either use "pack://application:,,,/Blockade.bmp" (absolute) or "/Blockade.bmp" (Relative) for a resource in the local assembly.
(I didn't use '/' at first)
"pack://application:,,,/ReferencedAssembly;component/File.xaml" is for referenced assembly. (I guess the problem with the answer is that the authority part is missing)
The following works:
new BitmapImage(new Uri("/MyProject;component/Resources/next.png", UriKind.Relative));
Just replace "MyProject" with the name of your project, and adjust the path to your image.
Make sure the image is added to the project with the "BuildAction" set to "Resource".

Best way to display default image if specified image file is not found?

I've got your average e-Commerce app, I store ITEM_IMAGE_NAME in the database, and sometimes managers MISSPELL the image name.
To avoid "missing images" (red X in IE), every time I display the list of products, I check the server for the image related to the product, and if that file doesn't exist - I replace it with default image.
As far as i can tell this doesn't affect performance, but I was wondering if there are any alternatives to fix a "missing image" problem.
I'm using ASP.NET + C# (.NET 3.5)
Some code:
foreach (Item item in Items)
{
string path = Path.Combine("~/images/", item.categoryImage);
item.categoryImage = File.Exists(Server.MapPath(path)) ? item.categoryImage : GetImageDependingOnItemType();
}
You might consider something with javascript
<img src="image.jpg" onerror="this.onerror=null;this.src='default.jpg'">
Edit: Or program a 404.aspx returning a default image, if a nonexisting image was requested.
<style>
.fallback { background-image: url("fallback.png"); }
</style>
<img class="fallback" src="missing.png" width="400" height="300">
If missing.png loads, it will cover the space allocated for it, as if the fallback were not specified. (Assuming it's not transparent.)
If missing.png fails to load, the space will instead be filled with fallback.png. You'll still get a little "broken image" icon, but I prefer it that way... a little hint that says "fix me".
If your images aren't all the same size, you'll notice that the background tiles by default. You can use background-repeat: no-repeat; if you don't like that.
I like Erik's solution, but without removing the event after the first execution, because if you are using that code in, let's say, an MVC partial view, this will work only the first time it is loaded. So I'd go with:
<img src="image.jpg" onerror="this.src='default.jpg';" />
In case you have many images in the same situation, like a grid, you can do this instead:
$("img").on("error", function () {
$(this).attr('src', 'default.jpg');
});
Of course, you may want to use a more specific jQuery selector.
You can specify on the server what image should be returned for all requests to non-existent image files. That way the user can get a "2 AWESUM 2 SHO" lolcat instead of a red x.
I think your way is pretty much OK. I'd do it in a function or do in .categoryImage accessor.
I think I would find a way to make the data consistent rather than allowing users to enter inconsistent data. Perhaps your management app could allow the manager to select an existing image or upload a new one, then set the name of the image based on this input so that you'd be assured that the image will exist. Only remove an image when all references to it have been removed from the database. Restrict the interaction with the data to your app so that people can't make those sorts of mistakes.
Another way to handle this would be to have a handler (or a controller in ASP.NET MVC) that does the image lookup based on id and returns the image data. Coupled with caching this could be very efficient and would allow you to do image replacement as well.

Categories