gpt4 book ai didi

c# - WPF .NET 弹出窗口 - 悬停时打开,如果鼠标悬停则保持打开

转载 作者:行者123 更新时间:2023-12-05 03:07:44 28 4
gpt4 key购买 nike

我有一个 Textblock,当鼠标悬停在它上面时,我想在上面打开一个 Popup。我已使用 MultiBindingIsOpen 属性绑定(bind)到 PopupIsMouseOverTextBlockIsMouseOver,它工作正常,除了当鼠标从文本移动到弹出窗口时,弹出窗口闪烁。

闪烁的原因是幕后事件的执行顺序:

鼠标从textblock移动到popup--IsMouseOver of textblock 设置为false --> 转换器被调用,两个参数都为 false --> 只有 popupIsMouseOver 被设置为 true --> 转换器执行,两个参数都为 false,弹出窗口消失 --> 转换器调用并再次执行,因为另一个之前为弹出窗口的 IsMouseOver 引发了事件,这次 PopupIsMouseOver True --> 弹出窗口再次出现。我已经尝试添加 StaysOpen=False,但它永远不会关闭/行为与预期不同。

问题:如何避免闪烁?

代码:

<Grid>
<ListBox ItemsSource="{Binding RandomNames}">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBlock Text="Name: "
Grid.Column="0"/>
<TextBlock Grid.Column="1"
x:Name="NameBlock"
Text="{Binding}">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Foreground" Value="Red" />
</Trigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
<Popup x:Name="PopupX"
Grid.Column="1"
PlacementTarget="{Binding ElementName=NameBlock}"
Placement="Bottom">
<!--<Popup.IsOpen>
<MultiBinding Converter="{StaticResource PopupIsOpenConverter}">
<Binding ElementName="PopupX" Path="IsMouseOver" Mode="OneWay" />
<Binding ElementName="NameBlock" Path="IsMouseOver" Mode="OneWay" />
</MultiBinding>
</Popup.IsOpen>-->
<Popup.Style>
<Style TargetType="Popup">
<Setter Property="IsOpen" Value="True" />
<Style.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding IsMouseOver, ElementName=NameBlock}" Value="False" />
<Condition Binding="{Binding IsMouseOver, RelativeSource={RelativeSource Self}}" Value="False" />
</MultiDataTrigger.Conditions>
<Setter Property="IsOpen" Value="False" />
</MultiDataTrigger>
</Style.Triggers>
</Style>
</Popup.Style>
<TextBlock Text="{Binding}"
Foreground="Coral" />
</Popup>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>

转换器代码

[ValueConversion(typeof(bool), typeof(bool))]
public class PopupIsOpenConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
return values.Any(value => value is bool && (bool) value);
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new ActionNotSupportedException();
}
}

最佳答案

感谢this post ,我能够使用延迟多重绑定(bind)解决问题。请注意,多绑定(bind)转换器是通用的,可以接受任何常规多绑定(bind)转换器加上延迟。

我的 XAML:

<Popup.IsOpen>
<local:DelayedMultiBindingExtension Converter="{StaticResource PopupIsOpenConverter}" Delay="0:0:0.01">
<Binding ElementName="PopupX" Path="IsMouseOver" Mode="OneWay" />
<Binding ElementName="RecipientsTextBlock" Path="IsMouseOver" Mode="OneWay" />
</local:DelayedMultiBindingExtension>
</Popup.IsOpen>

我的多重绑定(bind)转换器:

[ContentProperty("Bindings")]
internal sealed class DelayedMultiBindingExtension : MarkupExtension, IMultiValueConverter, INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;

public Collection<BindingBase> Bindings { get; }

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; }

private object _undelayedValue;
private object _delayedValue;
private DispatcherTimer _timer;

public object CurrentValue
{
get { return _delayedValue; }
set
{
_delayedValue = _undelayedValue = value;
_timer.Stop();
}
}

public int ChangeCount { get; private set; } // Public so Binding can bind to it

public TimeSpan Delay
{
get { return _timer.Interval; }
set { _timer.Interval = value; }
}

public DelayedMultiBindingExtension()
{
this.Bindings = new Collection<BindingBase>();
_timer = new DispatcherTimer();
_timer.Tick += Timer_Tick;
_timer.Interval = TimeSpan.FromMilliseconds(10);
}

public override object ProvideValue(IServiceProvider serviceProvider)
{
var valueProvider = serviceProvider.GetService(typeof(IProvideValueTarget)) as IProvideValueTarget;
if (valueProvider == null) return 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);
}

public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
var newValue = Converter.Convert(values.Take(values.Length - 1).ToArray(),
targetType,
ConverterParameter,
ConverterCulture ?? culture);

if (Equals(newValue, _undelayedValue)) return _delayedValue;
_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++;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(ChangeCount)));
}
}

关于c# - WPF .NET 弹出窗口 - 悬停时打开,如果鼠标悬停则保持打开,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46671458/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com