我有一个看起来像这样的多绑定:
<UserControl.Visibility>
<MultiBinding Converter="{StaticResource isMouseOverToVisibiltyConverter}">
<Binding ElementName="otherElement" Path="IsMouseOver" />
<Binding RelativeSource="{RelativeSource Self}" Path="IsMouseOver" />
</MultiBinding>
</UserControl.Visibility>
Run Code Online (Sandbox Code Playgroud)
而且,我希望能够在两个绑定的IsMouseOver之间添加一个延迟,并将Visibility设置为Collapsed.
我找到了这个DelayBinding实现:http: //www.paulstovell.com/wpf-delaybinding
但是,这对MultiBinding不起作用,而且我一直无法弄清楚如何使用MultiBinding.
我可以选择在代码隐藏中的事件中对Visibility进行更改,这样可以工作,但是如果通过绑定系统有某种方法可以做到这一点会很好.
有没有办法为MultiBinding添加延迟?
编辑:雷,为了让你的类编译和运行,我不得不做一些修复.但是,由于更新没有传播,因此仍然存在问题.它似乎只更新一次目标属性.
[ContentProperty("Bindings")]
public class DelayedMultiBindingExtension : MarkupExtension, IMultiValueConverter, INotifyPropertyChanged
{
public Collection<BindingBase> 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<BindingBase>();
_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;
}
Run Code Online (Sandbox Code Playgroud)
编辑2:即使我无法让Ray的代码工作,我已经将它标记为答案,因为它导致我的一些代码可以正常工作.请参阅下面的答案,了解我使用的代码.
您链接的DelayBinding类仅延迟源更新,而不是目标更新.延迟目标更新(这是您要求的)要简单得多.像这样的东西应该做的伎俩:
public class DelayedMultiBindingExtension : MarkupExtension, IMultiValueConverter, INotifyPropertyChanged
{
public Collection<Binding> Bindings { get; 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(); } }
object _undelayedValue;
object _delayedValue;
DispatcherTimer _timer;
public int ChangeCount { get; set; } // Public so Binding can bind to it
public DelayedMultiBindingExtension()
{
_timer = new DispatcherTimer();
_timer.Tick += _timer_Tick;
}
public override object ProvideValue(IServiceProvider serviceProvider)
{
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 });
return multi;
}
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();
}
void _timer_Tick(object sender, EventArgs e)
{
_timer.Stop();
_delayedValue = _undelayedValue;
ChangeCount++;
if(PropertyChanged!=null)
PropertyChanged(this, new PropertyChangedEventArgs("ChangeCount"));
}
public event PropertyChangedEventHandler PropertyChanged;
}
Run Code Online (Sandbox Code Playgroud)
工作原理:构造一个MultiBinding,它对标记扩展本身的ChangeCount属性有一个额外的绑定.标记扩展本身也会注册为转换器.每当源值更改时,绑定计算并调用转换器.这反过来调用"真实"转换器来计算值.不是立即更新值,而是将其存储在_undelayedValue中,并返回先前的值(_delayedValue).此外,如果值已更改,则启动(或重新启动)计时器.当计时器触发时,该值被复制到_delayedValue中并且ChangeCount递增,从而强制重新评估绑定.这次返回新的_delayedValue.