I have the following xaml (Note this is used in a Microsoft Workflow Foundation activity and is contained within a <sap:ActivityDesigner.Icon>. Hopefully, it won't matter but I thought I'd mention it.)
<DrawingBrush>
<DrawingBrush.Drawing>
<ImageDrawing>
<ImageDrawing.Rect>
<Rect Location="0,0" Size="16,16" ></Rect>
</ImageDrawing.Rect>
<ImageDrawing.ImageSource>
<BitmapImage UriSource="MyImage.png"/>
</ImageDrawing.ImageSource>
</ImageDrawing>
</DrawingBrush.Drawing>
</DrawingBrush>
I need to change the UriSource at run-time so I thought I'd use a converter as such:
<DrawingBrush>
<DrawingBrush.Drawing>
<ImageDrawing>
<ImageDrawing.Rect>
<Rect Location="0,0" Size="16,16" ></Rect>
</ImageDrawing.Rect>
<ImageDrawing.ImageSource>
<BitmapImage UriSource="{Binding Path=MyObject, Converter={StaticResource NameToImageConverter}}"/>
</ImageDrawing.ImageSource>
</ImageDrawing>
</DrawingBrush.Drawing>
</DrawingBrush>
but if try to bind it to my object and use a converter, I'm getting the following error:
The provided DependencyObject is not a context for this Freezable
Note that it doesn't hit my converter.
I found The provided DependencyObject is not a context for this Freezable WPF c# which I thought would help but to no avail.
When setting a name to the BitmapImage object
<BitmapImage Name="MyBitmapImage"/>
I thought I'd be able to set this via code but I still get the same error.
I don't know what I've done since originally looking at this but originally I got an error saying something along the lines that I should use a beginInit and endInit. Sorry don't have the exact error since I can't replicate it.
Any ideas on how this can be achieved?
Thanks.
A BitmapImage implements the ISupportInitialize interface and can only be initialized once, and not changed later. If your MyObject is supposed to change its value during runtime and notify the UI, that won't work.
You can change the Binding to
<ImageDrawing
ImageSource="{Path=MyObject, Converter={StaticResource NameToImageConverter}}"
Rect="0,0,16,16" />
and make the Binding Converter return a BitmapImage instead of an Uri:
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
...
string uri = ...;
return new BitmapImage(new Uri(uri));
}
Related
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.
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
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;
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
}
i got some xaml here and what i m trying to do it's simply bind a property call Property (not the real name) on the width of a rectangle and to convert the value of this property with the converter name Conv and it's working perfectly with {TemplateBinding Property} or DataContext={TemplateBinding Property} or with a relative source (like in the code sample).
My problem is that the converterParameter should also be a binding property, but i m not able to bind any property in the converterParameter. So the 30 in the sample should be something like {Binding Path=SecondProperty}. If anyone got that problem or maybe if anyone got some other way to bind stuff in custom control thanks a lot ;)
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="clr-namespace:RatingControl">
<Style TargetType="controls:Ctr">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="controls:Ctr">
<Grid>
<Grid.Resources>
<controls:Converter x:Name="Conv" />
</Grid.Resources>
<Rectangle x:Name="rect" Width="{Binding Path=Property, RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource Conv}, ConverterParameter=30}" Height="20" />
It doesn't look like that's possible: http://msdn.microsoft.com/en-us/library/system.windows.data.binding.converterparameter(VS.95).aspx
You can add a property to the Converter class and bind to that.
You can't bind to a property of the Binding object, since it isn't a DependencyProperty in fact Binding isn't a DependencyObject. This is understandable can you imagine the complexity of managing dependency trees and the possiblity of recursive or circular bindings in bindings.
However you could use a Specialised converter for the task:-
public class MySpecialConverter: IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
Ctr obj = (Ctr)value;
var val = obj.Property;
var param = obj.SecondProperty;
// Do your intended code with val and param here.
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException("This converter only works for one way binding");
}
}
now your Xaml looks like:-
<Rectangle x:Name="rect" Height="20"
Width="{Binding RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource Conv}" />
It's a really good solution but it's not working bcs my first property must be bind (twoWay) because if i got any change on it the converter must convert again the value so i get the result back and show the real result.