WPF Custom Control with Image. - wpf

I am quite new to WPF/XAML and I am currently facing a problem.
I have a solution with two projects in it, the first project is a Custom Control Library with a custom Window form control inside. The second project is a WPF application using my custom window form.
All work fine except for the form Icon. In the WPF application project I set my window icon property to /ProjectTwoNameSpace;component/Resources/Images/Film.ico, and in the WPF custom control I try to show that image that way :
<Image Grid.Column="0" Margin="3" Width="27" Height="27">
<Image.Source>
<BitmapImage UriSource="{Binding Path=Icon}" />
</Image.Source>
</Image>
But it doesn't work, I get a error at runtime saying that the property UriSource or StreamSource must be set for my <Image> tag.
Anyone can help me ? I think it's jsut a WPF newbie problem.

The UriSource property of a BitmapImage cannot be set as you have shown because it is of type Uri and you are trying to set it to a string. I'd say the easiest way to accomplish what you're doing is to bind your Image.Source to Icon, and then convert the string to a bitmap Image object. Assuming your control is in a window, this would look something like this
<Window.Resources>
<converters:StringToBitmapImageConverter x:Key="stringToBitmapImageConverter" />
</Window.Resources>
...
<Image Grid.Column="0" Margin="3" Width="27" Height="27"
Source="{Binding Path=Icon, Converter={StaticResource stringToBitmapImageConverter}}">
</Image>
And then the converter would look like:
class StringToBitmapImageConverter: IValueConverter
{
#region IValueConverter Members
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
BitmapImage image = new BitmapImage();
image.BeginInit();
image.UriSource = new Uri(value as string);
image.EndInit();
return image;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
#endregion
}

Related

Why is my ImageSource Binding not updated?

