title: Binding to a Controls DependencyProperty in DataTemplate of Listbox with dynamic items does not work
body: <p>Ok, since I spend one day reading articles in stackoverflow without success I must ask for help. Complete example follows below.</p>
  
  <p>Short version: 
  I have a DoubleTextBox, which provides a DependencyProperty "Number". When I use the DoubleTextBox directly, the Binding and Validation works fine. However, when I use it in a DataTemplate of a Listbox, the Binding to Objects in an ObservableCollection does fail. ValidatesOnDataErrors works neither.</p>
  
  <p>Thank you very, very much!</p>
  
  <p><strong>The XAML:</strong></p>
  
  <pre><code>&lt;Window x:Class="WpfApp1.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:WpfApp1"
          mc:Ignorable="d"
          Title="MainWindow" Height="350" Width="525"&gt;
  
    &lt;Window.DataContext&gt;
      &lt;local:ViewModel x:Name="ViewModel"/&gt;
    &lt;/Window.DataContext&gt;
  
    &lt;Grid&gt;
      &lt;Grid.ColumnDefinitions&gt;
        &lt;ColumnDefinition/&gt;
        &lt;ColumnDefinition Width="5"/&gt;
        &lt;ColumnDefinition/&gt;
      &lt;/Grid.ColumnDefinitions&gt;
  
      &lt;Grid Grid.Column="0"&gt;
        &lt;StackPanel Margin="10"&gt;
          &lt;StackPanel Orientation="Horizontal"&gt;
            &lt;TextBlock Text="Time (s):" Width="60"/&gt;
            &lt;local:DoubleTextBox Width="60" 
                                 Number="{Binding Time, UpdateSourceTrigger=PropertyChanged, 
              ValidatesOnDataErrors=True}" Decimals="2"/&gt;
          &lt;/StackPanel&gt;
        &lt;/StackPanel&gt;
      &lt;/Grid&gt;
  
      &lt;Grid Grid.Column="1" Background="SteelBlue"/&gt;
  
      &lt;Grid Grid.Column="2"&gt;
  
        &lt;Grid.Resources&gt;
          &lt;DataTemplate x:Key="MethodProgramViewTemplate"&gt;
            &lt;Grid KeyboardNavigation.TabNavigation="Local"&gt;
              &lt;Grid.ColumnDefinitions&gt;
                &lt;ColumnDefinition Width="60"/&gt;
                &lt;ColumnDefinition Width="60"/&gt;
              &lt;/Grid.ColumnDefinitions&gt;
              &lt;TextBlock Grid.Column="0" Text="Flow"/&gt;
              &lt;local:DoubleTextBox Grid.Column="1" TabIndex="0" Number="{Binding Flow, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}" Decimals="2" /&gt;
            &lt;/Grid&gt;
          &lt;/DataTemplate&gt;
  
        &lt;/Grid.Resources&gt;
  
        &lt;ListBox x:Name="PumpProgramListBox"
                   KeyboardNavigation.TabNavigation="Local"
                   ItemsSource="{Binding Path=MethodProgramView}" 
                   ItemTemplate="{StaticResource MethodProgramViewTemplate}"&gt;
          &lt;ListBox.ItemContainerStyle&gt;
            &lt;Style TargetType="{x:Type ListBoxItem}"&gt;
              &lt;Setter Property="HorizontalContentAlignment" Value="Stretch"/&gt;
              &lt;Setter Property="VerticalContentAlignment" Value="Stretch"/&gt;
            &lt;/Style&gt;
          &lt;/ListBox.ItemContainerStyle&gt;
        &lt;/ListBox&gt;
  
      &lt;/Grid&gt;
  
    &lt;/Grid&gt;
  &lt;/Window&gt;
  </code></pre>
  
  <p><strong>The ViewModel:</strong></p>
  
  <pre><code>using System;
  using System.Collections.Generic;
  using System.Collections.ObjectModel;
  using System.ComponentModel;
  using System.Linq;
  using System.Text;
  using System.Windows.Data;
  
  namespace WpfApp1
  {
    public class ViewModel : INotifyPropertyChanged, IDataErrorInfo
    {
      private double time = 0.0;
      public double Time
      {
        get =&gt; this.time;
        set
        {
          if (this.time != value)
          {
            System.Diagnostics.Debug.WriteLine(String.Format("ViewModel Time - from {0} to {1}", this.time, value));
            this.time = value;
            RaisePropertyChanged(nameof(Time));
          }
        }
      }
  
      public ObservableCollection&lt;Method&gt; methodProgram { get; private set; } = new ObservableCollection&lt;Method&gt;();
  
      private CollectionViewSource methodProgramView;
      public ICollectionView MethodProgramView
      {
        get
        {
          if (methodProgramView == null)
          {
            methodProgramView = new CollectionViewSource();
            methodProgramView.Source = methodProgram;
          }
          return methodProgramView.View;
        }
      }
  
      public ViewModel()
      {
        this.Time = 1.5;
        for (int i = 1; i &lt;= 3; i++)
        {
          this.methodProgram.Add(new Method() { Flow = i });
        }
      }
  
      public event PropertyChangedEventHandler PropertyChanged;
      internal void RaisePropertyChanged(string propName) =&gt;
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));
  
      public string Error =&gt; "";
  
      public string this[string columnName]
      {
        get
        {
          string result = null;
          switch (columnName)
          {
            case nameof(Time):
              result = this.Time &lt; 0 ? "Time must be positive" : null;
              break;
  
            default:
              break;
          }
  
          return result;
        }
      }
    }
  }
  </code></pre>
  
  <p><strong>The "Method" Object:</strong></p>
  
  <pre><code>using System;
  using System.Collections.Generic;
  using System.ComponentModel;
  using System.Linq;
  using System.Text;
  
  namespace WpfApp1
  {
    public class Method : INotifyPropertyChanged, IDataErrorInfo
    {
      private double flow = 0.0;
      public double Flow
      {
        get =&gt; this.flow;
        set
        {
          if (this.flow != value)
          {
            System.Diagnostics.Debug.WriteLine(String.Format("Method Flow - from {0} to {1}", this.flow, value));
            this.flow = value;
            RaisePropertyChanged(nameof(Flow));
          }
        }
      }
  
      public event PropertyChangedEventHandler PropertyChanged;
      internal void RaisePropertyChanged(string propName) =&gt;
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));
  
      public string Error =&gt; "";
  
      public string this[string columnName]
      {
        get
        {
          string result = null;
          switch (columnName)
          {
            case nameof(Flow):
              result = this.Flow &lt; 0 ? "Flow must be positive" : null;
              break;
  
            default:
              break;
          }
  
          return result;
        }
      }
    }
  }
  </code></pre>
  
  <p><strong>The DoubleTextBox:</strong></p>
  
  <pre><code>using System;
  using System.Collections.Generic;
  using System.Linq;
  using System.Text;
  using System.Text.RegularExpressions;
  using System.Windows;
  using System.Windows.Controls;
  using System.Windows.Data;
  using System.Windows.Input;
  
  namespace WpfApp1
  {
    public class DoubleTextBox : TextBox
    {
      #region Properties
      public double Number
      {
        get { return (double)this.GetValue(NumberProperty); }
        set { this.SetValue(NumberProperty, value); }
      }
  
      public static readonly DependencyProperty NumberProperty = DependencyProperty.Register(
          nameof(Number), typeof(double), typeof(DoubleTextBox),
          new FrameworkPropertyMetadata(3.3d, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
          new PropertyChangedCallback(NumberProperty_PropertyChanged))
      );
  
      public int Decimals
      {
        get { return (int)this.GetValue(DecimalsProperty); }
        set { this.SetValue(DecimalsProperty, value); }
      }
  
      public static readonly DependencyProperty DecimalsProperty = DependencyProperty.Register(
          nameof(Decimals), typeof(int), typeof(DoubleTextBox),
          new FrameworkPropertyMetadata((int)2, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
          new PropertyChangedCallback(DecimalsProperty_PropertyChanged))
      );
      #endregion Properties
  
      #region Constructor
      public DoubleTextBox()
      {
        this.TextChanged += DoubleTextBox_TextChanged;
        this.LostFocus += DoubleTextBox_LostFocus;
        this.PreviewTextInput += DoubleTextBox_PreviewTextInput;
        this.RefreshText();
      }
      #endregion Constructor
  
      #region Methods
      private static void NumberProperty_PropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
      {
        System.Diagnostics.Debug.WriteLine(String.Format("NumberProperty_PropertyChanged - from {0} to {1}", e.OldValue, e.NewValue));
        (d as DoubleTextBox).RefreshText();
      }
  
      private static void DecimalsProperty_PropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
      {
        (d as DoubleTextBox).RefreshText();
      }
  
      private void RefreshText()
      {
        System.Diagnostics.Debug.WriteLine(String.Format("DoubleTextBox - DataContext: {0}", this.DataContext));
        Text = Number.ToString("N" + this.Decimals.ToString());
      }
  
      private void DoubleTextBox_PreviewTextInput(object sender, TextCompositionEventArgs e)
      {
        e.Handled = !IsTextAllowed(e.Text);
      }
  
      private static bool IsTextAllowed(string text)
      {
        string CultureName = System.Threading.Thread.CurrentThread.CurrentCulture.Name;
        System.Globalization.CultureInfo ci = new System.Globalization.CultureInfo(CultureName);
        char DecimalSeparator = ci.NumberFormat.NumberDecimalSeparator[0];
        Regex regex = new Regex(String.Format("([-+0-9]+[{0}][0-9]+)|([-+0-9{0}])", DecimalSeparator));  //regex that matches only numbers
        bool match = regex.IsMatch(text);
  
        return regex.IsMatch(text);
      }
  
      void DoubleTextBox_LostFocus(object sender, System.Windows.RoutedEventArgs e)
      {
        RefreshText();
      }
  
      void DoubleTextBox_TextChanged(object sender, TextChangedEventArgs e)
      {
        double number;
        if (string.IsNullOrEmpty(Text))
        {
          Number = 0;
        }
        else if (double.TryParse(Text, out number))
        {
          Number = Double.Parse(number.ToString("N" + this.Decimals.ToString()));
        }
        else
        {
          BindingExpression bex = GetBindingExpression(NumberProperty);
          if (bex != null)
          {
            ValidationError validationError = new ValidationError(new ExceptionValidationRule(), bex);
            validationError.ErrorContent = "Number is not valid";
            Validation.MarkInvalid(bex, validationError);
          }
        }
      }
      #endregion Methods
    }
  }
  </code></pre>