Answered by:
dynamic property not working well with DependencyProperties

Question
-
My requirement is Binding dynamic property to my Value (double) property of Custom control.But it not working as expected.
Below is the code :
Simple customcontrol part :<Style TargetType="{x:Type local:CustomControl1}"> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type local:CustomControl1}"> <Border Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}"> <TextBox x:Name="PART_TextBox" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}"/> </Border> </ControlTemplate> </Setter.Value> </Setter> </Style>
public class CustomControl1 : Control { public double? Value { get { return (double?)GetValue(ValueProperty); } set { SetValue(ValueProperty, value); } } // Using a DependencyProperty as the backing store for Value. This enables animation, styling, binding, etc... public static readonly DependencyProperty ValueProperty = DependencyProperty.Register("Value", typeof(double?), typeof(CustomControl1), new PropertyMetadata(null, new PropertyChangedCallback(OnValueChanged), new CoerceValueCallback(CoerceValueChange))); private static object CoerceValueChange(DependencyObject d, object baseValue) { return baseValue; } private static void OnValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { ((CustomControl1)d).OnValueChanged(e); } private void OnValueChanged(DependencyPropertyChangedEventArgs e) { if (tb != null && e.NewValue != null) tb.Text = e.NewValue.ToString(); else tb.Text = string.Empty; } static CustomControl1() { DefaultStyleKeyProperty.OverrideMetadata(typeof(CustomControl1), new FrameworkPropertyMetadata(typeof(CustomControl1))); } TextBox tb = null; public override void OnApplyTemplate() { base.OnApplyTemplate(); tb = base.GetTemplateChild("PART_TextBox") as TextBox; } }
here goes the usage :
<Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="*" /> <ColumnDefinition Width="*" /> </Grid.ColumnDefinitions> <StackPanel Grid.Column="0"> <Label Content="Double TextBox without Converter" /> <Label Content="Double TextBox with Converter" /> <Label Content="MS TextBox" /> <Button Content="Button" Click="Button_Click_1"/> </StackPanel> <StackPanel Grid.Column="1"> <cc:CustomControl1 Value="{Binding MyValue}" Height="40" Width="200" Background="Red"/> <TextBox Height="30" Text="{Binding MyValue}" /> </StackPanel> </Grid>
public partial class MainWindow : Window ,INotifyPropertyChanged { private dynamic myValue; public dynamic MyValue { get { return myValue; } set { myValue = value; RaisePropertyChanged("MyValue"); } } public MainWindow() { InitializeComponent(); this.myValue = 3; this.DataContext = this; } private void Button_Click_1(object sender, RoutedEventArgs e) { this.myValue = 5; } public event PropertyChangedEventHandler PropertyChanged; private void RaisePropertyChanged(string name) { if (PropertyChanged != null) { this.PropertyChanged(this, new PropertyChangedEventArgs(name)); } } }
the coerce's base value is always null,but if i use converter in binding it works as expected.
but i want to use like normal property , Please help me on this.
binding works perfectly if i use TextBox,it is not the issue ,, i'm facing issue while i use DP's in CustomControl
Regards,
Kumar
- Edited by Muthukumar Arumugam Thursday, September 4, 2014 11:31 AM
Thursday, September 4, 2014 11:19 AM
Answers
-
The conversion doesn't work because the type of your dependency property is double? but you are setting your source property, which is of type dynamic, to an int.
Option 1: Change the type of the source property to double or double?:
private double myValue; public double MyValue { get { return myValue; } set { myValue = value; RaisePropertyChanged("MyValue"); } }
Option 2:
Set the value of the dynamic property to a double instead of an int by using the d suffix:
public MainWindow() { InitializeComponent(); this.myValue = 3d; this.DataContext = this; } private void Button_Click_1(object sender, RoutedEventArgs e) { this.MyValue = 5d; }
Also note that you should set the value of the property MyValue rather than the field myValue in the click event handler:
private void Button_Click_1(object sender, RoutedEventArgs e) { this.MyValue = 5d; }
- Marked as answer by Muthukumar Arumugam Thursday, September 4, 2014 4:35 PM
Thursday, September 4, 2014 3:09 PM
All replies
-
The conversion doesn't work because the type of your dependency property is double? but you are setting your source property, which is of type dynamic, to an int.
Option 1: Change the type of the source property to double or double?:
private double myValue; public double MyValue { get { return myValue; } set { myValue = value; RaisePropertyChanged("MyValue"); } }
Option 2:
Set the value of the dynamic property to a double instead of an int by using the d suffix:
public MainWindow() { InitializeComponent(); this.myValue = 3d; this.DataContext = this; } private void Button_Click_1(object sender, RoutedEventArgs e) { this.MyValue = 5d; }
Also note that you should set the value of the property MyValue rather than the field myValue in the click event handler:
private void Button_Click_1(object sender, RoutedEventArgs e) { this.MyValue = 5d; }
- Marked as answer by Muthukumar Arumugam Thursday, September 4, 2014 4:35 PM
Thursday, September 4, 2014 3:09 PM -
Hi,
TextBox Text property is string. You change your Dependency property to string it will bind.
public class CustomControl1 : Control { public string Value { get { return (string)GetValue(ValueProperty); } set { SetValue(ValueProperty, value); } } // Using a DependencyProperty as the backing store for Value. This enables animation, styling, binding, etc... public static readonly DependencyProperty ValueProperty = DependencyProperty.Register("Value", typeof(string), typeof(CustomControl1), new PropertyMetadata(null, new PropertyChangedCallback(OnValueChanged), new CoerceValueCallback(CoerceValueChange))); private static object CoerceValueChange(DependencyObject d, object baseValue) { return baseValue; } private static void OnValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { ((CustomControl1)d).OnValueChanged(e); } private void OnValueChanged(DependencyPropertyChangedEventArgs e) { if (tb != null && e.NewValue != null) tb.Text = e.NewValue.ToString(); else tb.Text = string.Empty; } static CustomControl1() { DefaultStyleKeyProperty.OverrideMetadata(typeof(CustomControl1), new FrameworkPropertyMetadata(typeof(CustomControl1))); } TextBox tb = null; public override void OnApplyTemplate() { base.OnApplyTemplate(); tb = base.GetTemplateChild("PART_TextBox") as TextBox; } }
Thursday, September 4, 2014 3:46 PM -
Thank you,it workedThursday, September 4, 2014 4:36 PM
-
Good catch Magnus.
I missed that.
Hope that helps
Please don't forget to up vote answers you like or which help you and mark one(s) which answer your question.Thursday, September 4, 2014 7:12 PM