I have a button in a custom control with an image defined like so in Xaml (I've just added the part of the xaml that specifically refers to the image for the sake of brevity;
<StackPanel>
<Image Style="{StaticResource vtlImageStyle}">
<Image.Source>
<Binding Path="FirstImage"
RelativeSource="{RelativeSource TemplatedParent}">
<Binding.TargetNullValue>
<ImageSource>/ViewToLearn.VtlWpfControls;component/Images/button_rounded_blue_previous24.png</ImageSource>
</Binding.TargetNullValue>
</Binding>
</Image.Source>
</Image>
</StackPanel>
Now I would like to change this slightly so that the TargetNullValue is actually bound to a dependencyProperty which would then give me the freedom to change the default image based on another criteria.
To this end I created a dependency property of type string to represent the Uri of the image (with its own default value).
Protected Friend Shared ReadOnly DefaultFirstButtonImageUriProperty As DependencyProperty = DependencyProperty.Register("DefaultFirstButtonImageUri", GetType(String), GetType(VtlDataNavigator), New PropertyMetadata("/ViewToLearn.VtlWpfControls;component/Images/button_rounded_blue_first24.png", New PropertyChangedCallback(AddressOf OnDefaultFirstButtonImageUriChanged)))
Private Shared Sub OnDefaultFirstButtonImageUriChanged(ByVal o As DependencyObject, ByVal e As DependencyPropertyChangedEventArgs)
Dim vtlDataNavigator As VtlDataNavigator = CType(o, VtlDataNavigator)
If vtlDataNavigator IsNot Nothing Then
vtlDataNavigator.OnDefaultFirstButtonImageUriChanged(CType(e.OldValue, String), CType(e.NewValue, String))
End If
End Sub
Protected Overridable Sub OnDefaultFirstButtonImageUriChanged(ByVal oldValue As String, ByVal newValue As String)
' TODO: Add your property changed side-effects. Descendants can override as well.
End Sub
Public Property DefaultFirstButtonImageUri As String
' IMPORTANT: To maintain parity between setting a property in XAML and procedural code, do not touch the getter and setter inside this dependency property!
Get
Return CType(GetValue(VtlDataNavigator.DefaultFirstButtonImageUriProperty), String)
End Get
Set(ByVal value As String)
SetValue(VtlDataNavigator.DefaultFirstButtonImageUriProperty, value)
End Set
End Property
However when I try to set this in the xaml like so
<Image.Source>
<Binding Path="FirstImage"
RelativeSource="{RelativeSource TemplatedParent}">
<Binding.TargetNullValue>
<ImageSource>{Binding Path=DefaultFirstButtomImageUri}</ImageSource>
</Binding.TargetNullValue>
</Binding>
</Image.Source>
It throws an error pointing out that it couldn't create an imagesource from the text '{Binding Path=DefaultFirstButtonImageUri}'. Fine I understand the logic behind this, so I tried another approach;
<Image Style="{StaticResource vtlImageStyle}"
Source="{Binding Path=FirstImage}"
TargetNullValue="{Binding Path=DefaultFirstButtonImageUri}">
<!--<Image.Source>
<Binding Path="FirstImage"
RelativeSource="{RelativeSource TemplatedParent}">
<Binding.TargetNullValue>
<ImageSource>{Binding Path=DefaultFirstButtomImageUri}</ImageSource>
</Binding.TargetNullValue>
</Binding>
</Image.Source>-->
</Image>
Which would have been a great and easy solution if Image actually had a TargetNullValue property.
Can anybody suggest a way to do this?
Edit
In response to the suggestion of using PriorityBinding (which I'd never encountered before so thanks for the info on that) I tried the following:
<Image Style="{StaticResource vtlImageStyle}">
<Image.Source>
<PriorityBinding>
<Binding Path="FirstImage"></Binding>
<Binding Path="DefaultFirstButtonImage"></Binding>
</PriorityBinding>
</Image.Source>
<!--<Image.Source>
<Binding Path="FirstImage"
RelativeSource="{RelativeSource TemplatedParent}">
<Binding.TargetNullValue>
<ImageSource>{Binding Path=DefaultFirstButtomImageUri}</ImageSource>
</Binding.TargetNullValue>
</Binding>
</Image.Source>-->
</Image>
and the DefaultFirstButtonImage dependecyProperty is defined like so;
Protected Friend Shared ReadOnly DefaultFirstButtonImageProperty As DependencyProperty = DependencyProperty.Register("DefaultFirstButtonImage", GetType(ImageSource), GetType(VtlDataNavigator), New PropertyMetadata(New BitmapImage(New Uri("/ViewToLearn.VtlWpfControls;component/Images/button_rounded_blue_first24.png")), New PropertyChangedCallback(AddressOf OnDefaultFirstButtonImageChanged)))
Private Shared Sub OnDefaultFirstButtonImageChanged(ByVal o As DependencyObject, ByVal e As DependencyPropertyChangedEventArgs)
Dim vtlDataNavigator As VtlDataNavigator = CType(o, VtlDataNavigator)
If vtlDataNavigator IsNot Nothing Then
vtlDataNavigator.OnDefaultFirstButtonImageChanged(CType(e.OldValue, ImageSource), CType(e.NewValue, ImageSource))
End If
End Sub
Protected Friend Overridable Sub OnDefaultFirstButtonImageChanged(ByVal oldValue As ImageSource, ByVal newValue As ImageSource)
' TODO: Add your property changed side-effects. Descendants can override as well.
End Sub
Public Property DefaultFirstButtonImage As ImageSource
' IMPORTANT: To maintain parity between setting a property in XAML and procedural code, do not touch the getter and setter inside this dependency property!
Get
Return CType(GetValue(VtlDataNavigator.DefaultFirstButtonImageProperty), ImageSource)
End Get
Set(ByVal value As ImageSource)
SetValue(VtlDataNavigator.DefaultFirstButtonImageProperty, value)
End Set
End Property
Unfortunately this appears not to work at all. When I place an instance of my control in which this code resides onto a window I get an error stating that the format of the Uri could not be determined. Unfortunately this is thrown from the test application I have to built to test the control, however I suspect that it must originate in the dependency property.