setting dependency property in user control style - wpf

I implemented a user control with a dependency property that looks like this:
public partial class MyUC : UserControl, INotifyPropertyChanged
{
public static readonly DependencyProperty MyBackgroundProperty =
DependencyProperty.Register("MyBackground", typeof(Brush), typeof(MyUC),
new FrameworkPropertyMetadata(Brushes.White,
FrameworkPropertyMetadataOptions.AffectsRender));
public Brush MyBackground
{
get { return (Brush)GetValue(MyBackgroundProperty); }
set { SetValue(MyBackgroundProperty, value); }
}
//...
}
and try to set this property in XAML as follows:
<UserControl x:Class="Custom.MyUC"
x:Name="myUCName"
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:local="clr-namespace:Custom"
mc:Ignorable="d"
TabIndex="0" KeyboardNavigation.TabNavigation="Local"
HorizontalContentAlignment="Left" VerticalContentAlignment="Top"
MouseLeftButtonDown="OnMouseLeftButtonDown">
<UserControl.Style>
<Style TargetType="local:MyUC">
<Setter Property="MyBackground" Value="Black"/>
</Style>
</UserControl.Style>
<Border BorderThickness="0">
//...
</Border>
</UserControl>
It compiles but when I run the app I get the following exception:
Set property 'System.Windows.Setter.Property' threw an exception.'
Line number '..' and line position '..'."
How can I solve this?

