Programmatically setting Image.Source property: I get an empty image - c#

I have a folder inside my project which includes some images, for example: "Cards/1-1.png".
I have an Image element linked with XAML, and I'm trying to set it's Source property programmatically:
BitmapImage bitmap = new BitmapImage();
string filename= "Cards/1-1.png";
bitmap.UriSource = new Uri("/Poker;component/" + filename, UriKind.Relative);
cardImage1.Source= bitmap; // myImage linked with XAML
I try to fill 5 images, and I checked the filenames, they're correct. But the images are still empty (they're inside the StackPanel on the right):
<StackPanel Orientation="Horizontal" DockPanel.Dock="Right"
Background="Green">
<Image Width="80" Height="100" Margin="10" x:Name="cardImage1"/>
<Image Width="80" Height="100" Margin="10" x:Name="cardImage2"/>
<Image Width="80" Height="100" Margin="10" x:Name="cardImage3"/>
<Image Width="80" Height="100" Margin="10" x:Name="cardImage4"/>
<Image Width="80" Height="100" Margin="10" x:Name="cardImage5"/>
</StackPanel>

BitmapImage implements ISupportInitialize interface which means any property change after initialization of object will be ignored unless wrap in BeginInit() and EndInit().
Quote from MSDN:
BitmapImage implements the ISupportInitialize interface to optimize
initialization on multiple properties. Property changes can only occur
during object initialization. Call BeginInit to signal that
initialization has begun and EndInit to signal that initialization has
completed. After initialization, property changes are ignored.
BitmapImage objects created using the BitmapImage constructor are
automatically initialized and property changes are ignored.
So, change your code to wrap property initialization like this:
BitmapImage bitmap = new BitmapImage();
string filename= "Cards/1-1.png";
bitmap.BeginInit();
bitmap.UriSource = new Uri("/Poker;component/" + filename, UriKind.Relative);
bitmap.EndInit();
cardImage1.Source= bitmap; // myImage linked with XAML
OR
Initialize all relevant properties at time of initialization by passing Uri in constructor like this:
string filename= "Cards/1-1.png";
BitmapImage bitmap = new BitmapImage(new Uri("/Poker;component/" + filename,
UriKind.Relative));

I tried this code but it isn't working, i found a way to do what you exactly need:
cardImage1.Source = new BitmapImage(new Uri("/Poker;component/" + filename, UriKind.Relative));
you assigned BitmapImage.Source to Image.Source, i think that's why it isn't working.
Hope it helps.

Related

How to put an Image in WPF Window [duplicate]

