银河

SKYIV STUDIO

  博客园 :: 首页 :: 博问 :: 闪存 :: :: :: 订阅 订阅 :: 管理 ::
前天(2008年4月2日)在当当网购买了一本书:

Windows Presentation Foundation 程序设计指南
[美]Charles Petzold 著,蔡学镛 译,胡志鹏、魏颢、成功 审校
ISBN: 978-7-121-05115-9,电子工业出版社,2008年1月第1次印刷

Applications = Code + Markup: A Guide to the Microsoft Windows Presentation Foundation
ISBN: 0-7356-1957-3; Microsoft Press; August 2006; 1002 pages
Errata: http://www.charlespetzold.com/wpf/errata.xml

于是就开始了WPF学习之旅。


这本书英文原作写得相当好,中文翻译也很好。英文原作是2006年8月出版的,中译本是在2008年1月出版的,出得有点迟了,而且不知为什么中译本出版时没有按照英文版的勘误表进行更正(倒是有好几处审校者的质疑,其实都是英文版的勘误表中已经更正过的)。

目前发现的错误(不断更新中...):


第190页,倒数第2自然段中间:

如果 Stretch 等于 Stretch.Uniform(默认),MeasureOverride 会利用 sizeAvailable 参数计算出正确的长宽比,并维持这样的比例,且让一个维度(宽或高)等于 sizeAvialable 的 Width 或 Height。

英文原文是:

For Stretch.Uniform(the default setting), MeasureOverride uses the sizeAvailable argument to calculate a size that maintains the correct aspect ratio but has one dimension equaling either the Width or Height dimension of sizeavailable.

我认为应该这样翻译:

如果 Stretch 等于 Stretch.Uniform(这是默认值),MeasureOverride 会利用 sizeAvailable 参数计算出一个尺寸,该尺寸保持正确的长宽比,且让一个维度(宽或高)等于 sizeAvailable 的 Width 或 Height。


第219页,程序代码之后的第2自然段,第1句:

除了 override FrameworkElement 与 Control,建立自定义的控件还有别的方式,使用 XAML 比使用代码的方式更常见,利用样本的定义达到此目的

英文原文是:

Besides overriding FrameworkElement and Control, there is another approach to creating custom controls that is used much more in XAML than in procedural code. This is through the definition of a template.

我认为应该这样翻译:

除了 override FrameworkElement 与 Control,建立自定义的控件还有别的方式,使用 XAML 比使用代码的方式更常见,就是通过定义一个模板来达到此目的


第235页,第2自然段,第2句:

Panel 最大的好处是,它有 Children Property 可以进行孩子的排序

英文原文是:

The big gift of Panel is the definition of Children property for storing the children.

我认为应该这样翻译:

Panel 最大的好处是,它有一个用来存储孩子们的 Children 属性


第239页,第5自然段之后,漏了以下一个自然段:

In other words, the grid is behaving as we might hope and expect. To further test it, dig out the ColorGrid control from the last chapter and replace UniformGrid with UniformGridAlmost.

换句话说,grid 的行为可能符合我们的期望和预期。为了进一步测试它,找出上一章的 ColorGrid 控件,并且将其中的所有 UniformGrid 都替换为 UniformGridAlmost。


第451页,NotePadClone.Help.cs 程序,中间位置:

  itemHelp.SubmenuOpened += ViewOnOpen;

这条语句应该删除(英文原版中就错了)。


第466页,第1句:

构造函数为此 XML 资源建立一个 Uri 对象,然后使用静态的 Application.GetResourceStream property,取得一个 StreamResourceInfo 对象。

这句话是英文原文的错误,不是译者的翻译错误。这句话应该是这样的:

构造函数为此 XML 资源建立一个 Uri 对象,然后调用静态的 Application.GetResourceStream 方法,取得一个 StreamResourceInfo 对象。


第468页,第1自然段,第2句:

你可以使用此程序,加载本章至今的任何 XAML 文件(扩展名是 .xml)

英文原文是:

You can use this program to load any of the XAML files shown is this chapter so far, including those with a file name extension of .xml.

我认为应该这样翻译:

你可以使用此程序,加载本章至今的任何 XAML 文件,包括那些扩展名是 .xml 的文件。(译者注:XAML 文件默认的扩展名是 .xaml)


