I don't understand the interest of a dependency property without callback defined.
A callback is just an added convenience -- dependency properties are integrated into the framework runtime, and have a built-in callback mechanism that updates any bindings. That is, if you set a binding with a dependency property as the source, then the target will update automatically when the dependency property changes.
For example, let's say you have a custom control with a DP defined:
public string SomeDP
{
get { return (string)GetValue(SomeDPProperty); }
set { SetValue(SomeDPProperty, value); }
}
public static readonly DependencyProperty SomeDPProperty =
DependencyProperty.Register("SomeDP", typeof(string), typeof(SomeFrameworkElement), new PropertyMetadata(null));
And if you set up a binding with the DP as the source for a TextBlock's "Text" property:
<local:SomeFrameworkElement x:Name="someFrameworkElement" SomeDP="initial" />
<TextBlock Text="{Binding ElementName=someFrameworkElement,Path=SomeDP}" />
Then whenever "someFrameworkElement"'s "SomeDP" property changes, the text will also change.
I am working in silverlight.
Made a new UserControl called TextBoxWithButton.
Now i want add a new property to my new control called TextBoxBackground.
I did this :
public partial class TextBoxWithButton : UserControl
{
public Brush TextBoxBackground
{
get{return textBox.Background;}
set{textBox.Background = value;}
}
}
This works fine, but when I try to animate this property I get an exception.
I think it's because TextBoxWithButton should be defined as a dependency property but I don't know exactly how to to this.
You need to turn this into a Dependency Property. For details on implementing a DP, see Custom Dependency Properties.
Once you have this setup as a Dependency Property, just bind your (inner) TextBox.Background to the "local" TextBoxBackground property (in xaml). You can then animate the UserControl's TextBoxBackground property as needed, and the "inner" property will change as well.
We can achieve the binding by simply CLR property, so why do we need to use DP?
When do you need DPs over CLRPs?
When you need binding
when you need property value change callback (Default Implementation)
When you need property value validation
When you need animation
When you need property value inheritance
When you need to attach a property value to another element (Attached Property, but still)
When you need styling
Some of these can be implemented in CLR properties. But, with DPs, its piece of cake.
Typically these are declared in UserControls and derived controls.
You can bind to a CLR property, but you can't bind with a CLR property; you'll need a dependency property to do any binding.
Edit (in response to comment)
Let's say you need a TextBox, but you want to customize it to have different behaviour in "EditMode" and "ReadMode". You'll need to either create a derived class or a UserControl; in either case you'll add a DependencyPropery.
public class TextBoxWithModes : TextBox
{
public bool EditMode
{
get { return (bool) GetValue(EditModeProperty); }
set { SetValue(EditModeProperty, value); }
}
public static readonly DependencyProperty EditModeProperty = DependencyProperty.Register(
"EditMode", typeof (bool), typeof (TextBoxWithModes));
}
With this in place, you can declare it in XAML:
<Namespace:TextBoxWithModes Text="enter text here"
Width="200"
HorizontalAlignment="Center"
EditMode="{Binding IsChecked, ElementName=editModeCheckBox}" />
I have a custom user control that exposes a DepenencyProperty (ImageData).
I've placed this user control on a page and I bind it's ImageData property to a property of my page's ViewModel (photo).
<localControls:PhotoPicker ImageData="{Binding Path=Photo, Mode=TwoWay}"/>
When the user interact with the control setting the controls ImageData property the Photo property of my viewmodel is updated == Perfect. However if the ViewModel changes the value of Photo, the ImageData property of PhotoPicker is not changed. What could I be missing in getting data from the ViewModel back down to the user control?
UPDATE:
Upon further investigation it seems that the setting from the ViewModel back to the control via the binding, through the dependencyproperty does not fire the setter of the dependency property wrapper property. What a mess. I need to know when that happens, if i can't do that in the setter of the wrapper property where should I do it?
UPDATE 2:
Seems that the only way to find about changes to the DependencyProperty is to add a PropertyChangedCallback in the PropertyMetadata when Registering the property.
Sounds like your view model doesn't send property changed notifications? Extremely simplified, your view model must look something like this:
public class MyViewModel : INotifyPropertyChanged
{
private object photo;
public object Photo
{
get { return this.photo; }
set { this.photo = value; this.OnPropertyChanged("Photo"); }
}
// ...
}
I have two UserControls ("UserControlParentView" and "UserControlChildView") with MVVM pattern implemented in both controls. Parent control is a container for Child control and child control's property should be updated by data binding from Parent control in order to show/hide some check box inside Child control.
Parent Control Description
UserControlParentViewModel has property:
private bool isShowCheckbox = false;
public bool IsShowCheckbox
{
get { return isShowCheckbox; }
set { isShowCheckbox = value; NotifyPropertyChanged("IsShowCheckbox"); }
}
UserControlParentViewModel - how I set DataContext of Parent control:
public UserControlParentView()
{
InitializeComponent();
this.DataContext = new UserControlParentViewModel();
}
UserControlParentView contains toggle button (in XAML), bound to UserControlParentViewModel's property IsShowCheckbox
<ToggleButton Grid.Column="1" IsChecked="{Binding IsShowCheckbox, Mode=TwoWay}"></ToggleButton>
Also Parent control contains instance of child element (somewhere in XAML)
<local:UserControlChildView IsCheckBoxVisible="{Binding IsShowCheckbox}" ></local:UserControlChildView>
so property in child control should be updated when user togggle/untoggle button.
Child control contains Boolean property to be updated from parent control, but nothing happened! Breakpoint never fired!
Property in UserControlChildView that should be updated from Parent control (here I plan to make chechBox visible/hidden in code behind):
public bool IsCheckBoxVisible
{
get { return (bool)GetValue(IsCheckBoxVisibleProperty); }
set { SetValue(IsCheckBoxVisibleProperty, value); }
}
// Using a DependencyProperty as the backing store for IsCheckBoxVisible. This enables animation, styling, binding, etc...
public static readonly DependencyProperty IsCheckBoxVisibleProperty =
DependencyProperty.Register("IsCheckBoxVisible", typeof(bool), typeof(TopMenuButton), new PropertyMetadata(false));
So the question is - what I'm doing wrong? Why child's property is never updated? BTW - there is no any binding error warnings in Output window...
You don't state where you put the breakpoint "never fired!". My guess is you placing a break point in the set mutator method of the IsCheckBoxVisible property.
You are operating under the assumption that the binding on that property will at some point cause the set method to be called when assigning the value. However the Silverlight binding framework actuall calls SetValue directly. It passes to the SetValue method the value of IsCheckBoxVisibleProperty and the value to be assigned.
I can't see all your code, so I can't work out everything, but a couple of questions:
In your DependencyProperty.Register call, you specify typeof(TopMenuButton), which should be the UserControlChildView - I don't know if that is your view or not?
You don't set up a callback method for property changed. To do this you would have to define the properties for the FrameworkPropertyMetadata, before registering the depencencyProperty like so:
FrameworkPropertyMetadata metadata = new FrameworkPropertyMetadata();
metadata.PropertyChangedCallback += OnSpacePropertyChanged;
You'd then have to declare OnSpacePropertyChanged, but you can at least respond to setting the property from there.
I am pretty sure you can't bind to a dependency property on a user control in Silverlight 3. I've tried it myself 9 months ago, and attempted all sorts of things to get it to work. Eventually I read somewhere that it simply wasn't possible. I have done it in WPF, so was beating my head on it for a while, thinking it was my implementation.
So, on the surface your code looks correct but this won't help.
I thought it was slated as something to be fixed in SL4.
Are you using SL4?
Hoho!! I've got it to work!
In child control I've changed property a bit
public bool IsCheckBoxVisible
{
get { return (bool)GetValue(IsCheckBoxVisibleProperty); }
set { SetValue(IsCheckBoxVisibleProperty, value); }
}
// Using a DependencyProperty as the backing store for IsCheckBoxVisible. This enables animation, styling, binding, etc...
public static readonly DependencyProperty IsCheckBoxVisibleProperty =
DependencyProperty.Register("IsCheckBoxVisible", typeof(bool), typeof(UserControlChildView), new PropertyMetadata(false, new PropertyChangedCallback((d, dc) =>
{
var button = d as UserControlChildView;
button.CheckBoxVisibility = ((bool)dc.NewValue) ? Visibility.Visible : Visibility.Collapsed;
})));
so now I have new event subscription (see anonymous method) and it fires when in parent control IsShowCheckbox property is changed!
CheckBoxVisibility depend.property looks like this:
public Visibility CheckBoxVisibility
{
get { return (Visibility)GetValue(CheckBoxVisibilityProperty); }
set { SetValue(CheckBoxVisibilityProperty, value); }
}
// Using a DependencyProperty as the backing store for IsCheckBoxVisible. This enables animation, styling, binding, etc...
public static readonly DependencyProperty CheckBoxVisibilityProperty =
DependencyProperty.Register("CheckBoxVisibility", typeof(Visibility), typeof(UserControlChildView), new PropertyMetadata(Visibility.Collapsed));
Constructor of serControlChildView looks like:
public UserControlChildView()
{
InitializeComponent();
this.LayoutRoot.DataContext = this;
}
So seems like it works! Thank you for your help, folks!
Ok, it seems like everything worked fine and I was confused just by non-fired breakpoint.
For simplicity I've decided to remove IsCheckBoxVisible boolean depend.property from the Child control and to bind checkBox visibility in Child control directly to CheckBoxVisibility depend.property (type is Visibility).
Also in the Parent control now I have this:
<local:UserControlChildView CheckBoxVisibility="{Binding Path=CheckboxControlVisibility}"></local:UserControlChildView>
So in the Parent control now I have CheckboxControlVisibility property (type is Visibility)