Error Binding ContentControl to Image from Resource Dictionary - c#

<Grid x:Name="ContentGrid">
<Grid.Resources>
<Image x:Key="art" Source="art.png" Stretch="None" />
</Grid.Resources>
<ContentControl Content="{Binding MyImg}" />
</Grid>
public Image MyImg
{
get { return (Image)GetValue(MyImgProperty); }
set { SetValue(MyImgProperty, value); }
}
public static readonly DependencyProperty MyImgProperty =
DependencyProperty.Register("MyImg", typeof(Image), typeof(MainPage), null);
public MainPage()
{
InitializeComponent();
ContentGrid.DataContext = this;
// Works.
MyImg = new Image() { Source = new BitmapImage(new Uri("art.png", UriKind.Relative)), Stretch = Stretch.None };
// Doesn't Work. Exception The parameter is incorrect. ???
MyImg = ContentGrid.Resources["art"] as Image;
}
ContentGrid.Resources["art"] as Image don't reuturn null but an image with the same source as art.png but assigning to the dependency property fails! why?

The second line isn't working because the image that you're referencing--the image in resources--doesn't have the source set up properly. In the first line, the one that works, you are properly setting up a BitmapImage and using a URI to reference the image. Your image in resources does not do that.
Therefore, try replacing your image in resources with this code:
<Image x:Key="art" Stretch="None">
<Image.Source>
<BitmapImage UriSource="art.png" />
</Image.Source>
</Image>

Related

Call GIF image source from the code behind in WPF c# for the tabcontrol's setter

i am using wpf tab control and setting the Icon and text in the tab header through style, i am able to set the text dynamically through getter and setter but can not able to set the image source. I tried to bind the image source through getter and setter but failed. Following is the style code in which i want to set the image source dynamically from the code behind.
-->
<Setter Property="HeaderTemplate" >
<Setter.Value>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<!--<Image gif:ImageBehavior.AnimatedSource="{DynamicResource MyFillBrush}" Width="20" />-->
<Image gif:ImageBehavior.AnimatedSource="25.gif" Width="20" />
<Label Content="{Binding }"/>
</StackPanel>
</DataTemplate>
</Setter.Value>
</Setter>
I know this is a bit old thread, but this is how you update the AnimatedSource from code:
var image = new BitmapImage();
image.BeginInit();
image.UriSource = new Uri(value);
image.EndInit();
ImageBehavior.SetAnimatedSource(Imagereference, image);
The 'value' is the location of your gif file such as "25.gif".
The Imagereference is the Image control you want to update. Also ensure you have the namespace referenced: using WpfAnimatedGif;
Maybe you can use Binding, something like
private string _dynamicGif = "test.gif";
public string DynamicGif
{
get { return _dynamicGif; }
private set
{
_dynamicGif = value;
RaisePropertyChanged("DynamicGif");
}
}
and
<Image gif:ImageBehavior.AnimatedSource="{Binding DynamicGif, UpdateSourceTrigger=PropertyChanged}" Width="20" />
Or, if it doesn't work, you can use MediaElement instead of Image, it won't require WPF Animated GIF. It's also pretty simple to use:
private Uri _imgSource = new Uri("test.gif");
public Uri ImgSource
{
get { return _imgSource; }
private set
{
_imgSource = value;
RaisePropertyChanged("ImgSource");
}
}
and
<MediaElement x:Name="gifImg" LoadedBehavior="Play" Width="20" Source="{Binding ImgSource}"/>
Hope this helps.

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

Set and Change Button Image by Cliciking on it WPF, C#