The problem arises because you're trying to apply a style with TargetType="MyUC" to an element of type UserControl.
The solution is to apply the style from outside of the control. So for example when you use the control in another window:
<Window.Resources>
<Style TargetType="local:MyUC">
<Setter Property="MyBackground" Value="Red" />
</Style>
</Window.Resources>
<Grid>
<local:MyUC />
</Grid>
As a test I added this code to the user control:
public partial class MyUC
{
public MyUC()
{
InitializeComponent();
}
public static readonly DependencyProperty MyBackgroundProperty =
DependencyProperty.Register("MyBackground", typeof(Brush), typeof(MyUC),
new PropertyMetadata(Brushes.White, PropertyChangedCallback));
private static void PropertyChangedCallback(DependencyObject dependencyObject,
DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
{
((MyUC)dependencyObject).MyBackgroundPropertyChanged(
(Brush)dependencyPropertyChangedEventArgs.NewValue);
}
private void MyBackgroundPropertyChanged(Brush newValue)
{
Background = newValue;
}
public Brush MyBackground
{
get { return (Brush)GetValue(MyBackgroundProperty); }
set { SetValue(MyBackgroundProperty, value); }
}
}
Which then results in the control having a red background.

Related

WPF Set a Dependencyproperty value using a DataTrigger [duplicate]

I implemented a user control with a dependency property that looks like this:
public partial class MyUC : UserControl, INotifyPropertyChanged
{
public static readonly DependencyProperty MyBackgroundProperty =
DependencyProperty.Register("MyBackground", typeof(Brush), typeof(MyUC),
new FrameworkPropertyMetadata(Brushes.White,
FrameworkPropertyMetadataOptions.AffectsRender));
public Brush MyBackground
{
get { return (Brush)GetValue(MyBackgroundProperty); }
set { SetValue(MyBackgroundProperty, value); }
}
//...
}
and try to set this property in XAML as follows:
<UserControl x:Class="Custom.MyUC"
x:Name="myUCName"
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:local="clr-namespace:Custom"
mc:Ignorable="d"
TabIndex="0" KeyboardNavigation.TabNavigation="Local"
HorizontalContentAlignment="Left" VerticalContentAlignment="Top"
MouseLeftButtonDown="OnMouseLeftButtonDown">
<UserControl.Style>
<Style TargetType="local:MyUC">
<Setter Property="MyBackground" Value="Black"/>
</Style>
</UserControl.Style>
<Border BorderThickness="0">
//...
</Border>
</UserControl>
It compiles but when I run the app I get the following exception:
Set property 'System.Windows.Setter.Property' threw an exception.'
Line number '..' and line position '..'."
How can I solve this?
The problem arises because you're trying to apply a style with TargetType="MyUC" to an element of type UserControl.
The solution is to apply the style from outside of the control. So for example when you use the control in another window:
<Window.Resources>
<Style TargetType="local:MyUC">
<Setter Property="MyBackground" Value="Red" />
</Style>
</Window.Resources>
<Grid>
<local:MyUC />
</Grid>
As a test I added this code to the user control:
public partial class MyUC
{
public MyUC()
{
InitializeComponent();
}
public static readonly DependencyProperty MyBackgroundProperty =
DependencyProperty.Register("MyBackground", typeof(Brush), typeof(MyUC),
new PropertyMetadata(Brushes.White, PropertyChangedCallback));
private static void PropertyChangedCallback(DependencyObject dependencyObject,
DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
{
((MyUC)dependencyObject).MyBackgroundPropertyChanged(
(Brush)dependencyPropertyChangedEventArgs.NewValue);
}
private void MyBackgroundPropertyChanged(Brush newValue)
{
Background = newValue;
}
public Brush MyBackground
{
get { return (Brush)GetValue(MyBackgroundProperty); }
set { SetValue(MyBackgroundProperty, value); }
}
}
Which then results in the control having a red background.

WPF validation error style in reuseable UserControl?

I have made a reusable UserControl in my WPF application that has a Textbox (and in the real project other components) inside of it. I'm using Fluent Validation with INotifyDataErrorInfo to validate user input in TextBoxes. My problem is that when the model whose property is bound to the UserControl's TextBox has errors, the TextBox's style doesn't trigger according to the style that is set. It seems that my style's trigger for the UserControl's Textbox can't read the Validation.HasError value from the model correctly. So is there a way to get the style to trigger and get the error tooltip for the UserControl's Textbox?
This question has been asked by several other people over the years, and I have looked at every single one of them, but none of them really work for me. One thing I tried that does work is a general ValidationRule in the UserControl.xaml for the textbox binding, but that doesn't allow for model specific rules. I'm hoping that some WPF guru will finally take the challenge and solve this problem! :)
If you make a sample project from the code I provided, and set the Height property to less than 10, you see that the normal TextBox gets the triggered errorstyle with the tooltip, but the UserControl's TextBox gets the basic red border:
Sample app with the cursor over the first textbox.
Here is my simplified code:
The UserControl:
<UserControl x:Class="UserControlValidationTest.DataInputUserControl"
x:Name="parentControl"
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"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<UserControl.Resources>
<Style TargetType="TextBox" x:Key="TextBoxStyle">
<Style.Triggers>
<Trigger Property= "Validation.HasError" Value="true">
<Setter Property="Background" Value="Pink"/>
<Setter Property="ToolTip" Value="{Binding RelativeSource={RelativeSource Self}, Path=(Validation.Errors)[0].ErrorContent}" />
</Trigger>
</Style.Triggers>
</Style>
</UserControl.Resources>
<StackPanel Orientation="Horizontal" DataContext="{Binding ElementName=parentControl}">
<TextBox Name="ValueBox" Text="{Binding Value, UpdateSourceTrigger=PropertyChanged}" Width="60" Style="{StaticResource TextBoxStyle}"/>
</StackPanel>
public partial class DataInputUserControl : UserControl
{
public DataInputUserControl()
{
InitializeComponent();
Validation.SetValidationAdornerSite(this, ValueBox);
}
public double Value
{
get => (double)GetValue(ValueProperty);
set => SetValue(ValueProperty, value);
}
public static readonly DependencyProperty ValueProperty =
DependencyProperty.Register("Value", typeof(double), typeof(DataInputUserControl), new FrameworkPropertyMetadata(0d, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
}
MainWindow.xaml:
<Window x:Class="UserControlValidationTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:UserControlValidationTest"
mc:Ignorable="d"
Title="MainWindow" Height="100" Width="200">
<Window.DataContext>
<local:MainWindowViewModel/>
</Window.DataContext>
<Window.Resources>
<Style TargetType="TextBox">
<Style.Triggers>
<Trigger Property= "Validation.HasError" Value="true">
<Setter Property="Background" Value="Pink"/>
<Setter Property="ToolTip" Value="{Binding RelativeSource={RelativeSource Self}, Path=(Validation.Errors)[0].ErrorContent}" />
</Trigger>
</Style.Triggers>
</Style>
</Window.Resources>
<StackPanel>
<TextBox Text="{Binding User.Height, UpdateSourceTrigger=PropertyChanged}" Width="60" Margin="10"/>
<local:DataInputUserControl Value="{Binding User.Height}" HorizontalAlignment="Center"/>
</StackPanel>
View model:
public class MainWindowViewModel
{
public UserModel User { get; set; }
public MainWindowViewModel()
{
User = new UserModel();
}
}
User Model:
public class UserModel : ValidatableModel
{
public double Height { get => GetPropertyValue<double>(); set => SetPropertyValue(value); }
public UserModel()
{
ModelValidator = new UserValidator();
Height = 180;
}
}
User Validator:
public class UserValidator : AbstractValidator<UserModel>
{
public UserValidator()
{
RuleFor(x => x.Height)
.GreaterThan(10);
}
}
Validatable Model:
using FluentValidation;
using FluentValidation.Results;
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.ComponentModel;
using System.Runtime.CompilerServices;
public abstract class ValidatableModel : INotifyDataErrorInfo, INotifyPropertyChanged
{
private readonly Dictionary<string, object> propertyBackingDictionary = new Dictionary<string, object>();
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string parameter = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(parameter));
}
protected T GetPropertyValue<T>([CallerMemberName] string propertyName = null)
{
if (propertyBackingDictionary.TryGetValue(propertyName, out object value))
{
return (T)value;
}
return default(T);
}
protected bool SetPropertyValue<T>(T newValue, [CallerMemberName] string propertyName = null)
{
if (EqualityComparer<T>.Default.Equals(newValue, GetPropertyValue<T>(propertyName)))
{
return false;
}
propertyBackingDictionary[propertyName] = newValue;
OnPropertyChanged(propertyName);
Validate();
return true;
}
private ConcurrentDictionary<string, List<string>> errors = new ConcurrentDictionary<string, List<string>>();
public IValidator ModelValidator { get; set; }
public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;
public void OnErrorsChanged(string propertyName)
{
ErrorsChanged?.Invoke(this, new DataErrorsChangedEventArgs(propertyName));
}
public IEnumerable GetErrors([CallerMemberName] string propertyName = null)
{
errors.TryGetValue(propertyName, out List<string> errorsForName);
return errorsForName;
}
public bool HasErrors => errors.Count > 0;
public void Validate()
{
errors.Clear();
var validationResults = ModelValidator.Validate(this);
foreach (var item in validationResults.Errors)
{
errors.TryAdd(item.PropertyName, new List<string> { item.ErrorMessage });
OnErrorsChanged(item.PropertyName);
}
}
}
}

