Load image from file to dynamic resource programmatically - wpf

I need to load an image file to WPF's dynamic resource programmatically because the directory which contains the image files can be moved.
How can I load an image to WPF's dynamic resource which is used like this: Source="{DynamicResource ...}" in XAML?

In XAML:
<Image Source="{DynamicResource MyDynamicImage}" />
In code:
var myimg = new BitmapImage(new Uri("SomeUriHere"));
Resources["MyDynamicImage"] = myimg;
(The Resources collection should be one which is in the scope of the Image of course, if you have a direct reference to the Image control you can also use the immediate Image.Resources)
Whenever you set a new object to that resource key the DynamicResource will update.

Related

Using Bitmap Class in XAML [duplicate]

I have two .png files added to my resources which I need to access their Uri when doing binding.
My xaml code is as followed:
<Grid>
<Image>
<Image.Source>
<BitmapImage DecodePixelWidth="10" UriSource="{Binding Path=ImagePath}"/>
</Image.Source>
</Image>
</Grid>
and the binding code using ImagePath is:
ImagePath = resultInBinary.StartsWith("1") ? Properties.Resources.LedGreen : Properties.Resources.ledRed;
However
Properties.Resources.LedGreen
returns a Bitmap instead of String containing the Uri of that particular image.
I just want to know how to extract that value without a need to address a path of the image in the directory that it's stored. (Which honestly I am not sure is a right thing to do as I couldn't find any similar situation on the net).
Please let me know if there is even a preferred method to the one I am trying to use if available.
In a WPF application you would usually not store images in Properties/Resources.resx and access them by means of the Properties.Resources class.
Instead you just add the image files to your Visual Studio project as regular files, perhaps in a folder named "Images" or the like. Then you would set their Build Action to Resource, which is done in the Properties window. You get there e.g. by right-clicking the image file and select the Properties menu item. Note that the default value of the Build Action should be Resource for image files anyways.
In order to access these image resources from code you would then use a Pack URI. With the above folder name "Images" and an image file named "LedGreen.png", creating such an URI would look like this:
var uri = new Uri("pack://application:,,,/Images/LedGreen.png");
So you could perhaps declare your property to be of type Uri:
public Uri ImageUri { get; set; } // omitted INotifyPropertyChanged implementation
and set it like this:
ImageUri = resultInBinary.StartsWith("1")
? new Uri("pack://application:,,,/Images/LedGreen.png")
: new Uri("pack://application:,,,/Images/LedRed.png");
Finally your XAML should look like shown below, which relies on built-in type conversion from Uri to ImageSource:
<Grid>
<Image Width="10" Source="{Binding Path=ImageUri}" />
</Grid>
Declare the Properties.Resources.LedGreen property as ImageSource and set it to Uri location rather than the Bitmap object.
Or if you insist of storing it as a bitmap you can get the source by returning Properties.Resources.LedGreen.ImageSource which will be of type ImageSource.
I would prefer the first approach.

Windows Phone Binding Image Location

I am trying to place a collection of images at certain places on a canvas through Binding.
For some reason, the images are displaying but are NOT at the locations which I have specified.
C#
_roomView.Room = new Room
{
Items = new List<Item> {
new Item {ImageUri = "/Escape;component/Images/Items/a.jpg", XPosition = 190, YPosition = 50},
new Item {ImageUri = "/Escape;component/Images/Items/b.png", XPosition = 390, YPosition = 100},
new Item {ImageUri = "/Escape;component/Images/Items/b.png", XPosition = 490, YPosition = 600}}
};
listBoxItems.ItemsSource = _roomView.Room.Items;
XML
<Canvas>
<Image Source="{Binding ImageUri}" Stretch="None" Canvas.Left="{Binding Room.Items.XPosition}" Canvas.Top="{Binding Room.Items.YPosition}"/>
</Canvas>
XPosition and YPosition are of type int. I have tried changing them to double but the images still aren't being displayed where I want them to be. They only get displayed at the top left of the screen - on top of each other.
Can anyone see the problem?
You're using the pack URI format which is only valid if your images have a Build Action of "Embedded Resource". Even then, I'm not sure this URI format is actually supported for Image.Source and if the URI has to be Relative or Absolute. Check the images Build Action (Right click --> Properties on those files) and try changing the UriKind.
Either way, unless you have a very good reason it's best to keep media assets as:
Build Action = Content and use the normal path URIs. Adding images to DLLs as Embedded Resources is bad for startup performance since it takes longer to load your bigger DLLs into the AppDomain.
It's also bad from a memory usage perspective since the DLLs loaded into memory are now bigger.
Bottom line:
<Image Source="myPicture.png" /> format is much better for performance than
<Image Source="myAssemblyName;component/myPicture.png" /> syntax.
Your C# code has collection of images.
Your XAML only shows a single image. If the XAML is in the listbox data template, you'll get several canvases, with 1 image each.
To display a collection of images on the single Canvas, you could use e.g. <ItemsControl>, set ItemsPanel to a Canvas, and in the data template you specify a single image with source, canvas.left and canvas.top.
If you're trying to do what I've described with a ListBox instead of ItemsControl, it wont work because it has one more layer of UI elements between ItemsPanel and item, namely the item container.
P.S. Fastest way to troubleshoot such GUI problems - XAML Spy, I've bought myself a personal license. Evaluation is 21 days long, fully functional.

