Wpf 简明教程

WPF - Debugging

这是一种识别并修复代码中的错误或缺陷而且它们不会按照您预期的那样工作的系统机制。调试子系统紧密耦合的复杂应用程序不容易,因为在一个子系统中修复错误可能会在另一个子系统中创建错误。

Debugging in C

在 WPF 应用程序中,程序员处理两种语言例如 C# 和 XAML。如果您熟悉在任何过程语言(例如 C# 或 C/C++)中的调试并且您还知道中断点的用法,那么您可以轻松调试应用程序的 C# 部分。

我们通过一个简单的示例来演示如何调试 C# 代码。创建新的 WPF 项目,项目名称为 WPFDebuggingDemo 。从工具箱中拖拽四个标签、三个文本框,以及一个按钮。查看以下 XAML 代码。

<Window x:Class = "WPFDebuggingDemo.Window1"
   xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml"
   Title = "Window1" Height = "400" Width = "604">

   <Grid>
      <TextBox Height = "23" Margin = "0,44,169,0" Name = "textBox1"
         VerticalAlignment = "Top" HorizontalAlignment = "Right" Width = "120" />

      <TextBox Height = "23" Margin = "0,99,169,0" Name = "textBox2"
         VerticalAlignment = "Top" HorizontalAlignment = "Right" Width = "120" />

      <TextBox HorizontalAlignment = "Right" Margin = "0,153,169,0"
         Name = "textBox3" Width = "120" Height = "23" VerticalAlignment = "Top" />

      <Label Height = "28" Margin = "117,42,0,0" Name = "label1"
         VerticalAlignment = "Top" HorizontalAlignment = "Left" Width = "120">
         Item 1</Label>

      <Label Height = "28" HorizontalAlignment = "Left"
         Margin = "117,99,0,0" Name = "label2" VerticalAlignment = "Top" Width = "120">
         Item 2</Label>

      <Label HorizontalAlignment = "Left" Margin = "117,153,0,181"
         Name = "label3" Width = "120">Item 3</Label>

      <Button Height = "23" HorizontalAlignment = "Right" Margin = "0,0,214,127"
         Name = "button1" VerticalAlignment = "Bottom" Width = "75"
         Click = "button1_Click">Total</Button>

      <Label Height = "28" HorizontalAlignment = "Right"
         Margin = "0,0,169,66" Name = "label4" VerticalAlignment = "Bottom" Width = "120"/>

   </Grid>

</Window>

以下是实现了按钮点击事件的 C# 代码。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace WPFDebuggingDemo {
   /// <summary>
      /// Interaction logic for Window1.xaml
   /// </summary>

   public partial class Window1 : Window {

      public Window1() {
         InitializeComponent();
      }

      private void button1_Click(object sender, RoutedEventArgs e) {

         if (textBox1.Text.Length > 0 && textBox2.Text.Length > 0 && textBox2.Text.Length > 0) {
            double total = Convert.ToDouble(textBox1.Text) +
            Convert.ToDouble(textBox2.Text) + Convert.ToDouble(textBox3.Text);
            label4.Content = total.ToString();
         }
         else {
            MessageBox.Show("Enter the value in all field.");
         }
      }
   }
}

当您编译并执行以上代码时,它将生成以下窗口。现在在文本框中输入值并按下 Total 按钮。您将在所有文本框中输入值的总和后获得总值。

debugging

如果您尝试输入除实际值之外的值,则上述应用程序将崩溃。为了找到并解决问题(为什么它崩溃),您可以在按钮点击事件中插入中断点。

我们如下一文所示在项 1 中写入“abc”。

write in item1

单击 Total 按钮后,您将看到程序在断点处停止。

program is crashing

现在将光标移动到 textbox1.Text,您将看到程序正尝试将 abc 值与其他值相加,这就是程序崩溃的原因。

Debugging in XAML

如果您希望在 XAML 中进行同样的调试,您会惊讶地知道至今仍无法像调试任何其他过程语言代码一样调试 XAML 代码。当您在 XAML 代码中听到术语“调试”时,它意味着尝试并找到错误。

  1. In data binding, your data doesn’t show up on screen and you don’t know why

  2. Or an issue is related to complex layouts.

  3. Or an alignment issue or issues in margin color, overlays, etc. with some extensive templates like ListBox and combo box.

Debugging an XAML program is something you typically do to check if your bindings work; and if it is not working, then to check what’s wrong. Unfortunately setting breakpoints in XAML bindings isn’t possible except in Silverlight, but we can use the Output window to check for data binding errors. Let’s take a look at the following XAML code to find the error in data binding.

