在 ScrollViewer 中,我显示了包(永远的垃圾邮件),界面冻结并且 CPU 负载过重。
系统日志的输出在哪里:
<ScrollViewer c:AutoScrollBehavior.AutoScroll="True" Background="White" Grid.Row="1" Content="{Binding LogSystem, Mode=OneWay}" Margin="10" />
主窗口视图模型
private string logSystem;
public string LogSystem
{
get { return logSystem; }
set
{
logSystem = value;
OnPropertyChanged("LogSystem");
}
}
#region LogMessage
/// <summary>
/// Очистить журнал, если сообщение не предоставлено или пусто.
/// </summary>
/// <param name="msg"></param>
private void Log(string msg = "")
{
if (!exit)
{
if (msg.Length > 0)
{
LogSystem += string.Format("[ {0} ] {1}{2}", DateTime.Now.ToString("HH:mm"), msg, Environment.NewLine);
}
else
{
logSystem = string.Empty;
}
}
}
private string ErrorMsg(string msg)
{
return string.Format("ERROR: {0}", msg);
}
private string SystemMsg(string msg)
{
return string.Format("SYSTEM: {0}", msg);
}
#endregion
联系
private void Connection(MyClient obj)
{
Log(SystemMsg(string.Format("PTU has connected")));
IpClient = $"{((IPEndPoint)obj.client.Client.RemoteEndPoint).Address}:{((IPEndPoint)obj.client.Client.RemoteEndPoint).Port}";
Send("Create Menu", "02-30-00-80-00-01-11-11-ad-09-01-00-00-00-60-8c-90-02-01-20-05-00-10-80-00-00-00-02-42-00-02-05-dc-00-00-00-11-00-00-12-b2-09-02-00-00-00-60-8c-91-02-01-20-05-00-10-00-00-00-00-02-40-00-01-05-de-00-00-00-11-00-00-b1-b0-00-00-c8-13-02-00-00-00-00-00-00-00-00-11-b2-af-00-00-c8-13-02-00-00-00-00-00-00-00-00-11-b3-b1-00-60-88-10-02-10-00-00-00-00-00-00-00-11-b4-ae-00-60-88-10-02-10-00-00-00-00-00-00-00-11-00-01-00-01-10-49-03");
while (obj.client.Connected && active)
{
try
{
obj.stream.BeginRead(obj.buffer, 0, obj.buffer.Length, new AsyncCallback(Read), obj);
obj.handle.WaitOne();
}
catch (Exception ex)
{
Log(ErrorMsg(ex.Message));
}
}
obj.client.Close();
IpClient = string.Empty;
Log(SystemMsg("PTU has disconnected"));
}
读
private void Read(IAsyncResult result)
{
MyClient obj = (MyClient)result.AsyncState;
int bytes = 0;
if (obj.client.Connected)
{
try
{
bytes = obj.stream.EndRead(result);
}
catch (Exception ex)
{
Log(ErrorMsg(ex.Message));
}
}
if (bytes > 0)
{
obj.data.AppendFormat("{0}", Encoding.UTF8.GetString(obj.buffer, 0, bytes));
try
{
if (obj.stream.DataAvailable)
{
obj.stream.BeginRead(obj.buffer, 0, obj.buffer.Length, new AsyncCallback(Read), obj);
}
else
{
var hexString = BitConverter.ToString(obj.buffer,0,bytes);
var name = getterGataTrain.WhatsIt(hexString.ToString());
if (name != null)
{
Log($"PTU->Train: [{name}] {hexString}");
switch (name)
{ //TRIAL RUN RECORD
case "TRIAL RUN RECORD":
StringBuilder hex0 = new StringBuilder();
hex0.Append("02-30-00-64-F1-03-11-21-03-03-07-24-59-FF-AD-00-");//02-30-00-64-F1-03-11-21-03-03-07
hex0.Append("49-05-D8-0F-C0-2E-16-2E-2E-2E-18-15-16-14-14-16-");
hex0.Append("00-00-00-00-00-00-00-00-00-DB-DB-DB-79-83-7B-7D-");
hex0.Append("7A-83-43-44-96-96-3A-39-6A-01-2E-00-0A-00-00-10-");
hex0.Append("00-00-00-00-00-00-55-00-14-41-00-08-01-10-41-10-");
hex0.Append("FF-0F-E0-3F-FF-FF-50-01-00-FE-47-01-01-01-01-10-");
hex0.Append("50-03-00-00-00-00-00-00-00-00-00-00-00-00-00-00");
Send("TRIAL RUN RECORD", hex0.ToString());
break;
}
}
else Log($"PTU->Train: {hexString}");
obj.data.Clear();
obj.handle.Set();
}
}
catch (Exception ex)
{
obj.data.Clear();
Log(ErrorMsg(ex.Message));
obj.handle.Set();
}
}
else
{
obj.client.Close();
obj.handle.Set();
}
}
发送
private void Send(string message,string hex)
{ Log($"Train->PTU:{hex}");
byte[] Send = Convertors.StringToByteArray(hex);
obj.stream.Write(Send, 0, Send.Length);
}
问题是通过重写其内容将文本添加到一行完全需要重新绘制整行的内容。
为了解决这个问题,我们需要
TextBox,即使在 modeIsReadOnly = true。文本框有一种方法TextBox.AppendText()可以快速轻松地将一些文本添加到文本框的末尾。即使里面有很多文字,添加也非常快。但是有一个细微的差别,你不应该无休止地添加行,因为如果你的文本长度超过(以字节为单位)2 GB,那么应用程序将崩溃,此外,我不认为在大容量文本上,它不会减速。因此,我将对最大行数进行限制。而这里的方法
TextBox.Select()和属性将对我们有所帮助TextBox.SelectedText。请注意,我根本不使用该属性
TextBox.Text。访问此属性会导致文本框的全部内容呈现在 中string,这可能会导致相同的制动与大量文本和频繁调用。由于在 MVVM 中直接使用控件并不是一件干净的事情,因此我创建了一个文本框继任者。
TotalMaxLines负责拆除多余的旧线路。如果为 0 或更少,则没有限制。LineSource负责将新行写入文本框,而自动换行来分割行。也就是说,您不应该手动添加Environment.NewLine到代码中的行。接下来,我将这个控件拧入窗口
在这段代码的帮助下,我测试了一切
注意
LogSystem = string.Format,这里的代码已经改变了。上面的例子有一个缺陷。如果您多次写入属性的
LogSystem速度如此之快,以至于界面没有时间在两次覆盖之间进行更新,那么被覆盖的行可能会丢失。不幸的是,这是对行为的限制DependencyProperty,您可以通过在视图模型一侧创建缓冲机制来绕过它而不会产生太大的反常,也就是说,在控件获取值并重置缓冲区时捕捉到这一事实。这种可能性非常小,但无论如何,为了可靠性,最好将日志并行写入文件。Log您的下一个问题是从第三方线程调用方法。要将输出重定向到 UI 线程,您可以使用Dispatcher,或例如Progress<T>.这就是代码可以更改的方式,以便接口的输出成为线程安全的。
Progress自动将输出重定向到创建它的同步上下文 (new Progress)。