Send Value from View Model to UserControl Dependency Property WPF

I have a dependency property in a UserControl with a property called SelectedColor. From my main app, the view of the window that uses this my code is:
<controls:ColorPicker SelectedColor="{Binding MyCanvas.CanvasBackgroundColor}" />
And the code from the view model is:
public MyCanvas { get; set; }
public MyWindowViewModel(MyCanvas myCanvas)
{
MyCanvas = myCanvas;
}
And then the XAML for my UserControl is:
<UserControl . . .>
<Button Click="Button_Click">
<Button.Style>
<Setter Property="Background" Value="Transparent" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border Background="{Binding SelectedColor}" BorderBrush="Black" BorderThickness="1" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Button.Style>
</Button>
</UserControl>
And the code-behind:
public ColorPicker()
{
InitializeComponent();
DataContext = this;
}
public SolidColorBrush SelectedColor
{
get { return (SolidColorBrush)GetValue(SelectedColorProperty); }
set { SetValue(SelectedColorProperty, value); }
}
public static readonly DependencyProperty SelectedColorProperty =
DependencyProperty.Register(nameof(SelectedColor), typeof(SolidColorBrush), new UIPropertyMetadata(null));
I think the problem might be with the line in the code-behind DataContext = this;. Is it correct that declaring this creates an entirely new context for the instance of this user control in the main app and therefore any values sent to it from the view model would be re-initialized? If so, how can I send the value over without it being re-declared? I also need the DataContext = this line because without it some functionality within my UserControl will no longer work.
Has anyone encountered this before?
Thanks in advance!
DataContext = this sets the DataContext of the UserControl to itself. You don't want to do this. Instead you could bind to a property of the UserControl using a {RelativeSource} without setting the DataContext property:
<Border Background="{Binding SelectedColor, RelativeSource={RelativeSource AncestorType=UserControl}}"
BorderBrush="Black" BorderThickness="1" />
Code-behind:
public ColorPicker()
{
InitializeComponent();
}
public SolidColorBrush SelectedColor
{
get { return (SolidColorBrush)GetValue(SelectedColorProperty); }
set { SetValue(SelectedColorProperty, value); }
}
public static readonly DependencyProperty SelectedColorProperty =
DependencyProperty.Register(nameof(SelectedColor), typeof(SolidColorBrush), new UIPropertyMetadata(null));

