I'm working on a custom control. This custom control has an image in it like this:
<Image Source="{TemplateBinding Poster}" />
In my C# file, the DependencyProperty is the following:
public static readonly DependencyProperty PosterProperty = DependencyProperty.Register(
nameof(Poster),
typeof(ImageSource),
typeof(MovieButton),
new UIPropertyMetadata(null));
public ImageSource Poster
{
get { return (ImageSource)GetValue(PosterProperty); }
set { SetValue(PosterProperty, value); }
}
Now I can add the following to my user control in XAML: Poster="Images/NoPoster.png" or Poster = new BitmapImage(new Uri(#"pack://application:,,,/Images/NoPoster.png")) from code.
Everything is working fine. What I'm wondering is, why can't I declare Poster as BitmapImage or string instead of ImageSource?
You can of course declare it as BitmapImage. But that would be an unnecessary restriction, because the base class ImageSource is sufficient.
You can also use string or Uri as property type, but then you should replace the TemplateBinding by a regular Binding, because source and target property types no longer match, and built-in automatic type conversion should take place:
<Image Source="{Binding Poster, RelativeSource={RelativeSource TemplatedParent}}" />
Note that you do not need an explicit binding converter, because type conversion is performed automatically by the ImageSourceConverter class, which is registered as type converter for ImageSource.
Related
I have a user control. With XAML. It has it's own properties, it has its ViewModel object set as DataContext:
<ComboBox ItemsSource="{Binding Items}" SelectedIndex="0">
<ComboBox.DataContext>
<vm:WindowsProfilePicker />
</ComboBox.DataContext>
Binding to its DataContext value properties is super easy and works as expected.
Let's say:
<Image Source="{Binding UserImage}" />
UserImage is a property of the ViewModel.
The Image element is however a part of my user control. The control has its own property named ImageSize defined as follows:
public static readonly DependencyProperty ImageSizeProperty
= DependencyProperty.Register(
"ImageSize",
typeof(double),
typeof(WindowsProfilePicker),
new FrameworkPropertyMetadata(126.0)
);
Of course we have getter and setter for it in code:
public double ImageSize {
get => (double)GetValue(ImageSizeProperty);
set => SetValue(ImageSizeProperty, value);
}
Now I would want to reference that property in my UserControl's XAML. It looks like this:
<Image
Width="
{Binding RelativeSource={RelativeSource AncestorType=local:WindowsProfilePicker},
Path=ImageSize}"
Height="{Binding RelativeSource={RelativeSource AncestorType=local:WindowsProfilePicker},
Path=ImageSize}"
Source="{Binding UserImage}" />
Nice? Not really, and it doesn't work. I get no errors, no warnings, but the image size is not set. The image in the control sets its size from the source bitmap size. When I replace my binding with a number, it works, the size is fixed. However, I want ImageSize property of my new control to be used as Image Width and Height. What am I doing wrong?
BTW, obviously I don't want the property to be bound with my ViewModel, because it's strictly presentation feature, unrelated to data.
The visuals like sizes must be set in XAML (optimally as styles), the data (in my case user profile pictures) in code, the control's ViewModel.
Try configuring property metadata somewhat like this:
public static readonly DependencyProperty ImageSizeProperty
= DependencyProperty.Register(
"ImageSize",
typeof(double),
typeof(WindowsProfilePicker),
new FrameworkPropertyMetadata((double)126.0,
FrameworkPropertyMetadataOptions.BindsTwoWayByDefault
| FrameworkPropertyMetadataOptions.AffectsRender
| FrameworkPropertyMetadataOptions.AffectsMeasure)
);
[TypeConverter(typeof(LengthConverter))]
public double ImageSize
{
get => (double)GetValue(ImageSizeProperty);
set => SetValue(ImageSizeProperty, value);
}
or
public static readonly DependencyProperty ImageSizeProperty
= DependencyProperty.Register(
"ImageSize",
typeof(double),
typeof(WindowsProfilePicker),
new FrameworkPropertyMetadata((double)126.0,
FrameworkPropertyMetadataOptions.BindsTwoWayByDefault
| FrameworkPropertyMetadataOptions.AffectsRender
| FrameworkPropertyMetadataOptions.AffectsMeasure)
{
BindsTwoWayByDefault = true,
DefaultUpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged
});
(AffectsRender & AffectsMeasure may not be necessary though)
This worked in UWP but I can't get the image to show using WPF XAML.
I start by defining a UserControl which binds the path of the image file:
<Grid Height="70" Width="70">
<Border Style="{StaticResource border}">
<Button Style="{StaticResource button}">
<Image Source="{Binding prop_image}"/>
</Button>
</Border>
</Grid>
I define the dependency property as:
public static readonly DependencyProperty prop_image =
DependencyProperty.Register("prop_image_path", typeof(string),
typeof(user_control), null);
public string prop_image_path
{
get { return (string)GetValue(prop_image); }
set { SetValue(prop_image, value); }
}
I then try to consume it as:
<local:user_control Grid.Column="1" Grid.Row="2"
prop_image_path="/Assets/my.png"/>
which is the exact same as UWP but with Binding instead of x:bind. when I create a button and set the image it works . . . but it doesn't display the alpha channel(which I guess means I have to use an alpha mask and have two files.) aside from this, moving a bunch of stuff from UWP to WPF XAML was a snap.
At first, you are using the wrong property path in {Binding prop_image}, which should be {Binding prop_image_path}. Since this Binding is in a UserControl's XAML to one of its own properties, you should also specify the source object of the Binding to be the UserControl instance, like:
<Image Source="{Binding prop_image_path,
RelativeSource={RelativeSource AncestorType=UserControl}}"/>
Besides that, the WPF dependency property system requires that you adhere to naming conventions for the dependency property identifier field.
It must be named like the property with a Property suffix:
public static readonly DependencyProperty prop_image_pathProperty =
DependencyProperty.Register(
"prop_image_path",
typeof(string),
typeof(user_control),
null);
You may also notice that your naming scheme is a little uncommon. According to widely accepted conventions, C#/.NET type and property names should use Pascal Casing, i.e.
public class MyUserControl
{
public static readonly DependencyProperty ImagePathProperty =
DependencyProperty.Register(
nameof(ImagePath),
typeof(string),
typeof(MyUserControl));
public string ImagePath
{
get { return (string)GetValue(ImagePathProperty); }
set { SetValue(ImagePathProperty, value); }
}
}
I have a simple usercontrol with a button in it which i modified.
When I add this usercontrol to my mainwindow, I can only access the usercontrol's properties. How can I access the button content ? Ideally I'd like to have a custom property let's say "TheText" and I changed it like that
<local:MyButtonControl TheText="My text here will be the button content">
This is what I have in the usercontrol "MyButtonControl"
public object TheText
{
get => (object)GetValue(_text);
set => SetValue(_text, value);
}
public static readonly DependencyProperty _text =
DependencyProperty.Register("Text", typeof(object), typeof(MyButton), new UIPropertyMetadata(null));
But what Am I supposed to put for binding ? Can't figure it out. Here's the concerned button.
<Button x:Name="button" Content="{Binding ??? }" Style="{StaticResource RoundedButton}"/>
The Binding should look like this:
<Button Content="{Binding Text,
RelativeSource={RelativeSource AncestorType=UserControl}}" .../>
Note that a correct dependency property declaration would have to use the same name for both the dependency property and the CLR wrapper. There is also a convention to name the identifier field as <PropertyName>Property.
public object Text
{
get => (object)GetValue(TextProperty);
set => SetValue(TextProperty, value);
}
public static readonly DependencyProperty TextProperty =
DependencyProperty.Register("Text", typeof(object), typeof(MyButton));
You should certainly also use string as type of a property that is called Text. Or you call the property ButtonContent or something like that.
In my user control (class LabeledBox), I've added dependency property as follows.
public static readonly DependencyProperty HorizontalProperty
= DependencyProperty.Register(
"Horizontal",
typeof (Orientation),
typeof (LabeledBox),
new PropertyMetadata(default(Orientation)));
public Orientation Horizontal
{
get { return (Orientation) GetValue(HorizontalProperty); }
set { SetValue(HorizontalProperty, value); }
}
However, when setting it according to the below, doesn't give me any difference in behavior. In fact, the setter in the property doesn't get called. What do I miss?
<local:LabeledBox x:Name="Info field"
Description="Info"
Horizontal="Horizontal" />
The component in question has a stack panel as outermost control and it's bound like this.
<StackPanel Name="TheContainer" Orientation="{Binding Horizontal}">
Perhaps I've done the binding incorrectly?
Give a name to your UserControl:
<UserControl .... x:Name="labeledBox">
And use the binding like this:
<StackPanel Name="TheContainer" Orientation="{Binding Horizontal, ElementName=labeledBox}">
Yes your Binding is not well try to update it to be seems like:
<StackPanel Name="TheContainer"
Orientation="{
Binding Horizontal,
RelativeSource={RelativeSource AncestorType=local:LabeledBox}}"/>
I am trying to bind the value of a ConverterParameter. Currently finding it too tricky...
Codebehind
public static readonly DependencyProperty RecognitionProperty = DependencyProperty.Register("RecognitionToEdit", typeof(Recognition), typeof(RecognitionInstancesWindow), null);
public Recognition Recognition
{
get { return (Recognition)GetValue(RecognitionProperty); }
set { SetValue(RecognitionProperty, value); }
}
XAML of a TextBox, which forms part of a datatemplate for a coverflow type control.
<TextBlock HorizontalAlignment="Left" Margin="2,0,0,0" Text="{Binding Converter={StaticResource DateConverter}, Path=Date, ConverterParameter={Binding Recognition, Path=Frequency}}" />
Can anyone see where I'm going wrong please?
Unfortunately it is not possible, that's because for property to be bindable it should be dependency, and the object should be derived from DependencyObject. Binding is not derived from DependencyObject, so it is impossible, you should look another ways to do that
One way to do that is to create a class in static resource, and pass that class to your converter like this
<namespace:MyClass x:Key="MyClass">
<Binding ... ConvertParameter={StaticResource MyClass}/>
from MyClass you can return anything you want ;)
this post can be helpful