我确定它已经存在,但一直无法找到它。 我正在寻找一个在我的应用程序上显示某种动画的 WPF 控件,以便我可以轻松判断 UI 线程何时锁定。 我正在寻找一个控件来显示 UI 线程被锁定的时间。 这将是一个开发工具,我只会在调试模式下运行时启用,并且当 UI 长时间无响应时,将用于识别应用程序中的性能问题。 所以我正在寻找类似于 Visual Studio PerfWatson Monitor。
我知道我可以自己写一个,但我确信其他人已经这样做了(而且可能比我更好)。如果您知道,请与我分享。谢谢!
我昨天打算回复这个问题,但没有完整的解决方案,只是一个建议!
我做了类似的事情,并创建了一个订阅 CompositionTarget.Rendering 的控件作为“UI 线程繁忙度”的简单指示器,然后在每秒更新一次的非常小的条形图上绘制帧速率(1.0/事件之间的时间)。所讨论的条形图非常轻量级,并且使用位图而不是 WPF 元素,因此它不会占用太多 CPU 时间。该控件可以作为装饰器覆盖在任何 WPF 表单上,以调试性能问题。
这非常有启发性,因为它实时显示 UI 线程丢失。
抱歉,我无法分享任何代码,因为它是我公司的专有代码,但我认为它可以让您了解如何解决这个问题。
为仅包含旋转矩形的任何控件创建一个控件模板。
然后,当您处于调试模式时,从代码后面添加控件,以确保它不会进入发布状态。
#if DEBUG
if(runtimeCondition)
{
//add or unhide control
}
#end if
真的很容易实现,这里有一个模板。
<ControlTemplate x:Key="spinningSquareTemplate">
<ControlTemplate.Resources>
<Storyboard x:Key="OnLoaded1" RepeatBehavior="Forever">
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[2].(RotateTransform.Angle)" Storyboard.TargetName="rectangle">
<EasingDoubleKeyFrame KeyTime="0:0:1" Value="360"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</ControlTemplate.Resources>
<Rectangle x:Name="rectangle" Fill="#FFFFB900" Stroke="Black" RenderTransformOrigin="0.5,0.5">
<Rectangle.RenderTransform>
<TransformGroup>
<ScaleTransform/>
<SkewTransform/>
<RotateTransform/>
<TranslateTransform/>
</TransformGroup>
</Rectangle.RenderTransform>
</Rectangle>
<ControlTemplate.Triggers>
<EventTrigger RoutedEvent="FrameworkElement.Loaded">
<BeginStoryboard Storyboard="{StaticResource OnLoaded1}"/>
</EventTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
当您的 UI 锁定时,方块将停止旋转。
这是基于 Dr. 的基本解决方案。安德鲁对 CompositionTarget.Rendering
的
见解:
using System.Threading;
//...
public class UiMonitor
{
public int FPS => _fps;
private int _frames;
private int _fps;
private readonly Timer _timer;
public UiMonitor()
{
_timer = new Timer(HandleTick, null, 1000, 1000);
Application.Current.Dispatcher.BeginInvoke(() =>
{
CompositionTarget.Rendering += HandleCompositionRendering;
});
}
private void HandleTick(object state)
{
_fps = Interlocked.Exchange(ref _frames, 0);
}
private void HandleCompositionRendering(object sender, EventArgs e)
{
Interlocked.Increment(ref _frames);
if (_fps > 30)
{
// ...
}
}
}
如果您想创建类似的控件,只需从
INotifyPropertyChanged
继承,然后在 FPS 更新后向您设计的任何图表或指标发出通知(FPS 属性已经每秒更新一次)。