第490页,XamlCruncher.cs 程序,中间位置:

      split = new GridSplitter();
      split.HorizontalAlignment = HorizontalAlignment.Center;
      split.VerticalAlignment = VerticalAlignment.Stretch;
      split.Height = 6;
      grid.Children.Add(split);
      Grid.SetRow(split, 0);
      Grid.SetColumn(split, 1);
      Grid.SetRowSpan(split, 3);

应改为(英文原版中就错了,但该书网站上提供下载的源程序代码是正确的):

      split = new GridSplitter();
      split.HorizontalAlignment = HorizontalAlignment.Center;
      split.VerticalAlignment = VerticalAlignment.Stretch;
      split.Width = 6;
      grid.Children.Add(split);
      Grid.SetRow(split, 0);
      Grid.SetColumn(split, 1);
      Grid.SetRowSpan(split, 3);


第512页,最后1自然段(除了程序代码以外):

然而,GradientStops property 必须变成一个 property element:

英文原文是:

The GradientStops property is of type GradientStopCollection, so we can put in an object element for that class:

我认为应该这样翻译:

GradientSopts property 的类型是 GradientStopCollection,于是我们可以将其放到一个 object element 中:


第525页,程序代码之后的第1自然段:

注意 StackPanel element tag 定义了一个 XML 命名空间的前缀 s,代表 System 命名空间(clr-namespace:System;assembly=mscorlib),这允许引用此 Resources collection 中的 Double 结构

英文原文是:

Notice that the StackPanel element tag defines an XML namespace prefix of s for the System namespace (clr-namespace:System;assembly=mscorlib), which allows referencing the Double structure in the Resources collection.

我认为应该这样翻译:

注意 StackPanel element tag 定义了一个 XML 命名空间的前缀 s,代表 System 命名空间(clr-namespace:System;assembly=mscorlib),这允许在此 Resources collection 中引用 Double 结构


第569页,程序代码之后的第1自然段,第2句:

然而,Page2 类没有这一关键的 Navigate 方法,可以用于直接访问 NavigationWindow 对象

英文原文是:

However, the Page2 class doesn't have direct access to the NavigationWindow object with that crucial Navigate method.

我认为应该这样翻译:

然而,Page2 类无法直接访问 NavigationWindow 对象,该对象具有关键的 Navigate 方法


第571页,最后1自然段,第2句:

但是这里还有一个有趣的实验:在 FrameNavigationDemoWindow.xaml 中,将 Window 改成 NavigationWindow,然后重新编译。

这句话有问题,建议改为:

但是这里还有一个有趣的实验:在 FrameNavigationDemoWindow.xaml 中,将 Window 改成 NavigationWindow,并添加一个 NavigationWindow.Content property element然后重新编译。


第584页底部到第585页顶部,DirectoryPage.xaml 源代码:

DirectoryPage.xaml <!-- ================================================
      DirectoryPage.xaml (c) 2006 by Charles Petzold
     ================================================ -->
<PageFunction xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
              xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
              xmlns:io="clr-namespace:System.IO;assembly=mscorlib"
              xmlns:tree="clr-namespace:Petzold.RecurseDirectoriesIncrementally"
              x:Class="Petzold.ComputerDatingWizard.DirectoryPage"
              x:TypeArguments="io:DirectoryInfo">
  <Grid>
    <Grid.RowDefinitions>
      <RowDefinition Height="Auto" />
      <RowDefinition Height="*" />
      <RowDefinition Height="Auto" />
    </Grid.RowDefinitions>

    <TextBlock Grid.Row="0" FontSize="16" FontStyle="Italic"
               HorizontalAlignment="Center">
      Computer Dating Wizard
    </TextBlock>


    <tree:DirectoryTreeView x:Name="treevue" Grid.Row="1" />

    <!-- Buttons at bottom-right corner of page. -->
    <Grid Grid.Row="2">
      <Grid.ColumnDefinitions>
        <ColumnDefinition Width="*" />
        <ColumnDefinition Width="Auto" />
        <ColumnDefinition Width="Auto" />
      </Grid.ColumnDefinitions>
      <Button Grid.Column="1" Click="CancelButtonOnClick"
              IsCancel="True" MinWidth="60" Margin="6">
        Cancel
      </Button>
      <Button Grid.Column="2" Name="btnOk" Click="OkButtonOnClick"
              IsEnabled="False" IsDefault="True" MinWidth="60" Margin="6">
        OK
      </Button>
    </Grid>
  </Grid>
</PageFunction>

应改为:

DirectoryPage.xaml <!-- ================================================
      DirectoryPage.xaml (c) 2006 by Charles Petzold
     ================================================ -->
