Click here to Skip to main content
15,892,005 members
Please Sign up or sign in to vote.
3.00/5 (2 votes)
Hi,

I need to load an image from disk based on a path provided for me by the database I'm using. The problem is: I can only load the image if it's included in the project, wich will not be the case.

Is it possible to, using XAML only, load an image that is in disk but not included in the project? How can I do it? If it's not possible using XAML only, how can I do it with C#?

Here's the part of my code used to load the images on XAML, I'm using Telerik RadGridView for Silverlight, and the image is being loaded in a cell of this grid, together with a textblock (some parts of the text is in brazilian portuguese).

XML
<StackPanel.Resources>
                        <AiPede:CellTemplateSelector x:Key="CellTemplateSelectorImageAndText">
                            <AiPede:CellTemplateSelector.ImageAndTextCell>
                                <DataTemplate>
                                    <StackPanel Orientation="Vertical">
                                        <Image Width="57" Height="57" HorizontalAlignment="Center" VerticalAlignment="Center" Source="{Binding Imagem}"/>
                                        <TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" TextWrapping="Wrap" Text="{Binding Produto}"/>
                                    </StackPanel>
                                </DataTemplate>
                            </AiPede:CellTemplateSelector.ImageAndTextCell>
                        </AiPede:CellTemplateSelector>
                    </StackPanel.Resources>
                    <sdk:Label Content="Disponíveis" FontFamily="Portable User Interface" FontSize="14" FontWeight="Bold" Foreground="#FF686765" Name="label2" Margin="5" />
                    <telerik:RadGridView Name="rgvBebidasComAlcoolDisponiveis" ShowGroupPanel="False" Width="220" Height="383" IsReadOnly="True" AutoGenerateColumns="False">
                        <telerik:RadGridView.Columns>
                            <telerik:GridViewDataColumn Header="Produto" CellTemplateSelector="{StaticResource CellTemplateSelectorImageAndText}" Width="*"/>
                        </telerik:RadGridView.Columns>
                    </telerik:RadGridView>


Thanks in advance!
Posted
Comments
Sergey Alexandrovich Kryukov 10-Sep-12 15:58pm    
Of course it's always possible and so simple that I don't even know what could it be a problem. But first, I would need to know what is the image type.
Is it bitmap or vector. If this is a vector, it it XAML containing a Canvas instance or something else?
--SA
liordino 10-Sep-12 16:05pm    
The image is a png. I'm getting some data from a webservice, and in this data I have a name and a path to an image about a product. I need to get the image on this path and show it with the text on a cell on a RadGridView (I'm using Telerik controls).

It should be done on this line of code:
<Image Width="57" Height="57" HorizontalAlignment="Center" VerticalAlignment="Center" Source="{Binding Imagem}"/>
Where "Imagem" is the column with the path to the image on the disk.
Problem is: the image appears only if I add it to my project. If it's not added the image is not shown.

I don't know it it adds on something, but it's a Silverlight website, and I'm running it on Visual Studio, not publishing it.

Sorry if I didn't made it clear on the original post. :P
Sergey Alexandrovich Kryukov 10-Sep-12 16:19pm    
No, it does not have to be in the project.
I already answered for both cases... please see how to do it,.. enjoy. :-)
--SA

Please see my comment to the question: of course this is possible and easy, but you need to clarify what is your image.

If this is a bitmap, you usually use the class: System.Windows.Media.Imaging.BitmapImage:
http://msdn.microsoft.com/en-us/library/system.windows.media.imaging.bitmapimage.aspx[^].

Look at the end of the MSDN article referenced above and find the sample showing loading an image from file. You can also load it from a resource embedded in your assembly's executable module or from any other kind of stream. See also the parent class System.Windows.Media.Imaging.BitmapSource and other derived classes: you might need further processing of a image or something else; besides, this is the core or WPF image processing, very good to know:
http://msdn.microsoft.com/en-us/library/system.windows.media.imaging.bitmapsource.aspx[^],
http://msdn.microsoft.com/en-us/library/system.windows.media.imaging.bitmapsource.aspx (inheritance hierarchy)[^].

You can also use vector graphics. One of the way is using XAML files which content is the instance of some WPF Canvas (System.Windows.Controls.Canvas):
http://msdn.microsoft.com/en-us/library/system.windows.controls.canvas.aspx[^].

To load it, you would need to use the class System.Windows.Markup.XamlReader:
http://msdn.microsoft.com/en-us/library/system.windows.markup.xamlreader.aspx[^].

