Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/django/22.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Wpf 延迟多重绑定_Wpf_Multibinding - Fatal编程技术网

Wpf 延迟多重绑定

Wpf 延迟多重绑定,wpf,multibinding,Wpf,Multibinding,我有一个多绑定,看起来像这样: <UserControl.Visibility> <MultiBinding Converter="{StaticResource isMouseOverToVisibiltyConverter}"> <Binding ElementName="otherElement" Path="IsMouseOver" /> <Binding RelativeSource="{Relative

我有一个多绑定,看起来像这样:

<UserControl.Visibility>
    <MultiBinding Converter="{StaticResource isMouseOverToVisibiltyConverter}">
        <Binding ElementName="otherElement" Path="IsMouseOver" />
        <Binding RelativeSource="{RelativeSource Self}" Path="IsMouseOver" />
    </MultiBinding>
</UserControl.Visibility>

并且,我希望能够在两个绑定的IsMouseOver变为false和可见性设置为折叠之间添加延迟

我发现这个延迟绑定实现:

但是,这对多重绑定不起作用,而且我一直无法弄清楚如何制作一个适用于多重绑定的

我确实可以选择在代码隐藏中对事件可见性进行更改,这是可行的,但如果有某种方法可以通过绑定系统实现这一点,那就太好了

有没有办法给多重绑定添加延迟

编辑:雷,为了让你的类编译和运行,我不得不做一些修正。但是,仍然有一些问题,因为更新没有被传播。它似乎只更新目标属性一次