<PageFunction xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
              xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
              xmlns:io="clr-namespace:System.IO;assembly=mscorlib"
              xmlns:tree="clr-namespace:Petzold.RecurseDirectoriesIncrementally"
              x:Class="Petzold.ComputerDatingWizard.DirectoryPage"
              x:TypeArguments="io:DirectoryInfo">
  <Grid>
    <Grid.RowDefinitions>
      <RowDefinition Height="*" />
      <RowDefinition Height="Auto" />
    </Grid.RowDefinitions>

    <tree:DirectoryTreeView x:Name="treevue" Grid.Row="0" />

    <!-- Buttons at bottom-right corner of page. -->
    <Grid Grid.Row="1">
      <Grid.ColumnDefinitions>
        <ColumnDefinition Width="*" />
        <ColumnDefinition Width="Auto" />
        <ColumnDefinition Width="Auto" />
      </Grid.ColumnDefinitions>
      <Button Grid.Column="1" Click="CancelButtonOnClick"
              IsCancel="True" MinWidth="60" Margin="6">
        Cancel
      </Button>
      <Button Grid.Column="2" Name="btnOk" Click="OkButtonOnClick"
              IsEnabled="False" IsDefault="True" MinWidth="60" Margin="6">
        OK
      </Button>
    </Grid>
  </Grid>
</PageFunction>

下面是修改前后程序运行的屏幕截图:

 


第585页,程序代码之后的第1自然段,倒数第2句:

另一个命名空间的声明关联起“tree”前缀和第16章 RecurseDirectoriesIncrementally 工程的命名空间。

这句话后面漏了一句:

That's where the DirectoryTreeView class comes from that forms the bulk of this page.

我认为应该这样翻译:

另一个命名空间的声明关联起“tree”前缀和第16章 RecurseDirectoriesIncrementally 工程的命名空间。而 RecurseDirectoriesIncrementally 命名空间正是此页面主体部分的 DirectoryTreeView 类所在的命名空间。


第586页,程序代码之后的第1自然段,第1句:

构造函数为 DirectoryTree 控件设置 ViewSelectionChanged 事件处理函数,好让 OK 按钮“只有在磁盘驱动器目录被选取的情况下”才会被 enable

英文原文是(这句话中的“SelectionChanged”应该是“SelectedItemChanged”):

The constructor attaches a SelectionChanged event handler to the DirectoryTreeView control so that the OK button is enabled only if a disk directory has been selected.

这认为应该这样翻译:

构造函数为 DirectoryTreeView 控件设置 SelectedItemChanged 事件处理函数,好让 OK 按钮“只有在磁盘驱动器目录被选取的情况下”才会被 enable


第594页,程序代码之后的第1自然段,第1句:

这两个 Hyperlink element 包含的不只是 NaviagateUri attribute (引用两个 XML 文件),也包含了 TargetName attribute (引用 BookList.xaml 页面上方的 Frame)。

英文原文是(这句话中的BookList.xaml”应该是“BookReader.xaml”):

The two Hyperlink elements contain not only NavigateUri attributes that reference two XAML files, but also TargetName attributes that reference the Frame at the left of the BookList.xaml page.

我认为应该这样翻译:

这两个 Hyperlink element 包含的不只是 NaviagateUri attribute (引用两个 XML 文件),也包含了 TargetName attribute (引用 BookReader.xaml 页面左边的 Frame)。


第600页,第1句:

WindowOnLoaded 事件处理函数会用 Tile 对象和 Empty 对象来为 UniformGrid 初始化。

应该改为(这句话英文原文就是错的):

PageOnLoaded 事件处理函数会用 Tile 对象和 Empty 对象来为 UniformGrid 初始化。


第607页,程序代码之后的第1自然段最后2句:

大多数情况下 Label.Content tag 不是必须的,你可以试着移除它。但是在这里,确实是必要的。

经实验,在这里,Label.Content tag 也不是必须的。也就是说,我试着移除它,程序照正常工作。


第609页,最后1自然段,第1句:

现在 ScrollBar 目标是由 Label 源来控制

英文原文是:

Now the ScrollBar target is governing the Label source.

我认为应该这样翻译:

现在 ScrollBar 目标控制 Label 源。


第612页,除了程序代码这外的第3个自然段(在该页正中间):

这段 XAML 在我看起来好像没问题,但却抛出一个异常,告诉我“类型为‘System.Windows.Data.Binding’的对象无法转换成‘System.String’”,这里显然指的是 Text property 的类型。此消息对我来说非常奇怪,因为它言下之意是解析器正在忽略这个再自然不过的数据绑定定义。