databinding on a user control only working partially (silverlight)

I am not sure what I am doing wrong here. I spent a good hour last night to figure it out, maybe I am just dumb.
I created this user control to display a bordered text, which uses data binding to fill the style and the text.
This is how I call it from the main page:
<mynamespace:BorderedText x:Name="DateTime"
Grid.Column="1"
Grid.Row="0"
BorderStyle="{StaticResource borderStyle}"
LabelStyle="{StaticResource labelStyle}"
TextStyle="{StaticResource valueStyle}"
Label="Current Date/Time"
Text="N/A" />
The control is pretty simple:
<UserControl x:Class="MyNamespace.BorderedText"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="480"
d:DesignWidth="480">
<Grid>
<Border Name="border" Style="{Binding BorderStyle}">
<StackPanel>
<TextBlock Style="{Binding LabelStyle}"
Text="{Binding Label}" />
<TextBlock Style="{Binding TextStyle}"
Text="{Binding Text}" />
</StackPanel>
</Border>
</Grid>
The problem is that all data binding works, except for the Border data binding. I also tried to data bind the background or any other property, without success.
Code behind has the DependencyProperty properties set up and that’s it. Note that the DataContext for data binding is set up in the constructor. Tried to assign it to the Grid or to the Border itself, without success.
Does anybody have any clue or see something big I am missing here?
namespace MyNamespace
{
public partial class BorderedText : UserControl
{
public static readonly DependencyProperty LabelProperty = DependencyProperty.Register("Label", typeof(string), typeof(BorderedText), new PropertyMetadata(null));
public static readonly DependencyProperty LabelStyleProperty = DependencyProperty.Register("LabelStyle", typeof(Style), typeof(BorderedText), new PropertyMetadata(null));
public static readonly DependencyProperty TextProperty = DependencyProperty.Register("Text", typeof(string), typeof(BorderedText), new PropertyMetadata(null));
public static readonly DependencyProperty TextStyleProperty = DependencyProperty.Register("TextStyle", typeof(Style), typeof(BorderedText), new PropertyMetadata(null));
public static readonly DependencyProperty BorderStyleProperty = DependencyProperty.Register("BorderStyle", typeof(Style), typeof(BorderedText), new PropertyMetadata(null));
public BorderedText()
{
InitializeComponent();
((Grid)this.Content).DataContext = this;
//((Border)this.Content).DataContext = this;
}
public string Label
{
set { SetValue(LabelProperty, value); }
get { return (string)GetValue(LabelProperty); }
}
public Style LabelStyle
{
set { SetValue(LabelStyleProperty, value); }
get { return (Style)GetValue(LabelStyleProperty); }
}
public string Text
{
set { SetValue(TextProperty, value); }
get { return (string)GetValue(TextProperty); }
}
public Style TextStyle
{
set { SetValue(TextStyleProperty, value); }
get { return (Style)GetValue(TextStyleProperty); }
}
public Style BorderStyle
{
set { SetValue(BorderStyleProperty, value); }
get { return (Style)GetValue(BorderStyleProperty); }
}
}
}
---- UPDATE:
It turned out to be something completely different and unrelated to databinding which is properly wired...
In the borderStyle I was using this syntax for a background property:
<Setter Property="Background">
<Setter.Value>
<SolidColorBrush>
<SolidColorBrush.Color>
<Color>
<Color.A>
100
</Color.A>
<Color.R>#95</Color.R>
<Color.B>#ED</Color.B>
</Color>
</SolidColorBrush.Color>
</SolidColorBrush>
</Setter.Value>
</Setter>
which apparently works in the designer but not in the phone.
Changing it to:
<Setter Property="Background">
<Setter.Value>
<SolidColorBrush Color="#649500ED" />
</Setter.Value>
</Setter>
Solved the problem
Well, you forgot one thing... the DataContext of the Border!
Give your UserControl a name, and then you can add to your binding something like:
<TextBox Text="{Binding Path=MyText, ElementName=UserControlRoot}" />
this will work (at least it worked for me in WPF, heh)