Using it would look like this:
C#
Canvas image = (Canvas)XamlReader.Load(/* some instance of an input stream is passed here: file, resource or any other one */);


This approach is very convenient, because the user can easily supply such a XAML image using a number of vector graphics editors, notably Inkscape:
http://en.wikipedia.org/wiki/Inkscape[^],
http://inkscape.org/[^].

It has export to XAML (but make sure it renders properly, because XAML has a bit less expressing capabilities compared to SVG, advanced features like fussiness cannot be used).

I think vector graphics has a lot of benefits over bitmaps (scaling without loss of quality, low memory footprint independent of scale and quality at bigger sizes), so a WPF application can be built without any bitmaps at all, excluding the application icon and window title bar icons.

—SA
 
Share this answer
 
v3
Comments
Kenneth Haugland 10-Sep-12 16:26pm    
Good answer. 5'ed :)
Sergey Alexandrovich Kryukov 10-Sep-12 16:37pm    
Thank you, Kenneth.
--SA
liordino 11-Sep-12 13:44pm    
Thanks, Sergey! Its now working, but only with absolute paths. I'm trying to make it work with relative paths but with no success. Any ideas? I think the problem will be solved even using the absolute path, but it would be nice to get a cleaner code. :)

Oh, and thanks again! =D
Sergey Alexandrovich Kryukov 11-Sep-12 14:03pm    
There is no big difference, but ultimately you should almost always work with absolute file names, even if the file is known by its relative name. Here is why: if the file name is "relative", and you use it directly, it will be found if this is a relative path relative to what? -- to the current directory. But the problem is: this directory can be anything. Even if your code does not change it, the user can start your application with absolutely any working directory. It depends on the current working directory of the parent process (very usually, some file manager, like Windows Explorer or any other); it also is a parameter of a .LNK file. So, you cannot expect that this is an executable directory or something. Sometimes, the relative path is used, most typically, in console applications targeted to experienced users who intentionally control paths by using specific current directory. If this is not the case, you really need to use some "special directory" or executable directory, and calculate some absolute path based on some relative path (using System.IO.Path class).

Wait a minute, I'll put a separate answer, because this goes out of initial topic...

Done. Please see my Solution 3. I hope you will accept it as well, because it provides a comprehensive explanation on how to work with those directories.
--SA
liordino 17-Sep-12 10:33am    
Hi Sergey! How you're doing? So, I came into another problem regarding this scenario: in fact I have to load the images from an FTP, since the code will run in the client side, and the images is on the server side. Basically what I tried was this:

<Image.Source>
<bitmapimage urisource="{Binding Imagem, StringFormat='ftp://user:password@server\/{0\}'}"/>
</Image.Source>

But it didn't load anything.
Do you know a way to load images via an fpt, using XAML?

Thanks in advance!
[An answer to the follow-up question about relative and absolute path names for image files:]

Please see my comments to your comment to my Solution 1.

By the reasons I explained there, first of all, there are no cases when a hard-coded path can be used in a fully functional application, no matter it this is an absolute or a relative path. all path names should be calculated during run time based on some data supplied by the user, configuration files, etc., but importantly, also based on some "special" directories which include a current working directory (in most cases, I would not recommend using it, as I explained in my comment to Solution 1), executable file directory (a location of the main executable module of the entry assembly, to be more precise) and some "special folders" associated with the user's profile.

Please see my two past answers where I provided comprehensive explanation on finding all relevant paths:
How to find my programs directory (Solution 1)[^],
How to find my programs directory (Solution 2)[^].

Good luck,
—SA
 
Share this answer
 
v2
Comments
liordino 11-Sep-12 14:17pm    
Thanks! I think I'll use a absolute path them, since I know it.
Sergey Alexandrovich Kryukov 11-Sep-12 14:28pm    
You are welcome.

Again, you should not use the absolute path directly (in most cases). You should have some data providing relative file names. For example, let's assume they are only the input files, so you can supply them in the executable directory or in a directory relative to the executable directory (but not just those included in project, some which are supplied separately). Then, you need to have some code which assumes that the data gives your the file names relative to the executable directory, which is calculated according to the recipe I gave you.

Same thing about "special folders" assigned to the user account to hold application data such as the one indexed by Environment.SpecialFolder.LocalApplicationData, but in this case, the files could be with read/write access.