在我的计算机上,抛出的异常是:不能在类型“Run”的“Text”属性上设置“Binding”。只能在 DependencyObject 的 DependencyProperty 上设置“Binding”。
这个异常消息再正常不过了。我想本书作者看到的奇怪的异常消息可能是他使用 CTP 版本的 WPF 软件的缘故。


第615页,程序代码之后的第2个自然段,第1句:

第一个 ScrollBar 定义一个 OneWayToSource 绑定,其 Number property 是第一个 SimpleElement

英文原文是:

The first ScrollBar defines a OneWayToSource binding with the Number property of the first SimpleElement.

我认为应该这样翻译:

第一个 ScrollBar 定义一个 OneWayToSource 绑定,绑定到第一个 SimpleElement 的 Number property


第615页,程序代码之后的第3个自然段,第1句和第2句:

第二个 ScrollBar 定义一个 TwoWay 绑定,其 Number property 是第一个 SimpleElement,且你将会看到这个也顺利工作。虽然 SimpleElement 没有显式的通知机制 ScrollBar,操作第一个 ScrollBar 产生的 Number property 的改变,会被此绑定检测到,结果第二个会跟随第一个 ScrollBar 变化。

英文原文是:

The second ScrollBar defines a TwoWay binding with the Number property of the first SimpleElement, and you'll see that this one works as well. Although SimpleElement has no explicit notification mechanism, changes to the Number property as a result of manipulating the first ScrollBar are detected in this binding, and the second ScrollBar tracks the first ScrollBar.

我认为应该这样翻译:

第二个 ScrollBar 定义一个 TwoWay 绑定,绑定到第一个 SimpleElement 的 Number property,且你将会看到这个也顺利工作。虽然 SimpleElement 没有显式的通知机制,操作第一个 ScrollBar 产生的 Number property 的改变,会被此绑定检测到,结果第二个 ScrollBar 会跟随第一个 ScrollBar 变化。


第615页,程序代码之后的第4个自然段,第1句:

第二个 SimpleElement element 定义了一个 OneWay 数据绑定。

英文原文是:

The second SimpleElement element defines a OneWay data binding with the second ScrollBar.

我认为应该这样翻译:

第二个 SimpleElement element 定义了一个 OneWay 数据绑定,绑定到第二个 ScrollBar


第627页,倒数第2自然段,最后2句:

然而,有可能你真正需要的是“被此字段 property 所引用的对象”的某个 property。这种情况下,你需要使用绑定。

英文原文是:

However, it's possible that what you really need is a property of the object referenced by the static property. In that case, you need a binding.

我认为应该这样翻译:

然而,有可能你真正需要的是“被此静态 property 所引用的对象”的某个 property。这种情况下,你需要使用绑定。


第631页,从第2自然段开始,到“就这样”。

原书上这一大段是论述如何定义一个名为 DateTimeChanged 的 public 事件,使用 WPF 数据绑定逻辑去更新 DateTime property。但是经我实验,这没有效果。


第639页,第4自然段,第1句和2句:

Style 类型定义在 System.Windows 中。其派生自 Object,且没有子类。

应改为(英文原文就是错的):

Style 类型定义在 System.Windows 中。其派生自 DispatcherObject,且没有子类。


第646页,程序代码之后的第2自然段:

如果你的应用中有许多对话框,而这些对话框的 Stack Panel 包含一些 radio buttons (放在 Group box 内),为了让这些 Radio Button 看起来更美观。RadioButton 的 TargetType 是很好的 Style 范例。

英文原文是:

If you have a bunch of dialog boxes in an application, and these dialog boxes have some radio buttons on stack panels within group boxes, you know you need to apply a Margin property to each RadioButton to make it look reasonably attractive. This is an excellent application of a Style with a TargetType of RadioButton.

我认为应该这样翻译:

如果你的应用中有许多对话框,而这些对话框的 Stack Panel 包含一些 radio buttons (放在 Group box 内),为了让这些 Radio Button 看起来更美观,你知道需要为每个 Radio Button 应用 Margin property。RadioButton 的 TargetType 是很好的 Style 范例。


第652页,除了程序代码之外的倒数第3自然段,第1句:

答案是 Binding 搭配 RelativeSource,这在本章最后会讨论到

英文原文是:

The solution is a Binding using RelativeSource, which I discussed toward the end of the previous chapter.

