【发布时间】:2021-11-11 23:54:01
【问题描述】:
谁能解释为什么当您将鼠标快速移到 WPF 窗口上时它会滞后?有没有办法解决?可能要更改窗口渲染设置?
以下代码运行矩形的平滑动画,直到您开始将鼠标移到帧速率将急剧下降的窗口上(使用 VS 中的 Application Profiler 确认)。也发生在没有调试器的发布版本中。
我读过Why does the Dispatcher Timer in WPF lag when i hover over my Application Window?,它建议使用不同的计时器来更新基础数据。我已经尝试过 System.Threading.Timer、System.Timers.Timer 和 System.Windows.Threading.DispatcherTimer,以及创建一个新线程以使用 Thread.Sleep 更新循环中的值。所有这些都提供相同的结果,所以我认为它实际上与计时器本身没有任何关系。
代码隐藏:
public partial class MainWindow : Window, INotifyPropertyChanged
{
private int _value;
public int Value { get => _value; set { _value = value; RaisePropertyChangedEvent(); } }
public event PropertyChangedEventHandler PropertyChanged;
public Timer Timer { get; set; }
public MainWindow()
{
InitializeComponent();
DataContext = this;
Timer = new Timer((o) =>
{
Value = Value > 100 ? -100 : Value + 1;
}, null, 0, 10);
}
protected void RaisePropertyChangedEvent([CallerMemberName] String propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
XAML:
<Window x:Class="MouseLagTest.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:MouseLagTest"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<Rectangle Width="50" Height="50" Fill="Red">
<Rectangle.RenderTransform>
<TranslateTransform X="{Binding Value}"/>
</Rectangle.RenderTransform>
</Rectangle>
</Grid>
编辑 在针对 .Net Framework 4.X 和 .Net Core 构建时,似乎会出现此问题。如果使用 Framework 3.X 构建,无论鼠标移动如何,它都会运行得非常流畅。我更喜欢使用 3.X 的解决方案。
【问题讨论】:
-
尝试在您的 Rectange 上设置 IsHitTestVisible="False" 并删除网格(因为您在当前示例中不需要它)
-
@Demon 谢谢,但这并没有改变任何东西。如果您使用文本绑定到值的文本框也会发生同样的事情,移动鼠标时它会延迟更新。鉴于此示例的基本原理,此问题肯定会影响所有 WPF 应用程序???
-
添加到 OP,“当针对 .Net Framework 4.X 和 .Net Core 构建时,似乎会出现此问题。如果使用 Framework 3.X 构建,无论鼠标移动如何,它都会运行得非常流畅。我'我更喜欢使用 3.X 的解决方案。”
-
虽然不是直接回答您的问题,但使用周期性
Task看起来不受鼠标移动的影响。 -
@mcy 感谢您的提示,看来如果您在主 GUI 线程上创建一个周期性任务(即,在使用 .ConfigureAwait(true) 的循环中),它就会保持流畅。与使用 System.Windows.Threading.DispatcherTimer 相同。任何来自不同线程的值更新(即 System.Threading.Timer,在它自己的线程中运行任务或使用 ConfigureAwait(false))然后你会得到窗口的延迟更新。考虑到我的应用程序中的数据实际上是通过后台线程(根本不是计时器)上的 TCP 套接字异步更新的,我没有看到任何简单的方法来解决这个问题:(