I've got a class, which holds 8 BitmapImage in an array. The Images are added in the following way in the class constructor:
public SymbolCollection(string[] symbolNames)
{
Symbols = new BitmapImage[8];
for (int i = 0; i < Symbols.Length; i++)
{
Symbols[i] = new BitmapImage();
Symbols[i].BeginInit();
Symbols[i].UriSource = new Uri(#"/Resources/" + symbolNames[i] + ".png", UriKind.Relative);
Symbols[i].EndInit();
}
}
The button's ImageSource are set to the following:
<Button x:Name="buttonPlayer1" HorizontalAlignment="Left" Height="80" Margin="44,387,0,0" VerticalAlignment="Top" Width="80" Click="OnPlayerSymbolClick">
<Button.Template>
<ControlTemplate>
<Image Source="{Binding Content}"/>
</ControlTemplate>
</Button.Template>
</Button>
I tried to set the image to the button in the MainWindow() method and change it in the OnPlayerSymbolClick() method, but the image doesn't even show up:
public MainWindow()
{
this.InitializeComponent();
SetSymbolCollection();
Uri u = symbolCollectionHolder[0].Symbols[0].UriSource;
Debug.WriteLine(u.ToString());
Image i = new Image();
BitmapImage bmp = new BitmapImage();
bmp.UriSource = u;
i.Source = bmp;
buttonPlayer1.Content = i;
}
private void OnPlayerSymbolClick(object sender, RoutedEventArgs e)
{
ImageBrush imagebrush = new ImageBrush();
imagebrush.ImageSource = symbolCollectionHolder[0].Symbols[1];
buttonPlayer1.Background = imagebrush;
buttonPlayer1.Content = imagebrush;
Debug.WriteLine(buttonPlayer1.Background.ToString());
Debug.WriteLine(imagebrush.ImageSource.ToString());
}
The Build Action for the png-s are set to Resource and there's a Resources folder in the project.
When an image resource file is to be loaded into a BitmapImage in code behind, you should use a Resource File Pack URI:
Symbols[i] = new BitmapImage(new Uri(
"pack://application:,,,/Resources/" + symbolNames[i] + ".png"));
Besides that, setting the Content or Background property is pointless when the Button's Template doesn't use these properties.
You probably wanted to write the Template like this:
<Button x:Name="buttonPlayer1" ...>
<Button.Template>
<ControlTemplate TargetType="Button">
<Image Source="{TemplateBinding Content}"/>
</ControlTemplate>
</Button.Template>
</Button>
which would require an ImageSource (or a derived object) as value of the Button's Content.
You could directly pass one of your Symbols:
buttonPlayer1.Content = Symbols[0];

Force an update to a control that's bound to the InkCanvas

I have the following XAML:
<Image Visibility="Visible"
Source="{Binding ElementName=inkCanvas,
Converter={StaticResource InkCanvasToImageSource},
UpdateSourceTrigger=PropertyChanged}">
</Image>
<InkCanvas x:Name="inkCanvas" />
What I'm trying to do is to convert the InkCanvas Stroke Collection into a BitmapImage. I'm using MVVM, and want to do this on a command. The problem that I have is that the above code will not trigger the converter to fire. I'm using UWP, so I can only pass one of the controls as a command parameter.
I need a method to convert from one to the other, but I'd like to do it inside the ViewModel.
An InkCanvas control is associated with an instance of an InkPresenter object (exposed through the InkPresenter property). The InkPresenter provides properties, methods, and events for managing the input, processing, and rendering of ink data for an InkCanvas control. So binding to InkCanvas won't trigger your converter to fire as the ink input is managed entirely by the InkPresenter. And InkCanvas.InkPresenter property is not a dependency property, we can't bind to this property. So we can't force the Image update with bingding to InkCanvas. We have to do it in code-behind and this may break the MVVM design.
To update the Image, we can use StrokesCollected and StrokesErased event to detect ink input and in these event save all InkStroke objects to a BitmapImage. For example:
In the XAML
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Image x:Name="MyImage" />
<Border Grid.Row="1" BorderBrush="Red" BorderThickness="2">
<InkCanvas x:Name="inkCanvas" />
</Border>
</Grid>
And in the code-behind:
public MainPage()
{
this.InitializeComponent();
...
inkCanvas.InkPresenter.StrokesCollected += InkPresenter_StrokesCollected;
inkCanvas.InkPresenter.StrokesErased += InkPresenter_StrokesErased;
}
private async void InkPresenter_StrokesErased(InkPresenter sender, InkStrokesErasedEventArgs args)
{
var image = await SaveAsync();
MyImage.Source = image;
}
private async void InkPresenter_StrokesCollected(InkPresenter sender, InkStrokesCollectedEventArgs args)
{
var image = await SaveAsync();
MyImage.Source = image;
}
private async Task<BitmapImage> SaveAsync()
{
var bitmap = new BitmapImage();
if (inkCanvas.InkPresenter.StrokeContainer.GetStrokes().Count > 0)
{
try
{
using (InMemoryRandomAccessStream stream = new InMemoryRandomAccessStream())
{
await inkCanvas.InkPresenter.StrokeContainer.SaveAsync(stream);
stream.Seek(0);
bitmap.SetSource(stream);
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex);
}
}
return bitmap;
}
Here I just set the image to MyImage, you can also set it to your ViewModel and use Binding in the Image.

WPF image source gif animation

How do I get the GIF animated to work with the code below? The problem is the image will change accordinly to few different image.
WPF:
<Image Source="{Binding ElementName=L, Path=Image}" Height="400" Width="600" Stretch="None" />
Code behind:
public readonly DependencyProperty ImageProperty;
public ImageSource ImageStatus
{
get { return (ImageSource)GetValue(ImageProperty); }
set { SetValue(ImageProperty, value); }
}
Image = new BitmapImage(new Uri("/L;component/Images/test.gif", UriKind.Relative));
EDITED:
http://eladm.wordpress.com/2009/04/02/animated-gif-support-behavior/
I have used this to make my gifs work: http://www.vcskicks.com/csharp_animated_gif.php
[edit]
I have found something for WPF: http://wpfanimatedgif.codeplex.com/
But I didn't test it!

Categories