title: WPF - Delayed Multibinding
body: <p>I have a multibinding that looks something like this:</p>
  
  <pre><code>&lt;UserControl.Visibility&gt;
      &lt;MultiBinding Converter="{StaticResource isMouseOverToVisibiltyConverter}"&gt;
          &lt;Binding ElementName="otherElement" Path="IsMouseOver" /&gt;
          &lt;Binding RelativeSource="{RelativeSource Self}" Path="IsMouseOver" /&gt;
      &lt;/MultiBinding&gt;
  &lt;/UserControl.Visibility&gt;
  </code></pre>
  
  <p>And, I want to be able to add a delay between IsMouseOver going to false for both bindings, and the Visibility being set to Collapsed.</p>
  
  <p>I found this DelayBinding implementation:
  <a href="http://www.paulstovell.com/wpf-delaybinding" rel="noreferrer">http://www.paulstovell.com/wpf-delaybinding</a></p>
  
  <p>But, that doesn't work for MultiBinding, and I've been unable to figure out how to make one that works with MultiBinding.</p>
  
  <p>I do have the option of doing the changes to Visibility in events in the code-behind, and that would work, but it would be nice if there was some way to do this through the binding system.</p>
  
  <p>Is there some way to add a delay to a MultiBinding?</p>
  
  <p>EDIT: Ray, in order to get your class to compile &amp; run, I had to make some fixes.  However, something is still wrong, as the updates aren't being propagated.  It seems to only update the target property once.</p>
  
  <pre><code>[ContentProperty("Bindings")]
  public class DelayedMultiBindingExtension : MarkupExtension, IMultiValueConverter, INotifyPropertyChanged
  {
      public Collection&lt;BindingBase&gt; Bindings { get; private set; }
      public IMultiValueConverter Converter { get; set; }
      public object ConverterParameter { get; set; }
      public CultureInfo ConverterCulture { get; set; }
      public BindingMode Mode { get; set; }
      public UpdateSourceTrigger UpdateSourceTrigger { get; set; }
  
      public object CurrentValue { get { return _delayedValue; } set { _delayedValue = _undelayedValue = value; _timer.Stop(); } }
  
      private object _undelayedValue;
      private object _delayedValue;
  
      private DispatcherTimer _timer;
      public int ChangeCount { get; private set; }  // Public so Binding can bind to it
  
      public DelayedMultiBindingExtension()
      {
          this.Bindings = new Collection&lt;BindingBase&gt;();
          _timer = new DispatcherTimer();
          _timer.Tick += _timer_Tick;
          _timer.Interval = TimeSpan.FromMilliseconds(500);
      }
  
      public override object ProvideValue(IServiceProvider serviceProvider)
      {
          var valueProvider = serviceProvider.GetService(typeof(IProvideValueTarget)) as IProvideValueTarget;
          if (valueProvider != null)
          {
              var bindingTarget = valueProvider.TargetObject as DependencyObject;
              var bindingProperty = valueProvider.TargetProperty as DependencyProperty;
  
              var multi = new MultiBinding { Converter = this, Mode = Mode, UpdateSourceTrigger = UpdateSourceTrigger };
              foreach (var binding in Bindings)
                  multi.Bindings.Add(binding);
              multi.Bindings.Add(new Binding("ChangeCount") { Source = this, Mode = BindingMode.OneWay });
  
              var bindingExpression = BindingOperations.SetBinding(bindingTarget, bindingProperty, multi);
  
              return bindingTarget.GetValue(bindingProperty);
          }
  
          return null;
      }
  
      public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
      {
          object newValue =
            Converter.Convert(
              values.Take(values.Length - 1).ToArray(),
              targetType,
              ConverterParameter,
              ConverterCulture ?? culture);
  
          if (!object.Equals(newValue, _undelayedValue))
          {
              _undelayedValue = newValue;
              _timer.Stop();
              _timer.Start();
          }
          return _delayedValue;
      }
  
      public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
      {
          return
            Converter.ConvertBack(value, targetTypes, ConverterParameter, ConverterCulture ?? culture)
            .Concat(new object[] { ChangeCount }).ToArray();
      }
  
      private void _timer_Tick(object sender, EventArgs e)
      {
          _timer.Stop();
          _delayedValue = _undelayedValue;
          ChangeCount++;
          if (PropertyChanged != null)
              PropertyChanged(this, new PropertyChangedEventArgs("ChangeCount"));
      }
  
      public event PropertyChangedEventHandler PropertyChanged;
  }
  </code></pre>
  
  <p>EDIT2: Even though I couldn't get Ray's code to work, I've marked it as the answer because it lead to me some code that does work.  See my answer below for the code I used.</p>