我正在尝试绘制一个从另一个线程异步接收输入的表单。输入过程会消耗大量的CPU时间。因此,我试图设置每秒大约10次的刷新率,但我正在努力实现这一目标。我想知道你们认为我能做些什么来加速我的代码,如果有的话?我试着将它减少到最简单的代码量。有些代码最初是从网络上发现的不同应用程序复制的,所以如果我遗漏了一些无关的东西,我会道歉(随时告诉我)。我可以根据请求尝试从抽象方法中提供更多代码。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using TagReader;
using Interactor;
using MathNet.Numerics.Distributions;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Media;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
namespace RFIDInteraction
{
abstract class RFIDApplication : Form
{
DateTime lastTime = DateTime.Now;
int refreshEllapse = (int)1000 / 10; //only refresh if 10 ms have passed
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
protected void maybeRefresh()
{
if ((DateTime.Now - lastTime).Milliseconds > refreshEllapse)
{
this.Refresh();
lastTime = DateTime.Now;
}
}
[MethodImpl(MethodImplOptions.Synchronized)]
private void InputWrapper(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
updateLoopStep(inputs); //code in this method (not shown) does some update based on the input - this could be expensive
maybeRefresh();
}
#region boringstuff
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
this.SuspendLayout();
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(1000, 1000);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.Fixed3D;
this.Name = "Application";
this.Text = "Application";
this.Load += new System.EventHandler(this.LoadContent);
SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint | ControlStyles.OptimizedDoubleBuffer | ControlStyles.ResizeRedraw, true);
this.ResumeLayout(false);
}
#endregion
protected Application()
{
InitializeComponent();
System.Collections.Specialized.NotifyCollectionChangedEventHandler inputCallback =
new System.Collections.Specialized.NotifyCollectionChangedEventHandler(InputWrapper);
new TagStatesThread(inputCallback); //Thread runs in background - could be an expensive process
}
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
protected void LoadContent(object sender, EventArgs e)
{
this.SetStyle(
ControlStyles.AllPaintingInWmPaint |
ControlStyles.UserPaint |
ControlStyles.DoubleBuffer,
true);
this.UpdateStyles();
loadAllContent(); //some simple method (not shown) which loads Image assets and such (once)
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
e.Graphics.Clear(BackColor);
//code in this method (not shown) handles drawing all the Images - by simply iterating through them all and calling e.Graphics.DrawImage. May have to draw a large number of images (up to 100)
displayNewState(e.Graphics);
}
}
}
另外,一个问题 - 当进行绘制调用,并且不需要做任何事情时,它似乎绘制得更快 - 这意味着如果不必更改像素,则消耗几乎可以忽略不计的处理时间(建议系统会自动检查需要绘制的内容并且非常智能。这是真的吗?
编辑:示例应用程序的屏幕截图:
答案 0 :(得分:2)
好吧,这就是你在WPF中的表现:
创建一个小的数据模型,用他们的方块代表您的Tic Tac Toe游戏:
public enum SquareValue
{
Empty = 0,
X = 1,
O = 2
}
public class Square: INotifyPropertyChanged
{
private SquareValue _value;
public SquareValue Value
{
get { return _value; }
set
{
_value = value;
OnPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
var handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
}
public class Game
{
public List<Square> Squares { get; private set; }
public Game()
{
this.Squares =
Enumerable.Range(0, 9)
.Select(x => new Square { Value = SquareValue.Empty })
.ToList();
}
}
请注意,Square类需要Implement
INotifyPropertyChanged
才能支持双向DataBinding。
使用ItemsControl,定义每个Tic Tac Toe板的外观:
<ItemsControl ItemsSource="{Binding Squares}" Margin="5" BorderThickness="1" BorderBrush="DarkBlue">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Rows="3" Columns="3"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border BorderBrush="DarkGray" BorderThickness="1">
<Path x:Name="Path" Stretch="Fill"
Margin="2"/>
</Border>
<!-- to be continued... -->
请注意,我们将
ItemsPanel
设置为3x3UniformGrid
,ItemTemplate
包含空Path
。
使用DataTrigger
,我们会定义广场的外观,具体取决于它是Empty
,X
还是O
:
<!-- continuation of the above XAML -->
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding Value}" Value="X">
<Setter TargetName="Path" Property="Stroke" Value="Red"/>
<Setter TargetName="Path" Property="Data" Value="M0,0 L10,10 M0,10 L10,0"/>
</DataTrigger>
<DataTrigger Binding="{Binding Value}" Value="O">
<Setter TargetName="Path" Property="Stroke" Value="Blue"/>
<Setter TargetName="Path" Property="Data">
<Setter.Value>
<EllipseGeometry RadiusX="10" RadiusY="10" Center="0.0,0.0"/>
</Setter.Value>
</Setter>
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
我们现在每个Tic Tac Toe板都有XAML,让我们现在创建一些XAML代表许多板,再次使用另一个ItemsControl
:
<ItemsControl ItemsSource="{Binding}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Rows="10" Columns="10"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<!-- the above XAML for a single Tic Tac Toe board goes here -->
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
请注意,这次我们使用10 x 10
UniformGrid
,因为我们将展示100个Tic Tac Toe板
现在我们将Window&#39; DataContext
设置为我们的Game类列表:
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
this.Loaded += (sender, args) =>
{
this.DataContext = Enumerable.Range(0,100)
.Select(x => new Game())
.ToList();
};
}
}
使用您想要的任何方法,修改Value
的{{1}}属性,使其变为Square
或X
。在这种情况下,因为这只是一个演示,我将使用O
并随机设置它。像这样修改Timer
类:
Game