Dependency property not working, trying to set through style setter

I am trying to set up a custom style for my newly made usercontrol, however i am getting the error : "Cannot convert the value in attribute 'Property' to object of type 'System.Windows.DependencyProperty'."
I thought i had set up Dependency properties but it seemed this was not the case, so i did some research and added:
public static readonly DependencyProperty ImageSourceProperty =
DependencyProperty.Register("ImageSource", typeof(BitmapSource), typeof(Image));
to make this:
-- MyButton.Xaml.Cs --
namespace Client.Usercontrols
{
public partial class MyButton : UserControl
{
public static readonly DependencyProperty ImageSourceProperty =
DependencyProperty.Register("ImageSource", typeof(BitmapSource), typeof(Image));
public MyButton()
{
InitializeComponent();
}
public event RoutedEventHandler Click;
void onButtonClick(object sender, RoutedEventArgs e)
{
if (this.Click != null)
this.Click(this, e);
}
BitmapSource _imageSource;
public BitmapSource ImageSource
{
get { return _imageSource; }
set
{
_imageSource = value;
tehImage.Source = _imageSource;
}
}
}
}
This unfortunately does not work. I also tried this:
public BitmapSource ImageSource
{
get { return (BitmapSource)GetValue(MyButton.ImageSourceProperty); }
set
{
SetValue(ImageSourceProperty, value);
}
}
But that did not work and the image was not shown and generated the same error as mentioned previously anyway.
Any ideas?
Regards Kohan.
-- MyButton.Xaml --
<UserControl x:Class="Client.Usercontrols.MyButton"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" MinHeight="30" MinWidth="40"
DataContext="{Binding RelativeSource={RelativeSource Self}}">
<Button Width="Auto" HorizontalAlignment="Center" Click="onButtonClick">
<Border CornerRadius="5" BorderThickness="1" BorderBrush="Transparent" >
<Grid>
<Image Name="tehImage" Source="{Binding ImageSource}" />
<TextBlock Name="tehText" Text="{Binding Text}" Style="{DynamicResource ButtonText}" />
</Grid>
</Border>
</Button>
</UserControl>
-- MYButton Style --
<Style TargetType="{x:Type my:MyButton}" >
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type my:MyButton}">
<ContentPresenter />
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="ImageSource" Value="../Images/Disabled.png" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Biggest problem I see is that you're registering the property as owned by Image rather than by your UserControl. Change to:
public static readonly DependencyProperty ImageSourceProperty =
DependencyProperty.Register("ImageSource", typeof(BitmapSource), typeof(MyButton));
If that doesn't work, will need to see your XAML.
The standard form for a dependency property is (i've added in your information):
public BitmapSource ImageSource
{
get { return (BitmapSource)GetValue(ImageSourceProperty); }
set { SetValue(ImageSourceProperty, value); }
}
/* Using a DependencyProperty as the backing store for ImageSource.
This enables animation, styling, binding, etc... */
public static readonly DependencyProperty ImageSourceProperty =
DependencyProperty.Register("ImageSource",
typeof(BitmapSource),
typeof(MyButton),
new UIPropertyMetadata(null)
);
it seems like your also trying to pass through the dependency property to the ImageSource of the object called "tehImage". You can set this up to automatically update using the PropertyChangedCallback... this means that whenever the property is updated, this will call the update automatically.
thus the property code becomes:
public BitmapSource ImageSource
{
get { return (BitmapSource)GetValue(ImageSourceProperty); }
set { SetValue(ImageSourceProperty, value); }
}
/* Using a DependencyProperty as the backing store for ImageSource.
This enables animation, styling, binding, etc... */
public static readonly DependencyProperty ImageSourceProperty =
DependencyProperty.Register("ImageSource",
typeof(BitmapSource), typeof(MyButton),
new UIPropertyMetadata(null,
ImageSource_PropertyChanged
)
);
private static void ImageSource_PropertyChanged(DependencyObject source, DependencyPropertyChangedEventArgs e)
{
((MyButton)source).tehImage.ImageSource = (ImageSource)e.NewValue
}
Hopefully with the correctly registered dependency property, this will help you narrow down the issue (or even fix it)
Set the DataContext for your UserControl:
public MyButton()
{
InitializeComponent();
DataContext = this;
}
Alternatively, if you can't do that (since the DataContext is set to another object, for example), you can do this in your XAML:
<UserControl x:Class="Client.Usercontrols.MyButton"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" MinHeight="30" MinWidth="40"
DataContext="{Binding RelativeSource={RelativeSource Self}}"
x:Name="MyControl">
<Button Width="Auto" HorizontalAlignment="Center" Click="onButtonClick">
<Border CornerRadius="5" BorderThickness="1" BorderBrush="Transparent" >
<Grid>
<Image Name="tehImage" Source="{Binding ElementName=MyControl, Path=ImageSource}" />
<TextBlock Name="tehText" Text="{Binding ElementName=MyControl, Path=Text}" Style="{DynamicResource ButtonText}" />
</Grid>
</Border>
</Button>
</UserControl>
The correct way of implementing a source for an Image in a user control in my opinion is not BitmapSouce. The easiest and best way (according to me again) is using Uri.
Change your dependency property to this (while also defining a change callback event):
ImageSourceProperty = DependencyProperty.Register(
"ImageSource", typeof (Uri), typeof (MyButton),
new FrameworkPropertyMetadata(new PropertyChangedCallback(OnImageSourceChanged)));
and the property to this:
public Uri ImageSource
{
get
{
return (Uri)GetValue(ImageSourceProperty);
}
set
{
SetValue(ImageSourceProperty, value);
}
}
Where your call back is like this:
private static void OnImageSourceChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
MyButton hsb = (MyButton)sender;
Image image = hsb.tehImage;
image.Source = new BitmapImage((Uri) e.NewValue);
}

Resources