It seems like it's quite complicated to load an image in runtime to a WPF window.
Image image;
image = new Uri("Bilder/sas.png", UriKind.Relative);
????.Source = new BitmapImage(image);
I'm trying this code, but I need some help to get it to work. I get some red lines below the code! I also wonder if I need to add some extra code inside the XAML code or is in enough with this:
<Image Height="200" HorizontalAlignment="Left" Margin="12,12,0,0" Name="image1"
Stretch="Fill" VerticalAlignment="Top" Width="350" />
Wonder because I have seen examples with sorces to the images inside the XAML tags.
EDIT:
I'm using this now:
var uri = new Uri("pack://application:,,,/sas.png");
var bitmap = new BitmapImage(uri);
image1.Source = bitmap;
The XAML:
<Grid Width="374">
<Image Height="200" HorizontalAlignment="Left" Margin="12,12,0,0" Name="image1" Stretch="Fill" VerticalAlignment="Top" Width="350" />
<Button Content="Start" Height="23" HorizontalAlignment="Left" Margin="12,226,0,0" Name="btnStart" VerticalAlignment="Top" Width="75" />
<Button Content="Land" Height="23" HorizontalAlignment="Left" Margin="287,226,0,0" Name="btnLand" VerticalAlignment="Top" Width="75" />
<ComboBox Height="23" HorizontalAlignment="Left" Margin="110,226,0,0" Name="cmbChangeRoute" VerticalAlignment="Top" Width="156" />
</Grid>
EDIT 2:
My issue is solved, this code works fine:
BitmapImage image = new BitmapImage(
new Uri("pack://application:,,,/Resources/" + company + ".png"));
image2.Source = image;
In WPF an image is typically loaded from a Stream or an Uri.
BitmapImage supports both and an Uri can even be passed as constructor argument:
var uri = new Uri("http://...");
var bitmap = new BitmapImage(uri);
If the image file is located in a local folder, you would have to use a file:// Uri. You could create such a Uri from a path like this:
var path = Path.Combine(Environment.CurrentDirectory, "Bilder", "sas.png");
var uri = new Uri(path);
If the image file is an assembly resource, the Uri must follow the the Pack Uri scheme:
var uri = new Uri("pack://application:,,,/Bilder/sas.png");
In this case the Visual Studio Build Action for sas.png would have to be Resource.
Once you have created a BitmapImage and also have an Image control like in this XAML
<Image Name="image1" />
you would simply assign the BitmapImage to the Source property of that Image control:
image1.Source = bitmap;
Make sure that your sas.png is marked as Build Action: Content and Copy To Output Directory: Copy Always in its Visual Studio Properties...
I think the C# source code goes like this...
Image image = new Image();
image.Source = (new ImageSourceConverter()).ConvertFromString("pack://application:,,,/Bilder/sas.png") as ImageSource;
and XAML should be
<Image Height="200" HorizontalAlignment="Left" Margin="12,12,0,0"
Name="image1" Stretch="Fill" VerticalAlignment="Top"
Source="../Bilder/sas.png"
Width="350" />
EDIT
Dynamically I think XAML would provide best way to load Images ...
<Image Source="{Binding Converter={StaticResource MyImageSourceConverter}}"
x:Name="MyImage"/>
where image.DataContext is string path.
MyImage.DataContext = "pack://application:,,,/Bilder/sas.png";
public class MyImageSourceConverter : IValueConverter
{
public object Convert(object value_, Type targetType_,
object parameter_, System.Globalization.CultureInfo culture_)
{
return (new ImageSourceConverter()).ConvertFromString (value.ToString());
}
public object ConvertBack(object value, Type targetType,
object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
Now as you set a different data context, Image would be automatically loaded at runtime.

ImageFailed with GridView

I have a problem with GridView and multiple items. Each of the item has image in it, source is online image, bound to property, like this:
<GridView x:Name="gridView" Width="710" ItemTemplate="{StaticResource FirstTemplate}" AllowDrop="True" CanDragItems="True" CanReorderItems="True">
<DataTemplate x:Key="FirstTemplate">
<Grid HorizontalAlignment="Left" Width="306" Height="210">
<Border Background="White" Opacity="0.1"/>
<Image Stretch="Uniform" Width="190" Height="100" Margin="0,50,0,0" ImageFailed="ImageFailed" Source="{Binding ImagePath}"/>
</Grid>
</DataTemplate>
Image paths are like this:
www.example.com/images/1.png
www.example.com/images/2.png
www.example.com/images/3.png
and so on...
If some image not exist, for example www.example.com/images/29.png, I use the event ImageFailed, which change the source of the image to image that is located in my project (default image). Code in this event:
private void ImageFailed(object sender, ExceptionRoutedEventArgs e)
{
var image = sender as Image;
image.Source = new BitmapImage(new Uri("ms-appx:///Images/default.png"));
}
And this is working just fine, the default image is shown in the items that don't have images. But, when I scroll down the gridview, and then return to the beginning, images are messed up. Some items that had their images, now have the default image. Again when I scroll the gridview, and then return, again random changes with images.
Is this some cache problem? What could be the problem here? Or is there any better way of setting the default image source?
The source of your problem could be virtualization, i.e. reuse of item containers. When you replace a failed image by a fallback image in your ImageFailed handler, you are effectively replacing the Binding by a fixed value, so that the item container will later always show only the fallback image.
You may instead implement the ImageFailed handler in the view model, so that replacing the image with a fallback image won't break the Binding.
Add another property, e.g. Image to your item class
public class ImageItem
{
public string ImagePath { get; set; }
private BitmapImage image;
public BitmapImage Image
{
get
{
if (image == null)
{
image = new BitmapImage();
image.ImageFailed += (s, e) =>
image.UriSource = new Uri("ms-appx:///Images/default.png");
image.UriSource = new Uri(ImagePath);
}
return image;
}
}
}
and change the Binding to this:
<Image ... Source="{Binding Image}"/> // no ImageFailed handler here

Load PNG from code behind [duplicate]

It seems like it's quite complicated to load an image in runtime to a WPF window.
Image image;
image = new Uri("Bilder/sas.png", UriKind.Relative);
????.Source = new BitmapImage(image);
I'm trying this code, but I need some help to get it to work. I get some red lines below the code! I also wonder if I need to add some extra code inside the XAML code or is in enough with this:
<Image Height="200" HorizontalAlignment="Left" Margin="12,12,0,0" Name="image1"
Stretch="Fill" VerticalAlignment="Top" Width="350" />
Wonder because I have seen examples with sorces to the images inside the XAML tags.
EDIT:
I'm using this now:
var uri = new Uri("pack://application:,,,/sas.png");
var bitmap = new BitmapImage(uri);
image1.Source = bitmap;
The XAML:
<Grid Width="374">
<Image Height="200" HorizontalAlignment="Left" Margin="12,12,0,0" Name="image1" Stretch="Fill" VerticalAlignment="Top" Width="350" />
<Button Content="Start" Height="23" HorizontalAlignment="Left" Margin="12,226,0,0" Name="btnStart" VerticalAlignment="Top" Width="75" />
<Button Content="Land" Height="23" HorizontalAlignment="Left" Margin="287,226,0,0" Name="btnLand" VerticalAlignment="Top" Width="75" />
<ComboBox Height="23" HorizontalAlignment="Left" Margin="110,226,0,0" Name="cmbChangeRoute" VerticalAlignment="Top" Width="156" />
</Grid>
EDIT 2:
My issue is solved, this code works fine:
BitmapImage image = new BitmapImage(
new Uri("pack://application:,,,/Resources/" + company + ".png"));
image2.Source = image;
In WPF an image is typically loaded from a Stream or an Uri.
BitmapImage supports both and an Uri can even be passed as constructor argument:
var uri = new Uri("http://...");
var bitmap = new BitmapImage(uri);
If the image file is located in a local folder, you would have to use a file:// Uri. You could create such a Uri from a path like this:
var path = Path.Combine(Environment.CurrentDirectory, "Bilder", "sas.png");
var uri = new Uri(path);
If the image file is an assembly resource, the Uri must follow the the Pack Uri scheme:
var uri = new Uri("pack://application:,,,/Bilder/sas.png");
In this case the Visual Studio Build Action for sas.png would have to be Resource.
Once you have created a BitmapImage and also have an Image control like in this XAML
<Image Name="image1" />
you would simply assign the BitmapImage to the Source property of that Image control:
image1.Source = bitmap;
Make sure that your sas.png is marked as Build Action: Content and Copy To Output Directory: Copy Always in its Visual Studio Properties...
I think the C# source code goes like this...
Image image = new Image();
image.Source = (new ImageSourceConverter()).ConvertFromString("pack://application:,,,/Bilder/sas.png") as ImageSource;
and XAML should be
<Image Height="200" HorizontalAlignment="Left" Margin="12,12,0,0"
Name="image1" Stretch="Fill" VerticalAlignment="Top"
Source="../Bilder/sas.png"
Width="350" />
EDIT
Dynamically I think XAML would provide best way to load Images ...
<Image Source="{Binding Converter={StaticResource MyImageSourceConverter}}"
x:Name="MyImage"/>
where image.DataContext is string path.
MyImage.DataContext = "pack://application:,,,/Bilder/sas.png";
public class MyImageSourceConverter : IValueConverter
{
public object Convert(object value_, Type targetType_,
object parameter_, System.Globalization.CultureInfo culture_)
{
return (new ImageSourceConverter()).ConvertFromString (value.ToString());
}
public object ConvertBack(object value, Type targetType,
object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
Now as you set a different data context, Image would be automatically loaded at runtime.

WPF conversion file from base64 and assignment source - c#

I gather from json files that the user clicks on a wpf list ( c # ) .
Click to call a json pass me the file content in Base64 . I would convert it and have it displayed immediately without writing it on the user's hard .
And ' possible to convert it and leave it on the ram can then see immediately , as well as assign it to the object's source imageViewer?
Thank you
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="40"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
</Grid.RowDefinitions>
<TextBlock FontFamily="{StaticResource Lato Thin}" Margin="10,0,0,0" Foreground="#007AFF" Text="{x:Static res:strings.indietroPage}" MouseDown="GoBackFrame_MouseDown" FontSize="20" Grid.Row="0" HorizontalAlignment="Left" VerticalAlignment="Center"/>
<Image Grid.Row="1" Source="{Binding uriImageSource}" Name="imageViewer"></Image>
</Grid>
first I was saving to disk first and then visualized , but I need that is not saved to disk , and you receive immediately as Source
File.WriteAllBytes(System.IO.Path.GetTempPath() + attachmentDownload.Name + "." + attachmentDownload.Extension, Convert.FromBase64String(attachmentDownload.B64Content));
i have try this
fileSourceBytes = Convert.FromBase64String(attachmentDownload.B64Content);
BitmapImage bi = new BitmapImage();
bi.BeginInit();
bi.StreamSource = new MemoryStream(fileSourceBytes);
bi.EndInit();
imageViewer.Source = bi;
but receive an error:
Object reference not set to an instance of an object.
solution:
codebehind
public Byte[] fileSourceBytes { get; set; }
fileSourceBytes = Convert.FromBase64String(attachmentDownload.B64Content);
BitmapImage bi = new BitmapImage();
bi.BeginInit();
bi.CacheOption = BitmapCacheOption.OnLoad;
bi.StreamSource = new MemoryStream(fileSourceBytes);
bi.EndInit();
uriImageSource = bi;
xaml:
<Image Grid.Row="1" Source="{Binding uriImageSource}" Name="imageViewer"></Image>
Maybe the best solution would be if you would just bind the BitmapImage to the ImageViewer's Source property.
ViewModel:
BitmapImage _imageViewerSource;
public BitmapImage ImageViewerSource {
get { return _imageViewerSource; }
private set
{
_imageViewerSource = value;
OnPropertyChanged("ImageViewerSource"); // or OnPropertyChanged(nameof(ImageViewerSource)); if you are using VS2015+
}
}
Xaml:
<Image Source="{Binding ImageViewerSource, Mode=OneWay}"/>
This should solve your problem issue
using (InMemoryRandomAccessStream stream = new InMemoryRandomAccessStream())
{
using (DataWriter writer = new DataWriter(stream.GetOutputStreamAt(0)))
{
writer.WriteBytes(Convert.FromBase64String(base64););
writer.StoreAsync().GetResults();
}
BitmapImage image = new BitmapImage();
image.SetSource(stream);
}

Converted BitmapImage not displaying on Page

I am having a problem with my Windows Phone application. When I get the photo from a web service, I want to display it as an image on the page. The web service returns a byte[] as the image data.
Dispatcher.BeginInvoke(() =>
{
tempImage = new BitmapImage();
globalWrapper = (PhotoWrapper)JsonConvert.DeserializeObject(
response.Content, typeof(PhotoWrapper));
tempImage.SetSource(new MemoryStream(globalWrapper.PictureBinary, 0,
globalWrapper.PictureBinary.Length));
globalWrapper.ImageSource = tempImage;
PictureList.Items.Add(globalWrapper);
});
PictureList is a ListBox defined as:
<ListBox Name="PictureList" ItemsSource="{Binding}" Margin="0,0,0,0">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<Button Click="details_Click">
<Button.Content>
<Image Source="{Binding ImageSource}"></Image>
</Button.Content>
</Button>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Now, my question is, how do you receive a byte[] from a webservice as JSON and display it on the page? I feel like I am pretty close here but am missing something rather elementary.
If you're certain that the byte[] data is valid, it could be something to do with the CacheOption property of the BitmapUmage. This property controls when data is actually loaded from the stream into the bitmap. The default is OnDemand, which only loads data from the stream when the image is displayed. You might want to try the OnLoad option instead, which loads it immediately, allowing you to close the stream.
Dispatcher.BeginInvoke(() =>
{
globalWrapper = (PhotoWrapper)JsonConvert.DeserializeObject(
response.Content, typeof(PhotoWrapper));
tempImage = new BitmapImage();
tempImage.BeginInit();
tempImage.CacheOption = BitmapCacheOption.OnLoad;
tempImage.SetSource(new MemoryStream(globalWrapper.PictureBinary, 0,
globalWrapper.PictureBinary.Length));
tempImage.EndInit();
globalWrapper.ImageSource = tempImage;
PictureList.Items.Add(globalWrapper);
});

Categories