locked
dynamic property not working well with DependencyProperties RRS feed

  • 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




    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;
        }
    

    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;
        }
    

    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 worked
    Thursday, 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