<Window x:Class = "DataBindingOneWay.MainWindow"
   xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml"
   Title = "MainWindow" Height = "350" Width = "604">

   <Grid>
      <StackPanel Name = "Display">
         <StackPanel Orientation = "Horizontal" Margin = "50, 50, 0, 0">
            <TextBlock Text = "Name: " Margin = "10" Width = "100"/>
            <TextBlock Margin = "10" Width = "100" Text = "{Binding FirstName}"/>
         </StackPanel>

         <StackPanel Orientation = "Horizontal" Margin = "50,0,50,0">
            <TextBlock Text = "Title: " Margin = "10" Width = "100"/>
            <TextBlock Margin = "10" Width = "100" Text = "{Binding Title}" />
         </StackPanel>

      </StackPanel>
   </Grid>

</Window>

Text properties of two text blocks are set to “Name” and “Title” statically, while other two text blocks Text properties are bind to “FirstName” and “Title” but class variables are Name and Title in Employee class which is shown below.

We have intentionally written an incorrect variable name so as to understand where can we find this type of a mistake when the desired output is not shown.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace DataBindingOneWay {

   public class Employee {
      public string Name { get; set; }
      public string Title { get; set; }

      public static Employee GetEmployee() {

         var emp = new Employee() {
            Name = "Ali Ahmed", Title = "Developer"
         };

         return emp;
      }
   }
}

这是用 c# 代码实现 MainWindow 类的方法。

using System;
using System.Windows;
using System.Windows.Controls;

namespace DataBindingOneWay {
   /// <summary>
      /// Interaction logic for MainWindow.xaml
   /// </summary>

   public partial class MainWindow : Window {

      public MainWindow() {
         InitializeComponent();
         DataContext = Employee.GetEmployee();
      }
   }
}

让我们运行此应用程序,您会立即看到在我们的 MainWindow 中,我们已经成功绑定到那个 Employee 对象的 Title,但是 name 没有绑定。

debugging in xaml

为了检查 name 发生了什么,让我们来看看生成了很多日志的输出窗口。

找到错误很容易,只需搜索错误,您就会找到以下错误,“BindingExpression 路径错误:在 'object' 'Employe' 上未找到 'FirstName' 属性”。

System.Windows.Data Error: 40 : BindingExpression path error: 'FirstName'
   property not found on 'object' ''Employee' (HashCode=11611730)'.
   BindingExpression:Path = FirstName; DataItem = 'Employee' (HashCode = 11611730);
   target element is 'TextBlock' (Name=''); target property is 'Text' (type 'String')

这清楚地表明,FirstName 不是 Employee 类的一个成员,所以它有助于修复您应用程序中的此类问题。

当您将 FirstName 再次更改为 Name 时,您会看到所需的输出。

UI Debugging Tools for XAML

引入了 UI 调试工具,在 Visual Studio 2015 中用 XAML 在运行时检查 XAML 代码。在这些工具的帮助下,XAML 代码以运行的 WPF 应用程序的视觉树的形式呈现,还有树中的不同 UI 元素属性。要启用这些工具,请按照以下步骤操作。

  1. 转到“工具”菜单,然后从“工具”菜单中选择“选项”。

  2. 这将打开以下对话框。

debugging tools
  1. 转到左侧 Debugging 项下的常规选项。

  2. 勾选突出显示的选项,即,“为 XAML 启用 UI 调试工具”,然后单击“确定”按钮。

现在运行任何 XAML 应用程序或使用以下 XAML 代码。

<Window x:Class = "XAMLTestBinding.MainWindow"
   xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml"
   Title = "MainWindow" Height = "350" Width = "604">

   <StackPanel>
      <ComboBox Name = "comboBox"  Margin = "50" Width = "100">
         <ComboBoxItem Content = "Green" />
         <ComboBoxItem  Content = "Yellow" IsSelected = "True" />
         <ComboBoxItem Content = "Orange" />
      </ComboBox>

      <TextBox  Name = "textBox" Margin = "50" Width = "100" Height = "23"
         VerticalAlignment = "Top" Text  =
         "{Binding ElementName = comboBox, Path = SelectedItem.Content, Mode = TwoWay, UpdateSourceTrigger = PropertyChanged}"
         Background = "{Binding ElementName = comboBox, Path = SelectedItem.Content}">
      </TextBox>

   </StackPanel>

</Window>

当您执行应用程序时,它将显示 Live Visual Tree,其中所有元素都显示在树中。

live visual tree

此 Live Visual Tree 显示了完整的布局结构,以了解 UI 元素位于何处。但此选项仅在 Visual Studio 2015 中可用。如果您使用的是较旧版本的 Visual Studio,则无法使用此工具,但是,还有另一个可以与 Visual Studio 集成的工具,如 Visual Studio 的 XAML Spy。您可以从 xamlspy 下载它。