I'm trying to dynamically bind an Image Source in XAML to an URI in ViewModel (MVVM). This works fine for the initial URI, the picture "C:\tmp\Test.png" is shown. But if I set another URI to ImageURI in ViewModel the picture is not updated. Can anyone help me?
XAML:
<Image x:Name="UserImage" Stretch="Fill" Grid.Row="0">
<Image.Source>
<BitmapImage CreateOptions="IgnoreImageCache" UriSource="{Binding ImageURI, UpdateSourceTrigger=Explicit, Mode=TwoWay}"/>
</Image.Source>
</Image>
ViewModel:
public string imageURI = "C:\\tmp\\Test.png";
public string ImageURI
{
get
{
return imageURI;
}
set
{
imageURI = value;
this.OnPropertyChanged("ImageURI");
}
}
BitmapImage implements ISupportInitialize. This means that property changes are ignored after initialization. Changing the Binding's source property has no effect.
You should directly bind the Image's Source property. Built-in automatic type conversion will create a BitmapFrame behind the scenes.
<Image Source="{Binding ImageURI}" .../>
Setting UpdateSourceTrigger=Explicit and Mode=TwoWay on the Binding is pointless.
If you need to explicitly create a BitmapImage (e.g. one where the IgnoreImageCache option is set), write an appropriate Binding Converter.
Pretty old question here with no solution. Sooo since i had a similar problem and used a slightly different approach, here is my solution:
Use a converter which returns a BitmapImage in this way:
public object Convert(object value, Type targetType, object parameter, CultureInfo culture) {
BitmapImage error = new();
error.BeginInit();
// OnLoad will give you errors just with the start of your application and
// and won't hide somewhere in your log
error.CacheOption = BitmapCacheOption.OnLoad;
error.UriSource = new Uri(#"pack://application:,,,/Images/error.png");
error.EndInit();
error.Freeze();
return error;
}
The binding:
<Image Source="{Binding Status, Converter={StaticResource enumAnalyzerStatusConverter}, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}" />
The OnLoad option will give an error on startup if something is bad with your image like the path. Remember to set the image in your project explorer to Ressource.

How to implement a Converter

I have a list of objects that I'm binding to the screen. One of the properties is isPurchased. It is a Boolean type.
I don't have a lot of experience with converters so I'm finding this a little difficult. I have 2 questions.
The 1st question is regarding syntax. I copied this example from here.
public class purchasedConverter : IValueConverter
{
public object Convert(inAppPurchases value, Type targetType, object parameter, string language)
{
return;
}
}
If the isPurchased == true then I'd like to set the background color to my stackpanel to a different color.
I changed object value to inAppPurchases value on the Convert method. However, no matter what I tried I could not get a reference to a Background.
I think I want to return Background="somecolor"
My 2nd question (assuming I can do the 1st part), is I'm using StandardStyles.xaml which comes with the Microsoft WinRT projects So my converter would exist there.
<StackPanel Grid.Column="1" VerticalAlignment="Top"
Background="CornflowerBlue" Orientation="Vertical" Height="130"
Margin="0,0,5,0"/>
However, like I said I've tried this before but I wasn't able to figure out how to add the convert to my .xaml file. Where would I reference the converter? Is it on the StandardStyls.xaml or the main .xaml that I'm viewing?
Any help is appreciated.
Background property of StackPanel is type of Brush (Panel.Background msdn) , so we can return object of type SolidColorBrush from Convert method.
Your converter should look like this:
class PurchasedConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
// isPurchased is bool so we can cast it to bool
if ((bool)value == true)
return new SolidColorBrush(Colors.Red);
else
return new SolidColorBrush(Colors.Orange);
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
Next you must create instance of this converter in XAML:
<Window.Resources>
<con:PurchasedConverter x:Key="pCon" />
</Window.Resources>
And now you can use this converter to binding Background property in StackPanel:
<StackPanel VerticalAlignment="Top" Orientation="Vertical" Height="130"
Background="{Binding isPurchased, Converter={StaticResource pCon}}"
Margin="0,0,5,0" >
</StackPanel>

multibind image source in xaml & wpf

In my project, i have a folder called Images, where all the images iam using in my application are saved in subfolders.All the images are set to "Resource" in the buildprocess.
myproject
|__Images
|__AppImages
|__StarOn.png
|__StarOff.png
Now, if i do set my image manually like this:
<Image Source="Images\AppImages\StarOn.png" width="32" height="32"/>
the image is correctly shown in the imagebox.
i would like to set the image using a converter and a binding like this:
<Image>
<Image.Source>
<Binding Path="Number" converter="{StaticResource GetImagePathConverter}"/>
</Image.Source>
</Image>
where the number is an integer
and my converter is:
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
int questionNr=int.parse(value.ToString());
if (questionNr>100)
{
return "Images\\AppImages\\StarOn.png";
}
return "Images\\AppImages\\starOff.png";
}
but this is not changing the image ?..
what iam doing wrong ?
how can i set the image source correctly from the converter ?
thanks in advance
Your way of using converter is incorrect. You need to create an instance of your converter use it in your binding through StaticResource. local: is the local namespace which you need to declare in your xaml -
<Image>
<Image.Resources>
<local:GetImagePathConverter x:Key="GetImagePathConverter"/>
</Image.Resources>
<Image.Source>
<Binding Path="Number" Converter="{StaticResource GetImagePathConverter}"/>
</Image.Source>
</Image>
Also, Source property is not of type string but instead ImageSource so you need something in your converter -
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
int questionNr=int.parse(value.ToString());
if (questionNr>100)
{
return new BitmapImage(new Uri("Images\\AppImages\\StarOn.png", UriKind.Relative));
}
return new BitmapImage(new Uri("Images\\AppImages\\StarOff.png", UriKind.Relative));
}
See this answer.
Basically, you have to take care of the type of object that you return in your converter, you cannot return string to a property of ImageSource type.
I'm not on my dev machine, but the code is something like this:
return new BitmapImage(new Uri(the/path/to/image.png)).Source; //or '*.ImageSource', can't remember

WPF Window Background ImageBrush not tiling