我认为应该这样翻译:

答案是 Binding 搭配 RelativeSource,这已经在上一章最后讨论过


第656页,程序代码之后的第1自然中间:

当 Seal 方法被调用,只读的 IsSeal property 被设定为 true

英文原文是:

The read-only IsSealed property becomes true when the Seal method is called, which happpens when the style is in use.

我认为应该这样翻译:

Sytle 被使用时,其 Seal 方法被调用,只读的 IsSealed property 被设定为 true


第677页,程序代码之后的第3自然段,最后1句:

TextBox 与 RichTextBox 控件具有相对简单的模板,因为这两个控件其实是 Border element,而 Border 包含 ScrollViewer 控件,ScrollViewer 再包含实际的编辑器,而编辑器则完全使用代码实现。

这句话英文原文就是这样,但在我的计算机上通过 DumpControlTemplate 程序却得到以下结论:

TextBox 与 RichTextBox 控件具有相对简单的模板,因为这两个控件其实是 ListBoxChrome element,而 ListBoxChrome 包含 ScrollViewer 控件,ScrollViewer 再包含实际的编辑器,而编辑器则完全使用代码实现。


第679页,除了代码之外的倒数第2自然段,第2句:

ContentPresenter 定义了 ContentTemplate property (对象为 DataTemplate),为的是要定义一个“用来显示内容”的模板。

ContentPresenter defines a property named ContentTemplate of type DataTemplate for defining a template used to display content.

我认为应该这样翻译:

ContentPresenter 定义了 ContentTemplate property (类型为 DataTemplate),为的是要定义一个“用来显示内容”的模板。


第680页,程序代码之后的第2自然段,最后1句:

此 UniformGrid 包含一个 TextBlock (用来显示雇员的名称)和一个 StackPanel (具有两个 TextBlock element,用来显示雇员的生日)。

The UniformGrid has a TextBlock for the employee's name and then a StackPanel with six TextBlock elements that effectively format the employee's birth date.

我认为应该这样翻译(英文原文误为“six”):

此 UniformGrid 包含一个 TextBlock (用来显示雇员的名称)和一个 StackPanel (具有五个 TextBlock element,用来显示雇员的生日)。


第694页,第2自然段,第1句:

下面的 Resource section,先定义控件的 layout

英文原文是:

Following the Resources section, the definition of the layout of the control begins.

我认为应该这样翻译:

在 Resources section 之后,先定义控件的 layout


第699页,DatePicker.cs 程序代码,最后一段:

    // Buttons are duplicated by PageDown and PageUp keys.
    protected override void OnPreviewKeyDown(KeyEventArgs args)
    {
      base.OnKeyDown(args);

      if (args.Key == Key.PageDown)
      {
        FlipPage(true);
        args.Handled = true;
      }
      else if (args.Key == Key.PageUp)
      {
        FlipPage(false);
        args.Handled = false;
      }
    }

应改为(英文原版就是错的):

    // Buttons are duplicated by PageDown and PageUp keys.
    protected override void OnPreviewKeyDown(KeyEventArgs args)
    {
      base.OnPreviewKeyDown(args);

      if (args.Key == Key.PageDown)
      {
        FlipPage(true);
        args.Handled = true;
      }
      else if (args.Key == Key.PageUp)
      {
        FlipPage(false);
        args.Handled = true;
      }
    }


第705页,除了程序代码之外的第4自然段:

XPath property 是一个 XML Path Language 字符串。关于 XML Path Language,你可以在 www.w3.org/TR/xpath 看到它的文件

英文原文是:

The XPath property is a string defined in XML Path Language as documented at www.w3.org/TR/xpath, except that no functions are allowed.

我认为应该这样翻译:

XPath property 是一个 XML Path Language 字符串(除了不支持 XPath 函数)。关于 XML Path Language,你可以在 www.w3.org/TR/xpath 看到它的文档


第738页,程序代码中部(NavigationBar.cs),应改为(其中红色的一对大括号是新增的。英文原版就错了):

    void TextBoxOnLostFocus(object sender, KeyboardFocusChangedEventArgs args)
    {
      int current;

      if (Int32.TryParse(txtboxCurrent.Text, out current))
      {
        if (current > 0 && current <= coll.Count)
          collview.MoveCurrentToPosition(current - 1);
      }
      else
        txtboxCurrent.Text = strOriginal;
    }



posted on 2008-04-04 20:51  银河  阅读(2062)  评论(4编辑  收藏  举报