WPF set from DependencyProperty not set a value if DP is binded in xaml

Code Wanderer 396 Reputation points
2020-10-10T19:37:07.58+00:00

I have this code inside class inherited from DependencyObject

   public float VolumeStartLeft
    {
        get { return (float)GetValue(VolumeStartLeftProperty); }
        set
        {
            if (mifp_VolumeStartLeft != null) mifp_VolumeStartLeft(value, e_side.left); // this is never called
            SetValue(VolumeStartLeftProperty, value);
        }
    }

    public static readonly DependencyProperty VolumeStartLeftProperty = DependencyProperty.Register(
        "VolumeStartLeft", typeof(float), typeof(c_delay_dp)
        , new PropertyMetadata(0.0f)); // , VolumeStartLeftCallback

inside xaml I bind this property into slider value.

    <Slider x:Name="SliderLeft" Value="{Binding VolumeStartLeft, Mode=TwoWay}" />

Problem is, set code is never called. When I add code (from property set) if (mifp_VolumeStartLeft != null) mifp_VolumeStartLeft(value, e_side.left); into DependencyPropertyCallback function and slider is changed, Callback is called, but never from set inside property. I wanted avoid to write callback functions for every DependencyProperty, how can I ensure that set will be called when value is changed from slider?

Developer technologies | Windows Presentation Foundation
{count} votes

2 answers

Sort by: Most helpful
  1. Peter Fleischer (former MVP) 19,341 Reputation points
    2020-10-11T08:09:15.913+00:00

    Hi,
    If you use static and instance properties you must set instance property in callback method:

    XAML MainWindow:

    <Window x:Class="WpfApp1.Window88"  
            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:WpfApp88"  
            mc:Ignorable="d"  
            Title="Slider Binding" Height="450" Width="800">  
      <Window.DataContext>  
        <local:ViewModel/>  
      </Window.DataContext>  
      <StackPanel DataContext="{Binding Obj}">  
        <TextBox Text="{Binding VolumeStartLeft}"/>  
        <Slider Value="{Binding VolumeStartLeft, Mode=TwoWay}"/>  
      </StackPanel>  
    </Window>  
    

    ViewModel:

    using System;  
    using System.ComponentModel;  
    using System.Diagnostics;  
    using System.Runtime.CompilerServices;  
    using System.Windows;  
      
    namespace WpfApp88  
    {  
      public class ViewModel  
      {  
        public c_delay_dp Obj { get; set; } = new c_delay_dp();  
      }  
      
      public class c_delay_dp : FrameworkElement, INotifyPropertyChanged  
      {  
        public float VolumeStartLeft  
        {  
          get { return (float)GetValue(VolumeStartLeftProperty); }  
          set  
          {  
            string stamp = DateTime.Now.ToString("HH:mm.fff");  
            Debug.WriteLine($"{stamp} - Setter VolumeStartLeft");  
            SetValue(VolumeStartLeftProperty, value);  
          }  
        }  
      
        public static readonly DependencyProperty VolumeStartLeftProperty = DependencyProperty.Register(  
            "VolumeStartLeft", typeof(float), typeof(c_delay_dp)  
            , new PropertyMetadata(1.0f,propCallBack)); // , VolumeStartLeftCallback  
      
        private static void propCallBack(DependencyObject d, DependencyPropertyChangedEventArgs e)  
        {  
          var dep = d as c_delay_dp;  
          if (dep == null) return;  
          dep.VolumeStartLeft = (float)e.NewValue;  
          dep.OnPropertyChanged(nameof(VolumeStartLeft));  
        }  
      
        public event PropertyChangedEventHandler PropertyChanged;  
        private void OnPropertyChanged([CallerMemberName] string propName = "") =>  
          PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));  
      }  
    }  
    

    Result:

    31462-x.gif


  2. Peter Fleischer (former MVP) 19,341 Reputation points
    2020-10-11T11:45:57.643+00:00

    Hi,
    I didn't unterstand how you want synchronize static and instance properties without code. You can use this approach:

    XAML MainWindow:

    <Window x:Class="WpfApp1.Window89"
            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:WpfApp89"
            mc:Ignorable="d"
            Title="Slider Binding" Height="450" Width="800">
      <Window.DataContext>
        <local:ViewModel/>
      </Window.DataContext>
      <StackPanel>
        <Slider Value="{Binding VolumeStartLeft, Mode=TwoWay}"/>
      </StackPanel>
    </Window>
    

    ViewModel and class:

    using System;
    using System.Diagnostics;
    using System.Windows;
    
    namespace WpfApp89
    {
      public class ViewModel:FrameworkElement
      {
        public float VolumeStartLeft
        {
          get { return (float)GetValue(VolumeStartLeftProperty); }
          set
          {
            string stamp = DateTime.Now.ToString("HH:mm.fff");
            Debug.WriteLine($"{stamp} - Setter VolumeStartLeft");
            SetValue(VolumeStartLeftProperty, value);
          }
        }
    
        public static readonly DependencyProperty VolumeStartLeftProperty = DependencyProperty.Register(
            "VolumeStartLeft", typeof(float), typeof(c_delay_dp)
            , new PropertyMetadata(1.0f)); // , VolumeStartLeftCallback
      }
    
      public class c_delay_dp : FrameworkElement
      {
        public static readonly DependencyProperty VolumeStartLeftProperty = DependencyProperty.Register(
            "VolumeStartLeft", typeof(float), typeof(c_delay_dp)
            , new PropertyMetadata(1.0f)); // , VolumeStartLeftCallback
      }
    }
    

Your answer

Answers can be marked as 'Accepted' by the question author and 'Recommended' by moderators, which helps users know the answer solved the author's problem.