我是初学者WPF开发人员。作为一个学习练习,我试图使用带有MVVM模式的WPF重新创建Visual Studio的内存窗口。对于那些不熟悉这个窗口的人。
为简单起见,我们假设内存是只读的,不会改变。根据MVVM模式,我们定义以下实体:
模型是一个包含2个属性的简单对象:
long Address
byte[] Data
模型表示定义的内存地址(Data
)的字节序列(Address
)。
ViewModel 将模型作为输入并公开以下属性:
string Addresses
表示同一行上显示的字节地址的string
。引用背景部分中的图片,Addresses
string
包含第一列的内容,即:
string Addresses = "0x022699B0" + '\n' +
"0x022699C8" + '\n' +
"0x022699E0" + '\n' +
...
string HexBytes
模型中Data
的十六进制表示形式。引用背景部分中的图片,HexBytes
string
包含第二列的内容,即:
string HexBytes = "c0 ac 45 68 06 ..."
string ASCIIBytes
模型中Data
的ASCII表示形式。引用背景部分中的图片,ASCIIBytes
string
包含第三列的内容,即:
string ASCIIBytes = "A.Ch....9.1.1.1.2.5 ..."
总而言之, ViewModel 以视图友好格式显示给出模型的数据。
查看可能最容易通过XAML代码段进行描述:
<UserControl x:Class="HexEditor.HexView"
xmlns ="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:z="clr-namespace:HexEditor">
<UserControl.DataContext>
<z:MemoryViewModel/>
</UserControl.DataContext>
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="3*"/>
<ColumnDefinition Width="1*"/>
</Grid.ColumnDefinitions>
<TextBox Grid.Column="0" IsReadOnly="True" Cursor="Arrow" FontFamily="Consolas" Text="{Binding Addresses, Mode=OneWay}"/>
<TextBox Grid.Column="1" IsReadOnly="True" TextWrapping="Wrap" Cursor="Arrow" FontFamily="Consolas" Text="{Binding HexBytes, Mode=OneWay}" />
<TextBox Grid.Column="2" IsReadOnly="True" TextWrapping="Wrap" Cursor="Arrow" FontFamily="Consolas" Text="{Binding ASCIIBytes, Mode=OneWay}" />
</Grid>
请注意,已在第二列和第三列上设置了TextWrapping
属性。这允许我们每行显示可变数量的字节,具体取决于Window的大小。
我遇到的问题是 ViewModel 必须公开的属性取决于视图的大小。在MVVM模式中, ViewModel 应独立于视图。这不是HexBytes
和ASCIIBytes
的问题,因为它们是从模型生成的。问题是如何生成Addresses
?要生成此string
,我必须知道将在每一行上显示的字符数(以便我可以计算下一行的第一个字节的正确地址)。不幸的是,这只是视图所知道的,因为它取决于视图的大小。
我尝试解决此问题的方法是捕获查看代码隐藏中的SizeChanged
事件,并使用TextBox.GetLineLength
方法通知 ViewModel 一行可以容纳多少字节。然后, ViewModel 可以使用此值来生成正确的Addresses
属性。
关于我提出的解决方案,我有两个问题:
TextBox
的第一行显示的字符数?非常感谢任何意见或建议。
答案 0 :(得分:1)
当您在事件处理程序中捕获该值时,只需更新从该事件处理程序中保留此值的VM属性,这样一旦事件触发,VM将始终具有该值...
由于您的VM已经是视图的DataContext
,因此这不会破坏MVVM模式,并且更新VM属性的值非常简单:
这一切都在您的View代码隐藏中:
字段:
private MyViewModel vm;
在视图构造函数中(如果动态分配DataContext,则为DataContextChanged事件):
vm = DataContext as MyViewModel; //Get VM instance from view's DataContext
在事件处理程序中:
vm.AddressLenght = TextBox.GetLineLength;
答案 1 :(得分:0)
是否有更优雅的方式通知ViewModel可以在1行显示的字符数
我认为你的方法是最好的。您想到的结果 - 带有推断列标题的可变列宽 - 意味着视图模型对视图的依赖性。 (有些MVVM方法使用某种&#34;消息传递和#34;框架(例如,事件聚合器)在视图和视图模型之间进行通信,但这只是让视图直接调用方法的更正式的方式。视图模型。)此外,您需要在任何情况下处理SizeChanged
事件,以便在每个重新调整大小时重新生成列标题。
我是否正在使用正确的控件和更正确的方法来获得最终结果
看起来很好。您可以考虑使用ObservableCollection<string>
以及ItemsControl
或ListBox
(而不是带有换行符的扁平字符串)。这样您就可以更好地控制用户界面,从而实现突出显示/选择单个地址等内容。同步滚动地址/字节;和虚拟化面板,以处理更大的数据集,而不会降低用户界面。