I have a window with a background image. The image may change at runtime which really should not matter for this.
I want the image to be fixed to the top left (which it is) and not scale (which is also correct. But I need the image to repeat (tile) when the window is made larger than the image. I am doing ...
What am i missing?
TIA
You need to set the TileMode property as well as the Viewport and ViewportUnits:
For example:
<Window.Background>
<ImageBrush ImageSource="myImage.png"
Viewport="0,0,300,300"
ViewportUnits="Absolute"
TileMode="Tile"
Stretch="None"
AlignmentX="Left"
AlignmentY="Top" />
</Window.Background>
Note: the second 2 segments of the Viewport attribute indicate the desired size of each repetition. If you want to display the entire image, these should be the width and height of the image.
Example output:
Edit in response to comments
If you don't know the size of the image to specify in the Viewport property, you can use a Binding with an IValueConverter to calculate it from the image. I am convinced there must be a better way of doing this, but I haven't found one yet!
XAML:
<Window.Resources>
<local:Converter x:Key="Converter" />
</Window.Resources>
<Window.Background>
<ImageBrush ImageSource="myImage.png"
ViewportUnits="Absolute"
TileMode="Tile"
Stretch="None"
AlignmentX="Left"
AlignmentY="Top"
Viewport="{Binding ImageSource, RelativeSource={RelativeSource Self}, Converter={StaticResource Converter}}"/>
</Window.Background>
Value converter:
public class Converter : IValueConverter
{
#region IValueConverter Members
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
var source = (ImageSource)value;
return new Rect(0,0,source.Width, source.Height);
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
#endregion
}
If you would like the entire solution in c#
ImageBrush brush = new ImageBrush();
brush.ImageSource = new BitmapImage(new Uri(#"c:\your\image\source.gif"));
brush.TileMode = TileMode.Tile;
brush.ViewportUnits = BrushMappingMode.Absolute;
brush.Viewport = new Rect(0, 0, brush.ImageSource.Width, brush.ImageSource.Height);
MainWindow1.Background = brush;

WPF Label adapt FontSize to it's Width and Height

I need to develop a Label control in WPF, on .NET 3.5 and VisualStudio 2010, in which the FontSize will automatically make the text fill the control area.
I don't know if I should create a CustomControl inheriting from Label or if I should create a UserControl which contains a Label control.
I've seen an example here using a ValueConverter, but I'm not understanding its behavior, here: change font size dynamically.
Can anyone give me a clue about that?
Update:
I found the solutiion using the DoubleConverter from the example I've posted before:
The soultion is using a ValueConverter, which I extracted from the example, but added the NumerFormat IFormatProvider to correctly parse "0.1" value, I found that at Decimal d1 = Decimal.Parse("0.1"); // = 1?!?:
[ValueConversion(typeof(object), typeof(double))]
public class DoubleConverter : IValueConverter
{
public object Convert(object value, Type targetType,
object parameter, CultureInfo culture)
{
double dblValue = (double)value;
double scale = Double.Parse(((string)parameter), System.Globalization.CultureInfo.InvariantCulture.NumberFormat);
return dblValue * scale;
}
public object ConvertBack(object value, Type targetType,
object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
Then, you have to instantiate in XAML the DoubleConverter, and specify the binding in the FonSize Property:
<UserControl x:Class="<Namespace>.LabelAutoFontSize"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:me="clr-namespace:<Namespace>"
mc:Ignorable="d"
d:DesignHeight="60" d:DesignWidth="278">
<UserControl.Resources>
<me:DoubleConverter x:Key="doubleConverter" />
</UserControl.Resources>
<Grid>
<Label
x:Name="lbl"
FontSize="{
Binding Path=Width,
RelativeSource={RelativeSource AncestorType={x:Type UserControl}},
Converter={StaticResource doubleConverter},
ConverterParameter=0.116}"
VerticalAlignment="Stretch"
HorizontalAlignment="Stretch"
Content="LabelAutoFontSize"
d:LayoutOverrides="Width"
HorizontalContentAlignment="Center"
VerticalContentAlignment="Center" />
</Grid>
</UserControl>
An important point is that the value for ConverterParameter depends absolutely from the font assigned. Each font may need a different value and you have to "play around" to get the correct value to fit exactly.
<Viewbox>
<TextBlock>asd</TextBlock>
</Viewbox>
Also does the job.

Resources