Image object rendering is extremly slow in WPF DataTemplate

I'm creating a simple file browser with thumbnails. I'm using a ListBox with a custom DataTemplate to display objects in an ObservableCollection.
<DataTemplate>
<StackPanel Margin="5">
<Image Source="{Binding Path=ThumbnailPath}"/>
<Label Background="White" Content="{Binding Path=FileName}"/>
</StackPanel>
</DataTemplate>
The objects (of my custom class File) have just these two string properties: ThumbnailPath and FileName. When user selects a folder, a BackgroundWorker gets a list of files and creates instances of the File class. These instances are dispatched to the UI thread (in groups of 10) using BW's ReportProgress. In the event handler they are added to the ObservableCollection bound to my ListBox.
The problem is when at least 20-30 Files are to be added to my collection; the UI freezes for almost three seconds before the ListBox gets updated. Don't even ask what happens when a folder contains hundreds of files. Everything is propely prepared in the background, so I guess the problem arises when WPF starts to initialize and render empty Image elements. When I comment out the Image from the DataTemplate, it takes a blink of an eye to update the collection and its view.
Is there anything that can be done about this? I know could create the whole View object in the background thread (a new StackPanel, add children new Label and new Image, set values), but the whole point of DataBinding and templating should be to avoid the need to do this... So how do I fill a ListBox with an Image in its DataTemplate without losing responsiveness?
PS: The actual thumbnails are generated by FFmpeg and saved to a file, but this process only starts after all items (with blank image object) are displayed, so they are of no concern in the context of this question.
Try this:
Change ThumbnailPath to the type of BitmapImage;
when setting property use
BitmapImage bi1 = new BitmapImage();
// BitmapImage.UriSource must be in a BeginInit/EndInit block
bi1.BeginInit();
bi1.UriSource = new Uri(#"C:\filepath.jpg");
To save significant application memory, set the DecodePixelWidth or
// DecodePixelHeight of the BitmapImage value of the image source to the desired
// height or width of the rendered image. If you don't do this, the application will
// cache the image as though it were rendered as its normal size rather then just
// the size that is displayed.
// Note: In order to preserve aspect ratio, set DecodePixelWidth
// or DecodePixelHeight but not both.
bi1.DecodePixelWidth = 200;
bi1.EndInit();
bi1.Freeze();
//if you do not Freeze, your app will leak memory.

image control - dynamic load image from the resource file

I create in the code some image control and i want to set on this image control some of the picture that i saved ( load those pictures before creating the image control )
How can i do it ?
Specify your image in your Resource like this
<BitmapImage x:Key="SampleImageSource" UriSource="sample.png" />
and assign that to your image control like
<Image Source="{StaticResource SampleImageSource}" />
or if you are trying to do in code
img.Source = (ImageSource) Resources["SampleImageSource"];

How to display an image in Silverlight?

This should be simple, but...
I created a folder in my solution called Images. I dragged an image into it. How do I now display this image on a Page or View?
Make sure the image is set as a Resource. It can be in any folder in any of your projects in your solution.
You can then reference this as [assembly];component/[path]/[imagename.extension]
For example:
<Image Source="/mynamespace.myassembly;component/ResourcesFolder/image.png" Width="16" Height="16" />
There are a couple of ways to get at it--here's the way that involves setting the image as a Resource in the Visual Studio file properties:
using (var stream = Application.GetResourceStream(
new Uri("SilverlightAssemblyName;component/Images/myImage.png",
UriKind.Relative)))
{
// read from stream
}
Where SilverlightAssemblyName is replaced by the Assembly Name you specified in the Silverlight tab of your Silverlight project.
If you want to use the image in code:
var bitmap = new BitmapImage();
bitmap.SetSource(stream);
myImageControl.ImageSource = bitmap;
Or, if you want to use the resource in XAML, you don't need any of the code:
<Image Source="/Images/myImage.png" Width="16" Height="16" />

Resources