You can use the absolute paths directly in some cases. Example #1: a file name supplied by the user via the UI or some configuration file accessible by the user; example #2: the absolute file names prescribed by the installation process in some configuration file; this way, this path can be different for different installations but the same during the application life time on the same machine.

By the way, are your files only the input (read-only) files? If so, did you consider using the files in the resource embedded in the executable module of an assembly? (Probably not, because you were interested in the file not included in the project in first place.) Anyway, if you are interested in that, I would answer, too.

--SA
liordino 11-Sep-12 14:41pm    
I've already tested the solution with an absolute path concatenated with the relative path that I get from the webservice, wich is this, in XAML:

<Image.Source>
<bitmapimage urisource="{Binding Imagem, StringFormat='myabsolutepath\{0\}'}"/>
</Image.Source>

By the way, I don't know yet if the files will be in the same directory of the application itself or in another one completely unrelated, thanks again for reminding me to check that. If they are in a completely unrelated uri, I thought of adding a property on the config with the absolute path... is it a bad practice in some way? And I would have to access them in XAML, in the code that I pasted above... do you know how to do that (if its possible, of course)?

Yeah, the files are only input, but unfortunatelly I can't add them to the project. I'm interested in knowing how to do it, anyway.
Sergey Alexandrovich Kryukov 11-Sep-12 16:47pm    
Do you mean the file assembly_name.exe.config? If you have some full path names here, I see nothing wrong in it, because they are written per concrete system and installation of the product. It's only important that the deployment process, whatever it is, creates correct path names which would work right away. Alternatively, you can make the user to do it manually, but that could only target the users who are advanced enough and should be advanced enough to understand and do it.
--SA
liordino 12-Sep-12 8:03am    
Yeah, I think that its really a solution that fits on my current situation. Thanks!
[An answer to the follow-up question about relative and absolute path names for image files:]

If the files are read-only, you can instead use resources embedded in an executable module of some of your assemblies.

Don't add an image to your directory. Create a .resx resource. Edit it by using "Add resource" => "Add existing file". Add a file. If a file was not in the same directory with the resource file, it will be copied there, so be careful not to keep multiple copies of the same file. Also, this file will be added to the project structure, and its reference will be added to your resource. Open the property of the project node representing your image file. You will see that it is not to be copied in output of the build. It will be places in resource embedded in your executable file. You will see that Visual Studio auto-generated code file, in a child node of the node representing the resource file. Open this file and locate a static class and its static property with the name resembling the name of your image file you used on input. Use this property to access the resource; don't use resource manager and string name of the resource — this is not really supportable way.

Use the property. If, for example, your image file is PNG, the property will be of the type System.Drawing.Bitmap. You won't need to match resource name, read image data from resource stream, etc. Just use the bitmap instance.

One more benefit: it will protect your images from modification by the user. If you also sign your assembly it would make the modification of your images nearly impossible.

As you can see, this way is only good if you have a fixed set of files prior to the build, which is not the case as formulated in your answer, but I added this solution just because you mentioned you would be interested to know this matter.

—SA
 
Share this answer
 
v2
Comments
liordino 12-Sep-12 8:02am    
Thats a nice way to handle this kind of files. I'll surely try it!
Sergey Alexandrovich Kryukov 12-Sep-12 13:16pm    
My pleasure.
Good luck, call again.
--SA
You stated that Imagem in the {Binding Imagem} is the data column with the path to the image. A URI can be used as the Source value in the XAML because the XAML loader will apply an implied conversion. When binding, the value provided must be the correct type, in this case ImageSource.

[DISCLAIMER: I'm a WPF, not Silverlight, developer. ]
 
Share this answer
 
Comments
liordino 11-Sep-12 13:06pm    
You mean like this: <Image x:Name="Imagem" Width="57" Height="57" HorizontalAlignment="Center" VerticalAlignment="Center" ImageSource="{Binding Imagem}"/> ?

Problem is that there's no ImageSource member on the Image type (sorry if I got it wrong).
Matt T Heffron 11-Sep-12 13:39pm    
No. The issue is that the *value* you are providing through the Binding to the Source needs to be of type ImageSource, not (presumably) a string (path to file). I'd use a ValueConverter in the Binding to take the path and create some object that derives from ImageSource, like System.Windows.Media.Imaging.BitmapSource.
liordino 11-Sep-12 13:43pm    
Yeah, thats what Sergey pointed out, and it worked, but only with absolute paths. I'm trying to make it work with relative paths but with no success. Any ideas?

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900