[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;
}
[ContentProperty(“绑定”)]
公共类DelayedMultiBindingExtension:MarkupExtension、IMultiValueConverter、INotifyPropertyChanged
{
公共集合绑定{get;private set;}
public IMultiValueConverter转换器{get;set;}
公共对象转换器参数{get;set;}
公共文化信息转换器文化{get;set;}
公共绑定模式模式{get;set;}
public UpdateSourceTrigger UpdateSourceTrigger{get;set;}
公共对象CurrentValue{get{return{uDelayedValue;}set{uDelayedValue=\uUndelayedValue=value;\uTimer.Stop();}
私有对象undelayedValue;
私有对象_delayedValue;
私人调度员定时器;
public int changecont{get;private set;}//public,因此绑定可以绑定到它
公共DelayedMultiBindingExtension()
{
this.Bindings=新集合();
_计时器=新调度程序();
_timer.Tick+=\u timer\u Tick;
_timer.Interval=TimeSpan.From毫秒(500);
}
公共覆盖对象ProviderValue(IServiceProvider服务提供程序)
{
var valueProvider=serviceProvider.GetService(typeof(IProvideValueTarget))作为IProvideValueTarget;
if(valueProvider!=null)
{
var bindingTarget=valueProvider.TargetObject作为DependencyObject;
var bindingProperty=valueProvider.TargetProperty作为DependencyProperty;
var multi=new MultiBinding{Converter=this,Mode=Mode,UpdateSourceTrigger=UpdateSourceTrigger};
foreach(绑定中的var绑定)
multi.Bindings.Add(绑定);
添加(新绑定(“变更计数”){Source=this,Mode=BindingMode.OneWay});
var bindingExpression=BindingOperations.SetBinding(bindingTarget、bindingProperty、multi);
返回bindingTarget.GetValue(bindingProperty);
}
返回null;
}
公共对象转换(对象[]值,类型targetType,对象参数,CultureInfo区域性)
{
对象新值=
转换,转换(
values.Take(values.Length-1).ToArray(),
目标类型,
转换器参数,
转化文化??文化);
如果(!object.Equals(newValue,_undelayedValue))
{
_undelayedValue=新值;
_timer.Stop();
_timer.Start();
}
返回_delayedValue;
}
公共对象[]转换回(对象值,类型[]目标类型,对象参数,CultureInfo区域性)
{
返回
Converter.ConvertBack(值、目标类型、ConverterParameter、ConverterCulture??区域性)
.Concat(新对象[]{ChangeCount}).ToArray();
}
私有void\u timer\u Tick(对象发送方,事件参数e)
{
_timer.Stop();
_延迟值=_未延迟值;
ChangeCount++;
if(PropertyChanged!=null)
PropertyChanged(这是新的PropertyChangedEventArgs(“ChangeCount”);
}
公共事件属性更改事件处理程序属性更改;
}

EDIT2:尽管我无法让Ray的代码工作,但我已经将其标记为答案,因为它会让我找到一些工作正常的代码。有关我使用的代码,请参见下面的答案。

注意这只回答了问题中的“我一直无法找到如何制作一个可以与多绑定一起工作的”部分,并解释了如何做。其他人可能会发现这些信息很有用,因此我将把它留在这里,并添加另一个回答主要问题的答案


将链接到的DelayBinding标记扩展更改为DelayMultiBinding类非常简单,该类的工作方式与MultiBinding相同

在标记扩展中:

  • 重命名为DelayMultiBindingExtension
  • 添加
    集合类型的
    绑定
    属性
  • 更改
    转换器的类型
    属性
  • ProvideValue
    中,构造一个
    DelayMultiBinding
    而不是
    DelayBinding
    ,传入所有绑定
  • 在延迟绑定类中:

  • 重命名为DelayMultiBinding
  • 采用绑定数组而不是单个绑定
  • 将值更改处理程序添加到每个属性
  • 构建多重绑定,就像构建绑定一样
  • 现在,不要编写
    MultiBinding
    ,而是编写
    DelayMultiBindingExtension

    <UserControl.Visibility> 
      <my:DelayMultiBindingExtension Delay="0:0:1" Converter="{StaticResource isMouseOverToVisibiltyConverter}">
        <Binding ElementName="otherElement" Path="IsMouseOver" /> 
        <Binding RelativeSource="{RelativeSource Self}" Path="IsMouseOver" /> 
      </my:DelayMultiBindingExtension> 
    </UserControl.Visibility> 
    
    
    
    就个人而言,我还将通过将这两个类转换为一个单独的类来清理它,该类是一个MarkupExtension,并且还处理计时器


    请注意,DelayBinding类和此类都延迟对源的更新,而不是对目标的更新。如果要延迟对目标的更新(确实如此),请参阅我的另一个答案。

    链接到的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;
    }
    
    公共类DelayedMu
    
    <local:IsMouseOverToVisibilityConverter x:Key="isMouseOverToVisibiltyConverter" />
    <local:DelayingMultiConverter x:Key="delayedIsMouseOverToVisibiltyConverter" Delay="00:00:00.500" Converter="{StaticResource isMouseOverToVisibiltyConverter}" />
    
    ...
    
    <UserControl.Visibility>
        <MultiBinding Converter="{StaticResource delayedIsMouseOverToVisibiltyConverter}">
            <Binding ElementName="otherElement" Path="IsMouseOver" />
            <Binding RelativeSource="{RelativeSource Self}" Path="IsMouseOver" />
            <Binding Source="{StaticResource delayedIsMouseOverToVisibiltyConverter}" Path="ChangeCount" />
        </MultiBinding>
    </UserControl.Visibility>
    
    internal class DelayingMultiConverter : IMultiValueConverter, INotifyPropertyChanged
    {
        private object undelayedValue;
        private object delayedValue;
        private DispatcherTimer timer;
    
        private int changeCount;
        public int ChangeCount
        {
            get { return this.changeCount; }
            private set
            {
                this.changeCount = value;
                this.NotifyPropertyChanged("ChangeCount");
            }
        }
    
        public IMultiValueConverter Converter { get; set; }
        public CultureInfo ConverterCulture { get; set; }
        public object ConverterParameter { get; set; }
    
        public TimeSpan Delay
        {
            get { return this.timer.Interval; }
            set { this.timer.Interval = value; }
        }
    
        public DelayingMultiConverter()
        {
            this.timer = new DispatcherTimer();
            this.timer.Tick += Timer_Tick;
        }
    
        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();
        }
    
        public event PropertyChangedEventHandler PropertyChanged;
    
        private void NotifyPropertyChanged(string info)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(info));
            }
        }
    
        private void Timer_Tick(object sender, EventArgs e)
        {
            timer.Stop();
            delayedValue = undelayedValue;
            ChangeCount++;
        }
    }
    
    <UserControl.Visibility>
        <db:DelayMultiBinding Converter="{StaticResource yourConverter}"
                              UpdateTargetDelay="00:00:01">
            <Binding ElementName="otherElement" Path="IsMouseOver" />
            <Binding RelativeSource="{RelativeSource Self}" Path="IsMouseOver" />
        </db:DelayMultiBinding>
    </UserControl.Visibility>