【问题标题】:WPF Window lag when moving mouse移动鼠标时WPF窗口滞后
【发布时间】: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 套接字异步更新的,我没有看到任何简单的方法来解决这个问题:(

标签: c# wpf lag


【解决方案1】:

因此,当您从后台线程调用 PropertyChanged 时,WPF 绑定会自动将更新编组到 GUI 线程以进行更新。

WPF Databinding thread safety?

出于某种原因,我认为这是快速移动鼠标时出现延迟的地方,可能是由于调度程序队列中的事件优先级。

如果您手动将更新编组到 GUI 线程上,它可以解决问题。

即特定属性更新:

Timer = new Timer((o) =>
{
    Application.Current.Dispatcher.BeginInvoke(new Action(() =>
    {
        Value = Increment(Value);
    }));
}, null, 0, 10);

一般来说:

protected void RaisePropertyChangedEvent(String propertyName = "")
{
    Application.Current.Dispatcher.BeginInvoke(new Action(() =>
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }));
}

无论鼠标移动如何,执行上述任一操作都将提供流畅的更新。如果使用计时器,您也可以只使用 DispatcherTimer,以便在主线程的 Dispatcher 循环顶部执行调用。 https://docs.microsoft.com/en-us/dotnet/api/system.windows.threading.dispatchertimer?view=windowsdesktop-5.0

很高兴听到一些建议,如果有更好的方法来实现这一点,或者涉及任何警告。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多