일부 캡처 된 네트워크 데이터 (이진 파일)의 WinForms 디스플레이가 있습니다. 나는 WPF로 학습 운동으로 옮기려고 노력하고 있으며 앞으로 더 많은 관리가 가능해야하기 때문에 노력하고 있습니다.이진 데이터 표시에 적합한 WPF 레이아웃
이진 데이터의 가장 일반적인 표시 형식은 왼쪽의 각 값의 숫자 값과 오른쪽의 인쇄 가능한 ASCII 문자에 해당하는 8 진수의 문자열 표시를 모두 보여주는 이중 열 레이아웃입니다.
또한 각 값의 색을 독립적으로 변경하여 감지 된 변경 사항을 강조 할 수 있기를 원합니다.
지금까지 나는FlowDocument
가
Table
에 의해 채워지는
RichTextBox
으로 시도했습니다.
TableRowGroup
과 숫자 표시 용과 문자열 표시 용의 두 개의 열이 있습니다.
루프가 데이터가 변경 될 때마다 TableRowGroup
을 다시 생성합니다. 16 바이트의 데이터마다 Paragraph
이 포함 된 새로운 TableRow
이 생성됩니다. TableCell
내의 값은 각각 Run
으로 관리됩니다. Run
색칠이 필요한 값에 해당하는 객체는 에 배치되기 전에 Span
에 더 중첩됩니다.
이 기능은 작동하지만 보통 데이터 크기의 WinForms RichTextBox
보다 눈에 띄게 느립니다. WPF는 ~ Run
인스턴스를 하나의 FlowDocument
에 포함 시키도록 실제로 설계되지 않았다고 가정합니다.
또한 나는 많은 수의 TableCell
과 Run
개체의 명령 생성이 WPF의 의도 된 방법이 아니라고 들었습니다. 그러나이 방법을 뷰 모델로 매핑하는 방법, 변경된 표시 옵션뿐 아니라 새 데이터의 속성 변경을 트리거하는 방법에 대해서는 잘 모르겠습니다.
의견을 보내 주시면 감사하겠습니다. 클립 보드 복사 지원은 매우 바람직합니다.
internal void RenderMessageDiff(GameMessage oldMsg, GameMessage newMsg)
{
if (newMsg == null) return;
var tablerows = new TableRowGroup();
if (oldMsg == null) oldMsg = newMsg;
var aby = newMsg.payload;
for (int offset = 0; offset < aby.Length - 1; offset += 16)
{
var leftCol = new Paragraph();
var rightCol = new Paragraph();
int blocklen = Math.Min(16, aby.Length - offset);
switch (selectDisplayFormat.SelectedValue as string)
{
case "u1":
for (int i = 0; i < blocklen; ++i)
{
if (i > 0) leftCol.Inlines.Add(new Run(","));
var v = new Run(aby[offset + i].ToString());
if (aby[offset + i] == oldMsg.payload[offset + i])
leftCol.Inlines.Add(v);
else
leftCol.Inlines.Add(new Span(v) { Foreground = Brushes.Red });
}
break;
case "u2":
for (int i = 0; i + 1 < blocklen; i += 2)
{
if (i > 0) leftCol.Inlines.Add(new Run(","));
var v = new Run(newMsg.ConvertUInt16LE(offset + i).ToString());
if (newMsg.ConvertUInt16LE(offset + i) == oldMsg.ConvertUInt16LE(offset + i))
leftCol.Inlines.Add(v);
else
leftCol.Inlines.Add(new Span(v) { Foreground = Brushes.Red });
}
break;
case "u4":
for (int i = 0; i + 3 < blocklen; i += 4)
{
if (i > 0) leftCol.Inlines.Add(new Run(","));
var v = new Run(newMsg.ConvertUInt32LE(offset + i).ToString());
if (newMsg.ConvertUInt32LE(offset + i) == oldMsg.ConvertUInt32LE(offset + i))
leftCol.Inlines.Add(v);
else
leftCol.Inlines.Add(new Span(v) { Foreground = Brushes.Red });
}
break;
case "x1":
default:
for (int i = 0; i < blocklen; ++i)
{
if (i > 0) leftCol.Inlines.Add(new Run(" "));
var v = new Run(aby[offset + i].ToString("X2"));
if (aby[offset + i] == oldMsg.payload[offset + i])
leftCol.Inlines.Add(v);
else
leftCol.Inlines.Add(new Span(v) { Foreground = Brushes.Red });
}
break;
}
Span changeRun = null;
for (int i = 0; i < blocklen; ++i)
{
char c = (char)aby[offset + i];
if (c < 32 || c >= 127) c = '.';
var v = new Run(c.ToString());
if (aby[offset + i] == oldMsg.payload[offset + i])
{
rightCol.Inlines.Add(v);
changeRun = null;
}
else
{
if (changeRun == null)
rightCol.Inlines.Add(changeRun = new Span(v) { Foreground = Brushes.Red });
else
changeRun.Inlines.Add(v);
}
}
tablerows.Rows.Add(new TableRow()
{
Cells = { new TableCell(leftCol), new TableCell(rightCol) }
});
}
textMessageDiff.RowGroups.Clear();
textMessageDiff.RowGroups.Add(tablerows);
}
이것은 단순히 표시하기위한 것입니까? UI에서 값을 편집해야하는 이유가 무엇입니까? – kmacdonald
@kmacdonald : 편집 할 필요가 없습니다. 그러나 다른 사소한 상호 작용이 도움이됩니다. 클립 보드에 복사. 추가 처리를위한 하위 집합 선택. 수색. –
@kmacdonald : 색상 화는 위치 지정에 영향을 미치지 않으므로 단락마다 하나의'Run'으로이 작업을 수행하고 렌더링을 무시할 수 있습니까? 대신에'Grid' 또는'ListView'를 사용해야합니까? –