将简单的“计算机仿真”应用程序从 WINFORM 迁移到 WPF
展示了将一个简单应用程序从WINFORM移植到WPF的一些步骤、陷阱和差异
WinForm

WPF

目录
引言
本文不是关于应用程序本身,而是关于将应用程序从WinForm移植到WPF。将一个简单应用程序从WinForm移植到WPF有多难?代码会发生多大变化?
我对WPF完全陌生,所以我可能得出了错误的结论,或者没有发现已有的功能。欢迎评论和提示。
我花了两天时间编写原始代码。我花了大约一周时间进行移植。
背景
我刚完成一个模拟非常简单计算机的程序。我打算使用这个应用程序来教授一些计算的基本概念。现在我必须编写文档。我读了Code Project上的一篇WPF示例文章,所以我决定移植我的代码,并发现其中的差异。文档总是可以等等。
关于应用程序的说明
该程序模拟了一台非常简单的十进制数字计算机。如果你想使用它,请查看“如何操作”选项卡。它需要更多的文档。
移植代码
自定义控件
该控件必须移动到一个类库中,并且不会像在WinForm中那样出现在工具箱中。由于我的控件派生自TextBox,所以我首先会放置一个TextBox,然后在XAML文件中更改其名称。
所有的DesignerAttributes
都被移除,事件变成了重写方法。重写方法与事件不同,所以你必须寻找正确的方法。在Winform中,使用PreFilterProperties
移除属性是不可用的。你可以在XAML中访问属性,可能是通过反射。
移除属性似乎不存在。所以以下WinForm代码没有等效项
public class DesignMemoryLocation :
System.Windows.Forms.Design.ParentControlDesigner
{
protected override void PreFilterProperties
(System.Collections.IDictionary properties)
{
properties.Remove("Multiline");
properties.Remove("Text");
properties.Remove("MaxLength");
}
}
Application
你的类派生自Window而不是Form。所以你处于一个不同的世界。你突然需要更多的程序集。
布局新外观的提示 (XAML)
首先,只尝试一些简单的布局,移动它们,向网格添加列和行,添加一些网格和一些分隔线。几个小时内,甚至不要看你的项目。
划分网格后,放置几个按钮。查看生成的XAML。删除margin、width、height,然后查看结果。大多数情况下,删除这些以及列跨度和行跨度可以改善布局。
UniformGrid
三个UniformGrid
用于行标题、行号和内存。
UniformGrid
非常有效地取代了TableLayout
。具有100个相同元素的内存必须在代码中完成。使用划分的网格来定位元素效果非常好,特别是放置列标题和行号。
XAML可能令人不知所措。
<TextBlock HorizontalAlignment="Center" VerticalAlignment="Bottom">x0</TextBlock>
要在某一列的左侧显示x0
,使用样式可能会有所帮助,但我还没有弄清楚它是如何工作的。我的下一篇阅读是关于XAML的。
数据网格
字段信息再次使用反射找到。行数据驻留在派生自ObservableCollection
的类中。你必须将System.Collections.ObjectModel
添加到你的程序集中。总的来说,DataGrid
非常好用。有很多关于它的文章,所以我不会详细介绍。
using System.Collections.ObjectModel;
public class Program : ObservableCollection<LineOfCode>
LineOfCode
是行的名称。
行选择
选择行的代码显示了一些有趣的差异。
Winform
void SelectRow(int row)
{
for (int r = 0; r < SourceProgram.Rows.Count; r++)
SourceProgram.Rows[r].Selected = r == row;
SourceProgram.FirstDisplayedCell = SourceProgram[0, row];
}
WPF
void SelectRow(int row)
{
SourceProgram.UnselectAllCells();
SourceProgram.SelectedItem = SourceProgram.Items[row];
}
取消选择是受欢迎的。另请注意,行选择是通过将SourceProgram.Items[row]
存储到选定项中完成的。这是因为项是单行数据的类。这种设计简化了代码。
更新显示
从文件读取源代码后,必须使DataGrid
无效。我找不到任何方法可以做到这一点,除了以下这个丑陋的代码。我欢迎任何提示。
/// <summary>
/// Force the display to be updated
/// there must be a better way to do this !!!
/// </summary>
private void UpdateDisplay()
{
// there must be a better way to do this !!!
SourceProgram.SelectedItem = SourceProgram.Items[99];
SourceProgram.ScrollIntoView(SourceProgram.SelectedItem);
DoEvents();
SourceProgram.SelectedItem = SourceProgram.Items[0];
SourceProgram.ScrollIntoView(SourceProgram.SelectedItem);
DoEvents();
}
DoEvents
使用WinForm,你可以使用Application.DoEvents()
。
使用WPF,你必须创建一个虚拟线程来拉取消息。
/// <summary>
/// Allows the completion of any UI processing
/// </summary>
private void DoEvents()
{
Application.Current.Dispatcher.Invoke
(DispatcherPriority.Background, new ThreadStart(delegate { }));
}
private bool Step()
{
DoEvents();
...
背景颜色
BackColor
颜色变为Background
。这是一个更好的名称,但它需要一个Brush
,并且枚举现在来自Colors
而不是Color
。
在DataGridView中编辑和验证单元格
原始版本 (CommittingEdit)
事件发生了显著变化。在某些情况下,它似乎更简单,在其他情况下则不那么简单。我认为他们试图做出普遍改进,但你不能满足所有人,包括你的父亲。
例如,比较SourceProgram_CommittingEdit(object sender, DataGridEndingEditEventArgs e)
与SourceProgram_CellEndEdit(object sender, DataGridViewCellEventArgs e)
中的代码,后者在对某行代码进行更改时发生。你会注意到惊人的差异。
版本 1 (SelectedCellsChanged)
SourceProgram_CommittingEdit
已被移除。它没有真正正常工作,希望在不久的将来会重新安装。
如何在没有CommittingEdit
的情况下支持字段编辑?这是一个权宜之计,直到CommittingEdit
得到支持。
添加了两个变量来记住上一个单元格。
LineOfCode previousLineOfCode = null;
int previousIndex = 0;
执行字段验证的函数CheckProgram
将由各种事件调用。
private void CheckProgram(DataGrid program)
{
if (!(program.CurrentItem is LineOfCode))
return;
LineOfCode checkLine = previousLineOfCode;
int checkColumnIndex = previousIndex;
previousLineOfCode = (LineOfCode)program.CurrentItem;
previousIndex = program.CurrentColumn.DisplayIndex;
if (checkLine == null)
return;
switch (checkColumnIndex)
...// validate the field
调用CheckProgram
的事件
SourceProgram_SelectedCellsChanged
SourceProgram_PreviewLostKeyboardFocus
SourceProgram_LostFocus
后两个似乎并非总是有效。我认为如果你真的需要字段编辑完美工作,你将不得不在所有Getfocus
事件中调用CheckProgram
。
这是如何工作的?
最重要的事件是SelectedCellChanged
。当这种情况发生时,上一个单元格已被编辑,应进行检查。问题是当前单元格不是关注的单元格。因此,代码只是检查了记住的上一个单元格。
你必须非常小心,如果在CheckProgram
中更改当前单元格,将调用SelectedCellsChanged
,并且你将陷入无限递归。因此,如果你想强制用户转到另一个单元格,最好添加一些逻辑来检测这种情况。
文件对话框
不再有像saveFileDialog_FileOk
这样的事件,对于其他事件,你必须调用对话框。从某种意义上说,它更原始,但不是大问题。唯一的问题是你的代码将需要进行大量更改。
RTF
WPF尚不支持浏览器。所以我选择RTF作为文档。这可能不是一个好主意。读取RTF文件是不同的。
Winform
if (File.Exists("howto.rtf")) HowTo.LoadFile("howto.rtf");
WPF
if (File.Exists("howtox.rtf"))
using (FileStream fs = File.Open("howto.rtf", FileMode.Open))
{
TextRange documentTextRange = new TextRange(
HowTo.Document.ContentStart,
HowTo.Document.ContentEnd);
documentTextRange.Load(fs, DataFormats.Rtf);
}
多行工具提示 (关于工具提示的提示 :)
你不能使用\n
,所以要么你搜索所有控件中的"\\n"
并将它们替换为"\n"
,要么你可以使用以下方法
<Button Grid.Column="1" Grid.Row="2" Margin="10" Name="StopButton"
Opacity="0.65" Grid.ColumnSpan="3" Click="StopButton_Click" >
<Button.ToolTip>
<TextBlock>
Depress to stop a running program.
<LineBreak/>
Highlighted when a halt instruction is executed.
</TextBlock>
</Button.ToolTip>
Stop
</Button>
这也似乎表明工具提示可以是任何东西。有人想要动画GIF吗???
关注点
值得吗?这做起来很有趣。如果演示是你的产品的重要组成部分,并且你想要一个全新的、真正漂亮的外观,这就是方法。
我还没有真正利用这个平台。我将回去,阅读更多关于它的内容,并尝试改善用户界面的外观。这只是第一次快速移植。
历史
- 2008年11月2日:初始版本
- 2008年11月6日:使用
WPFTool
版本1