Images bound to images added to resx files using XAML - wpf

My WPF application includes a resource file MyResources.resx, containing several strings and images. Because the application will need to be localized, all my references to globalized resources must be made via named properties of the auto-generated MyResources class. The following code works well for string resources:
<Button Content="{x:Static local:Properties.MyResources.ButtonText}" />
However the same does not work for images. Assuming I have an image eflag.bmp added to the resources as a resource named Flag, I would like to be able to do something like this:
<Image Source="{x:Static local:Properties.MyResources.Flag}" />
Please note that the following alternative approach:
<Image Source="/MyNamespace;component/Resources/eflag.bmp" />
cannot be used in this case because it will not be able to handle localization. The problem can be solved using code behind but I am looking for a XAML based solution.

Turn your x:Static into a Binding.Source and add a Converter which does Bitmap to ImageSource.
Source="{Binding Source={x:Static local:Properties.MyResources.Flag},
Converter={StaticResource BitmapToImageSourceConverter}}"
Alternatively you can make the converter a custom markup extension which takes a Bitmap and returns the ImageSource in ProvideValue.
Source="{me:BitmapToImageSource {x:Static local:Properties.MyResources.Flag}}"

Related

MahApps panoram control not displaying photo's

I want use the MahApps PanoramaControl to display a bunch of photo's. However I see only the string paths appear in the control, which will be correct if you look at my code.
But I can't figure out howto get it working to show the images instead of the links.
Xaml:
<Controls:Panorama Grid.Row="2"
Grid.ColumnSpan="4"
ItemBox="140"
ItemsSource="{Binding PhotoCollection, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
ViewModel:
string[] filePaths = Directory.GetFiles(#"D:\Google Drive\Images\Backgrounds");
test = new PanoramaGroup("My Photo's", filePaths);
PhotoCollection = new ObservableCollection<PanoramaGroup> { test };
Anyone an idea on how to make it show the images? The control is load as I can scroll sideways on the text.
There is not much documentation on their site on how to get it working...
Or are you using some other Metro style lib for the 4.0 framework?
In order to get MahApps Panorama control i would offer the follow solution below. As to other frameworks that provide this level of detailed MODERN UI experience I have not come across any but interested to know if you do.
Hope the solutions works for you.
You need to add a Data Template the represent the object you're showing.
Start off by defining the object in a POCO class (as illustrated below). Then in the population of the items ensure you translate them to the newly created POCO object instead of leaving them as string values.
public class Photo {
public string Path { get; set; }
}
Next in the definition of you XAML window you need to create a reference to the namespace where the POCO object resides.
xmlns:model="clr-namespace:project.models;assembly=project"
Last, but not least, you want to then create a DataTemplate to represent the object. This is added to the window resources.
<Window.Resources>
<DataTemplate DataType="{x:Type model:Photo}">
<Image Source="{Binding Path}"/>
</DataTemplate>
</Window.Resources>
This should then let the render take place in the interface where it belongs. Hope this works for you.

Using app-level resources in the Generic.xaml file of a custom control library

I have a button on a custom control and I'm trying to display an image on it which is defined as a resource in my App.xaml file like so:
<Application.Resources>
<BitmapImage x:Key="PlusSymbol" UriSource="Resources/PlusSymbol.png" />
</Application.Resources>
For some reason I can't use this as a static resource within my custom control's template defined in the Themes\Generic.xaml file, it crashes my application during runtime saying that it cannot find the requested resource. Here's the xaml code I'm using to bind to the resource:
<Button Grid.Row="0" Grid.Column="1" Margin="3">
<Image Source="{StaticResource PlusSymbol}"/>
</Button>
It DOES work during runtime if I define the resource the exact same way but within the Generic.xaml file, however it gives me a pre-compiler warning that it can't find the file since it's now looking for it in Themes/Resources/ rather than just in /Resources/. So I get a warning during design time but it works fine in runtime.
So why can't it find my resource when it's defined in App.xaml? I do this the exact same way in a regular WPF project and it works flawlessly, but in this custom control library it is giving me headaches. Any help is much appreciated!
This should work if you switch your StaticResource to DynamicResource so that the resource will be evaluated dynamically at runtime rather than statically. If you switch to DynamicResource.
<Button Grid.Row="0" Grid.Column="1" Margin="3">
<Image Source="{DynamicResource PlusSymbol}"/>
</Button>
I believe this is because of how theme-based styles and templates are handled, as opposed to standard resources. This answer and this answer speak specifically to Generic.xaml and how it is different from other ResourceDictionaries.
So the way I ended up getting this to work was by defining the BitmapImage in the Generic.xaml file and using a Pack URI to get to the file (here's the MSDN article about Pack URIs, which frankly just confused me). This way it's using a relative path to the file, and specifying the assembly that it's coming from (the file is located at \Resources\PlusSymbol.png in the MyCustomControlLibrary project and has a build action of Resource):
<BitmapImage x:Key="PlusSymbol" UriSource="pack://application:,,,/MyCustomControlLibrary;component/Resources/PlusSymbol.png" />
Then in the control template in Generic.xaml I use the resource like so:
<Button Grid.Row="0" Grid.Column="1" Margin="3" Height="25" Width="25"
<Image Source="{StaticResource PlusSymbol}"/>
</Button>
Note that I got fooled thinking that I could use the shorter version of the Pack URI like so:
<BitmapImage x:Key="PlusSymbol" UriSource="pack://application:,,,/Resources/PlusSymbol.png" />
However this was still causing the program to crash at runtime. I think the fact that this is a custom control library, and that the end consumer of the image is my UI project, makes the longer version which specifies the assembly that actually contains the image necessary.
Hope that helps anyone else who is having similar problems.
Note I don't think this technically answers my original question which specified using app-level resources (aka defined in the custom control library's App.xaml file) from Generic.xaml. Defining the PlusSymbol resource there still crashes the program. However I didn't actually care about doing it in App.xaml, I was just trying to get it to work right at both design time and run time. This solution does the trick for me, is fairly simple, and from what I can tell from my research is the best practice.

Can you programmatically set a property in a ControlTemplate from a ChildWindow?

I am working on a Silverlight application that has resource files that define styles for the different types of Child Windows in the application. The <Style> contains <ControlTemplate> markup with various content. Is there a way to set one of the properties of the controls defined within the <ControlTemplate> from the Child Window's class?
For example, imagine in the resource file I have markup like the following:
<Style x:Key="MyChildWindowStyle" TargetType="sdk:ChildWindow">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="sdk:ChildWindow">
<Grid x:Name="Root">
...
<Image Source="/Assets/image.png" />
...
</Grid>
</ContentTemplate>
</Setter>
</Style>
Now assume that I have a number of child windows that are configured to use this style. What I'd like to be able to do is from the code in those child windows be able to programmatically change the value of the image's Source.
Is this possible?
Thanks
In your resources you can do this:
<BitmapImage x:Key="MyImage" Source="/Assets/image.png"/>
<Style x:Key="MyChildWindowStyle" TargetType="sdk:ChildWindow">
...
<Image Source="{DynamicResource MyImage}" />
...
</Style>
Then in your child window's code-behind you can do this:
Resources["MyImage"] = new BitmapImage(new Uri("/Assets/other-image.png"));
But if your child window class is in another assembly you should be writing the uri a bit different:
Resources["MyImage"] = new BitmapImage(new Uri("pack://application:,,,/MyOtherAssemblyShortName;component/Assets/other-image.png"));
You can check msdn page for package uri format.
But I suggest you to use MVVM pattern in order to get most out of WPF in terms of bindings, styling etc. When you have a view model instead of a code-behind these things become simpler. You may wanna check the related msdn page, a codeproject sample, a toolkit or a validation mechanism designed for MVVM.
#zahir's answer pointed me in the right direction, but to get it to work in Silverlight I had to do the following:
First, I added the <BitmapImage> markup to my resource file, using the UriSource property to specify the default value.
<BitmapImage x:Key="MyImage" UriSource="../Assets/DefaultImage.png" />
Next, I referenced it in the <ControlTemplate> like so:
<Image ... Source="{StaticResource MyImage}"/>
Then, in my code-behind class I was able to modify the UriSource property like so:
BitmapImage img = (Application.Current.Resources["MyImage"] as BitmapImage);
if (img != null)
img.UriSource = "../Assets/NewImage.png";
Of course, the precise values for UriSource would depend on how you are handling image assets, where they are located, etc.

binding an image source in XAML

I am trying to bind an image source to my XAML through c#
this works
<Image Source="images/man.jpg"></Image>
this does not work
<Image Source="images/{Binding imagesource}"></Image>
where imagesource is a string variable in the c# file of this xaml and is being set equal to "man.jpg"
here is a way how to do it in XAML:
add this to the namespace:
xmlns:System="clr-namespace:System;assembly=mscorlib"
then add your images paths
<System:String x:Key="ImageRefresh">/Theme;component/Images/icon_refresh.png</System:String>
<System:String x:Key="ImageSearch">/Theme;component/Images/icon_search.png</System:String>
This is how you use it
<Image Height="16" Source="{StaticResource ImageSearch}" Stretch="Uniform" Width="16"/>
This works ok, but if you load your xaml style in Blend it will go bogus..
An object of type "System.String" cannot be applied to a property that expects the type "System.Windows.Media.ImageSource".
I haven't figured out yet, how to replace System:String with that Media.ImageSource... but hey.. it works for me in Visual Studio.
You can't stick a binding mid-way through the value like that. It's either a binding, or it's not. Assuming imagesource is publicly accessible via your DataContext, you could do this:
<Image Source="{Binding imagesource}"/>
However, if it's been set to "man.jpg" then it won't find the image. Either set imagesource to the full path ("images/man.jpg") or use a converter:
<Image Source="{Binding imagesource, Converter={StaticResource RelativePathConverter}}"/>
The converter would prepend "images/" onto its value. However, it may be necessary for the converter to return an ImageSource rather than a string.
Images have bitten me in the past. There is a certain lookup order involved.
When you use "image/man.jpg" it could refer to a file inside your silverlight xap, or relative to the location of XAP file. For example, it could be in YourProject.Web/ClientBin/image/man.jpg.
You should troubleshoot by using full URLs first and find out if this works.
imagesource needs to be an actual Image object, not a string.
Here is a method that will create a new Image object given a path:
public BitmapImage Load(string path)
{
var uri = new Uri(path);
return new BitmapImage(uri);
}

WPF relative path problem

I have created a custom TaskButton control that takes an image and text. The properties are set like this:
<custom:TaskButton Text="Calendar" ImagePath="Images/calendar.png" ... />
My custom control class implements Text and ImagePath properties, and the control template for the custom control (in Themes\Generic.xaml) sets its content like this, using a RelativeSource object to get the image path:
<!-- Button Content -->
<StackPanel>
<Image Source="{Binding Path=ImagePath, RelativeSource={RelativeSource TemplatedParent}}" Width="24" Height="24" Stretch="Fill" Margin="10,0,0,0" />
<TextBlock Text="{TemplateBinding Text}" HorizontalAlignment="Center" VerticalAlignment="Center" FontFamily="Segoe UI" FontWeight="Bold" Margin="6,0,10,0" Foreground="Black" />
</StackPanel>
The control works fine in most cases, but in a particular project, the relative path to the button's image does not get resolved correctly, and the button image is not displayed. Here is what I have figured out so far:
I am entering the path correctly when I use the custom control. If I place an image control on the same design surface with the same relative path, it is resolved correctly.
The problem is with the relative path. If I replace the relative path with an absolute path, the path is resolved correctly and the image is displayed.
As I mentioned above, the control works fine in most cases. The one case where it isn't working is a Prism 2.1 project, where the control is instantiated on a user control in a Prism module. The module is a simple class library, but it has all of the references of a WPF project.
Any idea why the relative path would fail? Thanks in advance for your help.
I finally figured out the problem. It was actually in the C# backing class for my control. I declared an ImagePath property as a string, since that was how I was going to specify the image. Oops--bad call on my part. That property should actually be an ImageSource property, not a string. WPF has a built-in ImageSourceConverter class that will resolve the path and return the specified image. So, I simply changed the property name from ImagePath to Image, and changed its type from string to ImageSource. That solved the problem.
Thanks to Aviad P. for taking a crack at this. It was unsolvable without the C# code showing the property declarations. I'll post all code and markup next time.

Resources